Initial Contribution
msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142
Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/perfmon/perf-v7.c b/arch/arm/perfmon/perf-v7.c
new file mode 100644
index 0000000..614eedc
--- /dev/null
+++ b/arch/arm/perfmon/perf-v7.c
@@ -0,0 +1,1009 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+perf-v7.c
+DESCRIPTION
+Manipulation, initialization of the ARMV7 Performance counter register.
+
+
+EXTERNALIZED FUNCTIONS
+
+INITIALIZATION AND SEQUENCING REQUIREMENTS
+*/
+
+/*
+INCLUDE FILES FOR MODULE
+*/
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "cp15_registers.h"
+
+/*
+DEFINITIONS AND DECLARATIONS FOR MODULE
+
+This section contains definitions for constants, macros, types, variables
+and other items needed by this module.
+*/
+
+/*
+ Constant / Define Declarations
+*/
+
+#define PM_NUM_COUNTERS 4
+#define PM_V7_ERR -1
+
+/*------------------------------------------------------------------------
+ * Global control bits
+------------------------------------------------------------------------*/
+#define PM_GLOBAL_ENABLE (1<<0)
+#define PM_EVENT_RESET (1<<1)
+#define PM_CYCLE_RESET (1<<2)
+#define PM_CLKDIV (1<<3)
+#define PM_GLOBAL_TRACE (1<<4)
+#define PM_DISABLE_PROHIBIT (1<<5)
+
+/*---------------------------------------------------------------------------
+ * Enable and clear bits for each event/trigger
+----------------------------------------------------------------------------*/
+#define PM_EV0_ENABLE (1<<0)
+#define PM_EV1_ENABLE (1<<1)
+#define PM_EV2_ENABLE (1<<2)
+#define PM_EV3_ENABLE (1<<3)
+#define PM_COUNT_ENABLE (1<<31)
+#define PM_ALL_ENABLE (0x8000000F)
+
+
+/*-----------------------------------------------------------------------------
+ * Overflow actions
+------------------------------------------------------------------------------*/
+#define PM_OVERFLOW_NOACTION (0)
+#define PM_OVERFLOW_HALT (1)
+#define PM_OVERFLOW_STOP (2)
+#define PM_OVERFLOW_SKIP (3)
+
+/*
+ * Shifts for each trigger type
+ */
+#define PM_STOP_SHIFT 24
+#define PM_RELOAD_SHIFT 22
+#define PM_RESUME_SHIFT 20
+#define PM_SUSPEND_SHIFT 18
+#define PM_START_SHIFT 16
+#define PM_STOPALL_SHIFT 15
+#define PM_STOPCOND_SHIFT 12
+#define PM_RELOADCOND_SHIFT 9
+#define PM_RESUMECOND_SHIFT 6
+#define PM_SUSPENDCOND_SHIFT 3
+#define PM_STARTCOND_SHIFT 0
+
+
+/*---------------------------------------------------------------------------
+External control register. What todo when various events happen.
+Triggering events, etc.
+----------------------------------------------------------------------------*/
+#define PM_EXTTR0 0
+#define PM_EXTTR1 1
+#define PM_EXTTR2 2
+#define PM_EXTTR3 3
+
+#define PM_COND_NO_STOP 0
+#define PM_COND_STOP_CNTOVRFLW 1
+#define PM_COND_STOP_EXTERNAL 4
+#define PM_COND_STOP_TRACE 5
+#define PM_COND_STOP_EVOVRFLW 6
+#define PM_COND_STOP_EVTYPER 7
+
+/*--------------------------------------------------------------------------
+Protect against concurrent access. There is an index register that is
+used to select the appropriate bank of registers. If multiple processes
+are writting this at different times we could have a mess...
+---------------------------------------------------------------------------*/
+#define PM_LOCK()
+#define PM_UNLOCK()
+#define PRINT printk
+
+/*--------------------------------------------------------------------------
+The Event definitions
+--------------------------------------------------------------------------*/
+#define PM_EVT_SW_INCREMENT 0
+#define PM_EVT_L1_I_MISS 1
+#define PM_EVT_ITLB_MISS 2
+#define PM_EVT_L1_D_MISS 3
+#define PM_EVT_L1_D_ACCESS 4
+#define PM_EVT_DTLB_MISS 5
+#define PM_EVT_DATA_READ 6
+#define PM_EVT_DATA_WRITE 7
+#define PM_EVT_INSTRUCTION 8
+#define PM_EVT_EXCEPTIONS 9
+#define PM_EVT_EXCEPTION_RET 10
+#define PM_EVT_CTX_CHANGE 11
+#define PM_EVT_PC_CHANGE 12
+#define PM_EVT_BRANCH 13
+#define PM_EVT_RETURN 14
+#define PM_EVT_UNALIGNED 15
+#define PM_EVT_BRANCH_MISS 16
+#define PM_EVT_EXTERNAL0 0x40
+#define PM_EVT_EXTERNAL1 0x41
+#define PM_EVT_EXTERNAL2 0x42
+#define PM_EVT_EXTERNAL3 0x43
+#define PM_EVT_TRACE0 0x44
+#define PM_EVT_TRACE1 0x45
+#define PM_EVT_TRACE2 0x46
+#define PM_EVT_TRACE3 0x47
+#define PM_EVT_PM0 0x48
+#define PM_EVT_PM1 0x49
+#define PM_EVT_PM2 0x4a
+#define PM_EVT_PM3 0x4b
+#define PM_EVT_LPM0_EVT0 0x4c
+#define PM_EVT_LPM0_EVT1 0x4d
+#define PM_EVT_LPM0_EVT2 0x4e
+#define PM_EVT_LPM0_EVT3 0x4f
+#define PM_EVT_LPM1_EVT0 0x50
+#define PM_EVT_LPM1_EVT1 0x51
+#define PM_EVT_LPM1_EVT2 0x52
+#define PM_EVT_LPM1_EVT3 0x53
+#define PM_EVT_LPM2_EVT0 0x54
+#define PM_EVT_LPM2_EVT1 0x55
+#define PM_EVT_LPM2_EVT2 0x56
+#define PM_EVT_LPM2_EVT3 0x57
+#define PM_EVT_L2_EVT0 0x58
+#define PM_EVT_L2_EVT1 0x59
+#define PM_EVT_L2_EVT2 0x5a
+#define PM_EVT_L2_EVT3 0x5b
+#define PM_EVT_VLP_EVT0 0x5c
+#define PM_EVT_VLP_EVT1 0x5d
+#define PM_EVT_VLP_EVT2 0x5e
+#define PM_EVT_VLP_EVT3 0x5f
+
+/*
+Type Declarations
+*/
+
+/*--------------------------------------------------------------------------
+A performance monitor trigger setup/initialization structure. Contains
+all of the fields necessary to setup a complex trigger with the internal
+performance monitor.
+---------------------------------------------------------------------------*/
+struct pm_trigger_s {
+ int index;
+ int event_type;
+ bool interrupt;
+ bool overflow_enable;
+ bool event_export;
+ unsigned char overflow_action;
+ unsigned char stop_index;
+ unsigned char reload_index;
+ unsigned char resume_index;
+ unsigned char suspend_index;
+ unsigned char start_index;
+ bool overflow_stop;
+ unsigned char stop_condition;
+ unsigned char reload_condition;
+ unsigned char resume_condition;
+ unsigned char suspend_condition;
+ unsigned char start_condition;
+};
+
+/*
+* Name and index place holder so we can display the event
+*/
+struct pm_name_s {
+ unsigned long index;
+ char *name;
+};
+
+/*
+Local Object Definitions
+*/
+
+unsigned long pm_cycle_overflow_count;
+unsigned long pm_overflow_count[PM_NUM_COUNTERS];
+
+/*---------------------------------------------------------------------------
+Max number of events read from the config registers
+---------------------------------------------------------------------------*/
+static int pm_max_events;
+
+/*--------------------------------------------------------------------------
+Storage area for each of the triggers
+*---------------------------------------------------------------------------*/
+static struct pm_trigger_s pm_triggers[4];
+
+/*--------------------------------------------------------------------------
+Names and indexes of the events
+--------------------------------------------------------------------------*/
+static struct pm_name_s pm_names[] = {
+ { PM_EVT_SW_INCREMENT, "SW Increment"},
+ { PM_EVT_L1_I_MISS, "L1 I MISS"},
+ { PM_EVT_ITLB_MISS, "L1 ITLB MISS"},
+ { PM_EVT_L1_D_MISS, "L1 D MISS"},
+ { PM_EVT_L1_D_ACCESS, "L1 D ACCESS"},
+ { PM_EVT_DTLB_MISS, "DTLB MISS"},
+ { PM_EVT_DATA_READ, "DATA READ"},
+ { PM_EVT_DATA_WRITE, "DATA WRITE"},
+ { PM_EVT_INSTRUCTION, "INSTRUCTIONS"},
+ { PM_EVT_EXCEPTIONS, "EXCEPTIONS"},
+ { PM_EVT_EXCEPTION_RET, "EXCEPTION RETURN"},
+ { PM_EVT_CTX_CHANGE, "CTX CHANGE"},
+ { PM_EVT_PC_CHANGE, "PC CHANGE"},
+ { PM_EVT_BRANCH, "BRANCH"},
+ { PM_EVT_RETURN, "RETURN"},
+ { PM_EVT_UNALIGNED, "UNALIGNED"},
+ { PM_EVT_BRANCH_MISS, "BRANCH MISS"},
+ { PM_EVT_EXTERNAL0, "EXTERNAL 0"},
+ { PM_EVT_EXTERNAL1, "EXTERNAL 1"},
+ { PM_EVT_EXTERNAL2, "EXTERNAL 2"},
+ { PM_EVT_EXTERNAL3, "EXTERNAL 3"},
+ { PM_EVT_TRACE0, "TRACE 0"},
+ { PM_EVT_TRACE1, "TRACE 1"},
+ { PM_EVT_TRACE2, "TRACE 2"},
+ { PM_EVT_TRACE3, "TRACE 3"},
+ { PM_EVT_PM0, "PM0"},
+ { PM_EVT_PM1, "PM1"},
+ { PM_EVT_PM2, "PM2"},
+ { PM_EVT_PM3, "PM3"},
+ { PM_EVT_LPM0_EVT0, "LPM0 E0"},
+ { PM_EVT_LPM0_EVT1, "LPM0 E1"},
+ { PM_EVT_LPM0_EVT2 , "LPM0 E2"},
+ { PM_EVT_LPM0_EVT3, "LPM0 E3"},
+ { PM_EVT_LPM1_EVT0, "LPM1 E0"},
+ { PM_EVT_LPM1_EVT1, "LPM1 E1"},
+ { PM_EVT_LPM1_EVT2, "LPM1 E2"},
+ { PM_EVT_LPM1_EVT3, "LPM1 E3"},
+ { PM_EVT_LPM2_EVT0, "LPM2 E0"},
+ { PM_EVT_LPM2_EVT1 , "LPM2 E1"},
+ { PM_EVT_LPM2_EVT2, "LPM2 E2"},
+ { PM_EVT_LPM2_EVT3, "LPM2 E3"},
+ { PM_EVT_L2_EVT0 , "L2 E0"},
+ { PM_EVT_L2_EVT1, "L2 E1"},
+ { PM_EVT_L2_EVT2, "L2 E2"},
+ { PM_EVT_L2_EVT3 , "L2 E3"},
+ { PM_EVT_VLP_EVT0 , "VLP E0"},
+ { PM_EVT_VLP_EVT1, "VLP E1"},
+ { PM_EVT_VLP_EVT2, "VLP E2"},
+ { PM_EVT_VLP_EVT3, "VLP E3"},
+};
+
+static int irqid;
+
+/*
+Function Definitions
+*/
+
+/*
+FUNCTION pm_find_event_name
+
+DESCRIPTION Find the name associated with the event index passed and return
+the pointer.
+
+DEPENDENCIES
+
+RETURN VALUE
+Pointer to text string containing the name of the event or pointer to
+an error string. Either way access to the returned string will not
+cause an access error.
+
+SIDE EFFECTS
+*/
+char *pm_find_event_name(unsigned long index)
+{
+ unsigned long i = 0;
+
+ while (pm_names[i].index != -1) {
+ if (pm_names[i].index == index)
+ return pm_names[i].name;
+ i++;
+ }
+ return "BAD INDEX";
+}
+
+/*
+FUNCTION pm_group_stop
+
+DESCRIPTION Stop a group of the performance monitors. Event monitor 0 is bit
+0, event monitor 1 bit 1, etc. The cycle count can also be disabled with
+bit 31. Macros are provided for all of the indexes including an ALL.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Stops the performance monitoring for the index passed.
+*/
+void pm_group_stop(unsigned long mask)
+{
+ WCP15_PMCNTENCLR(mask);
+}
+
+/*
+FUNCTION pm_group_start
+
+DESCRIPTION Start a group of the performance monitors. Event monitor 0 is bit
+0, event monitor 1 bit 1, etc. The cycle count can also be enabled with
+bit 31. Macros are provided for all of the indexes including an ALL.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Starts the performance monitoring for the index passed.
+*/
+void pm_group_start(unsigned long mask)
+{
+ WCP15_PMCNTENSET(mask);
+}
+
+/*
+FUNCTION pm_cycle_overflow_action
+
+DESCRIPTION Action to take for an overflow of the cycle counter.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Modify the state actions for overflow
+*/
+void pm_cycle_overflow_action(int action)
+{
+ unsigned long reg = 0;
+
+ if ((action > PM_OVERFLOW_SKIP) || (action < 0))
+ return;
+
+ RCP15_PMACTLR(reg);
+ reg &= ~(1<<30); /*clear it*/
+ WCP15_PMACTLR(reg | (action<<30));
+}
+
+/*
+FUNCTION pm_get_overflow
+
+DESCRIPTION Return the overflow condition for the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+0 no overflow
+!0 (anything else) overflow;
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_overflow(int index)
+{
+ unsigned long overflow = 0;
+
+/*
+* Range check
+*/
+ if (index > pm_max_events)
+ return PM_V7_ERR;
+ RCP15_PMOVSR(overflow);
+
+ return overflow & (1<<index);
+}
+
+/*
+FUNCTION pm_get_cycle_overflow
+
+DESCRIPTION
+Returns if the cycle counter has overflowed or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+0 no overflow
+!0 (anything else) overflow;
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_cycle_overflow(void)
+{
+ unsigned long overflow = 0;
+
+ RCP15_PMOVSR(overflow);
+ return overflow & PM_COUNT_ENABLE;
+}
+
+/*
+FUNCTION pm_reset_overflow
+
+DESCRIPTION Reset the cycle counter overflow bit.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void pm_reset_overflow(int index)
+{
+ WCP15_PMOVSR(1<<index);
+}
+
+/*
+FUNCTION pm_reset_cycle_overflow
+
+DESCRIPTION Reset the cycle counter overflow bit.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void pm_reset_cycle_overflow(void)
+{
+ WCP15_PMOVSR(PM_COUNT_ENABLE);
+}
+
+/*
+FUNCTION pm_get_cycle_count
+
+DESCRIPTION return the count in the cycle count register.
+
+DEPENDENCIES
+
+RETURN VALUE
+The value in the cycle count register.
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_cycle_count(void)
+{
+ unsigned long cnt = 0;
+ RCP15_PMCCNTR(cnt);
+ return cnt;
+}
+
+/*
+FUNCTION pm_reset_cycle_count
+
+DESCRIPTION reset the value in the cycle count register
+
+DEPENDENCIES
+
+RETURN VALUE
+NONE
+
+SIDE EFFECTS
+Resets the performance monitor cycle count register.
+Any interrupts period based on this overflow will be changed
+*/
+void pm_reset_cycle_count(void)
+{
+ WCP15_PMCNTENCLR(PM_COUNT_ENABLE);
+}
+
+/*
+FUNCTION pm_cycle_div_64
+
+DESCRIPTION Set the cycle counter to count every 64th cycle instead of
+every cycle when the value passed is 1, otherwise counts every cycle.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+Changes the rate at which cycles are counted. Anything that is reading
+the cycle count (pmGetCyucleCount) may get different results.
+*/
+void pm_cycle_div_64(int enable)
+{
+ unsigned long enables = 0;
+
+ RCP15_PMCR(enables);
+ if (enable)
+ WCP15_PMCR(enables | PM_CLKDIV);
+ else
+ WCP15_PMCR(enables & ~PM_CLKDIV);
+}
+
+/*
+FUNCTION pm_enable_cycle_counter
+
+DESCRIPTION Enable the cycle counter. Sets the bit in the enable register
+so the performance monitor counter starts up counting.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+*/
+void pm_enable_cycle_counter(void)
+{
+/*
+* Enable the counter.
+*/
+ WCP15_PMCNTENSET(PM_COUNT_ENABLE);
+}
+
+/*
+FUNCTION pm_disable_counter
+
+DESCRIPTION Disable a single counter based on the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+Any triggers that are based on the stoped counter may not trigger...
+*/
+void pm_disable_counter(int index)
+{
+ /*
+ * Range check
+ */
+ if (index > pm_max_events)
+ return;
+ WCP15_PMCNTENCLR(1<<index);
+}
+
+/*
+FUNCTION pm_enable_counter
+
+DESCRIPTION Enable the counter with the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+none.
+
+SIDE EFFECTS
+*/
+void pm_enable_counter(int index)
+{
+ /*
+ * Range check
+ */
+ if (index > pm_max_events)
+ return;
+ WCP15_PMCNTENSET(1<<index);
+}
+
+/*
+FUNCTION pm_set_count
+
+DESCRIPTION Set the number of events in a register, used for resets
+passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+-1 if the index is out of range
+
+SIDE EFFECTS
+*/
+int pm_set_count(int index, unsigned long new_value)
+{
+ unsigned long reg = 0;
+
+/*
+* Range check
+*/
+ if (index > pm_max_events)
+ return PM_V7_ERR;
+
+/*
+* Lock, select the index and read the count...unlock
+*/
+ PM_LOCK();
+ WCP15_PMSELR(index);
+ WCP15_PMXEVCNTR(new_value);
+ PM_UNLOCK();
+ return reg;
+}
+
+int pm_reset_count(int index)
+{
+ return pm_set_count(index, 0);
+}
+
+/*
+FUNCTION pm_get_count
+
+DESCRIPTION Return the number of events that have happened for the index
+passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+-1 if the index is out of range
+The number of events if inrange
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_count(int index)
+{
+ unsigned long reg = 0;
+
+/*
+* Range check
+*/
+ if (index > pm_max_events)
+ return PM_V7_ERR;
+
+/*
+* Lock, select the index and read the count...unlock
+*/
+ PM_LOCK();
+ WCP15_PMSELR(index);
+ RCP15_PMXEVCNTR(reg);
+ PM_UNLOCK();
+ return reg;
+}
+
+/*
+FUNCTION pm_show_event_info
+
+DESCRIPTION Display (print) the information about the event at the index
+passed. Shows the index, name and count if a valid index is passed. If
+the index is not valid, then nothing is displayed.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void pm_show_event_info(unsigned long index)
+{
+ unsigned long count;
+ unsigned long event_type;
+
+ if (index > pm_max_events)
+ return;
+ if (pm_triggers[index].index > pm_max_events)
+ return;
+
+ count = pm_get_count(index);
+ event_type = pm_triggers[index].event_type;
+
+ PRINT("Event %ld Trigger %s(%ld) count:%ld\n", index,
+ pm_find_event_name(event_type), event_type, count);
+}
+
+/*
+FUNCTION pm_event_init
+
+DESCRIPTION Given the struct pm_trigger_s info passed, configure the event.
+This can be a complex trigger or a simple trigger. Any old values in the
+event are lost.
+
+DEPENDENCIES
+
+RETURN VALUE
+status
+
+SIDE EFFECTS
+stops and clears the event at the index passed.
+*/
+int pm_event_init(struct pm_trigger_s *data)
+{
+ unsigned long trigger;
+ unsigned long actlr = 0;
+
+ if (0 == data)
+ return PM_V7_ERR;
+ if (data->index > pm_max_events)
+ return PM_V7_ERR;
+
+ /*
+ * Setup the trigger based ont he passed values
+ */
+ trigger = ((data->overflow_enable&1)<<31) |
+ ((data->event_export&1)<<30) |
+ ((data->stop_index&3)<<PM_STOP_SHIFT) |
+ ((data->reload_index&3)<<PM_RELOAD_SHIFT) |
+ ((data->resume_index&3)<<PM_RESUME_SHIFT) |
+ ((data->suspend_index&3)<<PM_SUSPEND_SHIFT) |
+ ((data->start_index&3)<<PM_START_SHIFT) |
+ ((data->overflow_stop&1)<<PM_STOPALL_SHIFT) |
+ ((data->stop_condition&7)<<PM_STOPCOND_SHIFT) |
+ ((data->reload_condition&7)<<PM_RELOADCOND_SHIFT) |
+ ((data->resume_condition&7)<<PM_RESUMECOND_SHIFT) |
+ ((data->suspend_condition&7)<<PM_SUSPENDCOND_SHIFT) |
+ ((data->start_condition&7)<<PM_STARTCOND_SHIFT);
+
+ /*
+ * Disable this counter while we are updating.
+ */
+ pm_disable_counter(data->index);
+
+ /*
+ * Lock, select the bank, set the trigger event and the event type
+ * then unlock.
+ */
+ PM_LOCK();
+ RCP15_PMACTLR(actlr);
+ actlr &= ~(3<<(data->index<<1));
+ WCP15_PMACTLR(actlr | ((data->overflow_action&3) << (data->index<<1)));
+ WCP15_PMSELR(data->index);
+ WCP15_PMXEVTYPER(data->event_type);
+ WCP15_PMXEVCNTCR(trigger);
+ PM_UNLOCK();
+
+ /*
+ * Make a copy of the trigger so we know what it is when/if it triggers.
+ */
+ memcpy(&pm_triggers[data->index], data, sizeof(*data));
+
+ /*
+ * We do not re-enable this here so events can be started together with
+ * pm_group_start() that way an accurate measure can be taken...
+ */
+
+ return 0;
+}
+
+int pm_set_event(int index, unsigned long event)
+{
+ unsigned long reg = 0;
+
+ /*
+ * Range check
+ */
+ if (index > pm_max_events)
+ return PM_V7_ERR;
+
+ /*
+ * Lock, select the index and read the count...unlock
+ */
+ PM_LOCK();
+ WCP15_PMSELR(index);
+ WCP15_PMXEVTYPER(event);
+ PM_UNLOCK();
+ return reg;
+}
+
+/*
+FUNCTION pm_set_local_iu
+
+DESCRIPTION Set the local IU triggers. Note that the MSB determines if
+ these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_iu(unsigned long value)
+{
+ WCP15_LPM0EVTYPER(value);
+}
+
+/*
+FUNCTION pm_set_local_iu
+
+DESCRIPTION Set the local IU triggers. Note that the MSB determines if
+ these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_xu(unsigned long value)
+{
+ WCP15_LPM1EVTYPER(value);
+}
+
+/*
+FUNCTION pm_set_local_su
+
+DESCRIPTION Set the local SU triggers. Note that the MSB determines if
+ these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_su(unsigned long value)
+{
+ WCP15_LPM2EVTYPER(value);
+}
+
+/*
+FUNCTION pm_set_local_l2
+
+DESCRIPTION Set the local L2 triggers. Note that the MSB determines if
+ these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_l2(unsigned long value)
+{
+ WCP15_L2LPMEVTYPER(value);
+}
+
+/*
+FUNCTION pm_set_local_vu
+
+DESCRIPTION Set the local VU triggers. Note that the MSB determines if
+ these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_vu(unsigned long value)
+{
+ WCP15_VLPMEVTYPER(value);
+}
+
+/*
+FUNCTION pm_isr
+
+DESCRIPTION:
+ Performance Monitor interrupt service routine to capture overflows
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+static irqreturn_t pm_isr(int irq, void *d)
+{
+ int i;
+
+ for (i = 0; i < PM_NUM_COUNTERS; i++) {
+ if (pm_get_overflow(i)) {
+ pm_overflow_count[i]++;
+ pm_reset_overflow(i);
+ }
+ }
+
+ if (pm_get_cycle_overflow()) {
+ pm_cycle_overflow_count++;
+ pm_reset_cycle_overflow();
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+void pm_stop_all(void)
+{
+ WCP15_PMCNTENCLR(0xFFFFFFFF);
+}
+
+void pm_reset_all(void)
+{
+ WCP15_PMCR(0xF);
+ WCP15_PMOVSR(PM_ALL_ENABLE); /* overflow clear */
+}
+
+void pm_start_all(void)
+{
+ WCP15_PMCNTENSET(PM_ALL_ENABLE);
+}
+
+/*
+FUNCTION pm_initialize
+
+DESCRIPTION Initialize the performanca monitoring for the v7 processor.
+ Ensures the cycle count is running and the event counters are enabled.
+
+DEPENDENCIES
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+*/
+void pm_initialize(void)
+{
+ unsigned long reg = 0;
+ unsigned char imp;
+ unsigned char id;
+ unsigned char num;
+ unsigned long enables = 0;
+ static int initialized;
+
+ if (initialized)
+ return;
+ initialized = 1;
+
+ irqid = INT_ARMQC_PERFMON;
+ RCP15_PMCR(reg);
+ imp = (reg>>24) & 0xFF;
+ id = (reg>>16) & 0xFF;
+ pm_max_events = num = (reg>>11) & 0xFF;
+ PRINT("V7Performance Monitor Capabilities\n");
+ PRINT(" Implementor %c(%d)\n", imp, imp);
+ PRINT(" Id %d %x\n", id, id);
+ PRINT(" Num Events %d %x\n", num, num);
+ PRINT("\nCycle counter enabled by default...\n");
+
+ /*
+ * Global enable, ensure the global enable is set so all
+ * subsequent actions take effect. Also resets the counts
+ */
+ RCP15_PMCR(enables);
+ WCP15_PMCR(enables | PM_GLOBAL_ENABLE | PM_EVENT_RESET |
+ PM_CYCLE_RESET | PM_CLKDIV);
+
+ /*
+ * Enable access from user space
+ */
+ WCP15_PMUSERENR(1);
+ WCP15_PMACTLR(1);
+
+ /*
+ * Install interrupt handler and the enable the interrupts
+ */
+ pm_reset_cycle_overflow();
+ pm_reset_overflow(0);
+ pm_reset_overflow(1);
+ pm_reset_overflow(2);
+ pm_reset_overflow(3);
+
+ if (0 != request_irq(irqid, pm_isr, 0, "perfmon", 0))
+ printk(KERN_ERR "%s:%d request_irq returned error\n",
+ __FILE__, __LINE__);
+ WCP15_PMINTENSET(PM_ALL_ENABLE);
+ /*
+ * Enable the cycle counter. Default, count 1:1 no divisor.
+ */
+ pm_enable_cycle_counter();
+
+}
+
+void pm_free_irq(void)
+{
+ free_irq(irqid, 0);
+}
+
+void pm_deinitialize(void)
+{
+ unsigned long enables = 0;
+ RCP15_PMCR(enables);
+ WCP15_PMCR(enables & ~PM_GLOBAL_ENABLE);
+}