KSAPI: Performance monitoring tool for Snapdragon linux
KSAPI records performance statistics for Snapdragon linux platform. It uses the /proc FS as a means to exchange configuration data and counter statistics. It can monitor the counter statistics for Scorpion processor supported hardware performance counters on a per thread basis or AXI counters on an overall system basis. Change-Id: Iaaf51db68dbd6d5a55fe34328d041bde5015230d Signed-off-by: Sheetal Sahasrabudhe <sheetals@codeaurora.org> (cherry picked from commit 4e6bb52bcee479762f283b4a44a1bdd4f1277aa2) Conflicts: arch/arm/Kconfig
This commit is contained in:
committed by
Stephen Boyd
parent
8636af8f7a
commit
e11d14dfd1
@@ -1416,6 +1416,18 @@ config PL310_ERRATA_769419
|
||||
on systems with an outer cache, the store buffer is drained
|
||||
explicitly.
|
||||
|
||||
config KSAPI
|
||||
tristate "KSAPI support (EXPERIMENTAL)"
|
||||
depends on ARCH_MSM_SCORPION || ARCH_MSM_KRAIT
|
||||
default n
|
||||
help
|
||||
KSAPI: Performance monitoring tool for linux.
|
||||
KSAPI records performance statistics for Snapdragon linux platform.
|
||||
It uses the /proc FS as a means to exchange configuration data and
|
||||
counter statistics. It can monitor the counter statistics for
|
||||
Scorpion processor supported hardware performance counters on a per
|
||||
thread basis or AXI counters on an overall system basis.
|
||||
|
||||
endmenu
|
||||
|
||||
source "arch/arm/common/Kconfig"
|
||||
|
||||
@@ -257,6 +257,7 @@ core-y += arch/arm/net/
|
||||
core-y += $(machdirs) $(platdirs)
|
||||
|
||||
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
|
||||
core-y += arch/arm/perfmon/
|
||||
|
||||
libs-y := arch/arm/lib/ $(libs-y)
|
||||
|
||||
|
||||
48
arch/arm/include/asm/perftypes.h
Normal file
48
arch/arm/include/asm/perftypes.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Code Aurora nor
|
||||
* the names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
** perftypes.h
|
||||
** DESCRIPTION
|
||||
** ksapi.ko function hooks header file
|
||||
*/
|
||||
|
||||
#ifndef __PERFTYPES_H__
|
||||
#define __PERFTYPES_H__
|
||||
|
||||
typedef void (*VPVF)(void);
|
||||
typedef void (*VPULF)(unsigned long);
|
||||
typedef void (*VPULULF)(unsigned long, unsigned long);
|
||||
|
||||
extern VPVF pp_interrupt_out_ptr;
|
||||
extern VPVF pp_interrupt_in_ptr;
|
||||
extern VPULF pp_process_remove_ptr;
|
||||
extern void perf_mon_interrupt_in(void);
|
||||
extern void perf_mon_interrupt_out(void);
|
||||
|
||||
#endif
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
#include <asm/perftypes.h>
|
||||
|
||||
/*
|
||||
* No architecture-specific irq_finish function defined in arm/arch/irqs.h.
|
||||
*/
|
||||
@@ -71,6 +73,7 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
||||
perf_mon_interrupt_in();
|
||||
irq_enter();
|
||||
|
||||
/*
|
||||
@@ -90,6 +93,7 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
|
||||
irq_exit();
|
||||
set_irq_regs(old_regs);
|
||||
perf_mon_interrupt_out();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
9
arch/arm/perfmon/Makefile
Normal file
9
arch/arm/perfmon/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
obj-$(CONFIG_KSAPI) += ksapi.o
|
||||
|
||||
# Object file lists.
|
||||
obj-y += perf-function-hooks.o
|
||||
#ifdef CONFIG_ARCH_MSM8X60
|
||||
ksapi-y += perf-v7.o perf-smp.o per.o per-process-perf.o per-axi.o
|
||||
#else
|
||||
ksapi-y += perf-v7.o per.o per-process-perf.o per-axi.o
|
||||
#endif
|
||||
109
arch/arm/perfmon/cp15_registers.h
Normal file
109
arch/arm/perfmon/cp15_registers.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Code Aurora nor
|
||||
* the names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
cp15_registers.h
|
||||
|
||||
DESCRIPTION: define macros for reading and writing to the cp registers
|
||||
for the ARMv7
|
||||
|
||||
REV/DATE: Fri Mar 18 15:54:32 EST 2005
|
||||
*/
|
||||
|
||||
#ifndef __cp15_registers__
|
||||
#define __cp15_registers__
|
||||
|
||||
#include "mcrmrc.h"
|
||||
|
||||
#define WCP15_SDER(reg) MCR15(reg, 0, c1, c1, 1)
|
||||
/*
|
||||
* Performance Monitor Registers
|
||||
*/
|
||||
#define WCP15_PMACTLR(reg) MCR15(reg, 0, c9, c15, 5)
|
||||
#define WCP15_PMCCNTCR(reg) MCR15(reg, 0, c9, c15, 2)
|
||||
#define WCP15_PMCCNTR(reg) MCR15(reg, 0, c9, c13, 0)
|
||||
#define WCP15_PMCCNTSR(reg) MCR15(reg, 0, c9, c13, 3)
|
||||
#define WCP15_PMCNTENCLR(reg) MCR15(reg, 0, c9, c12, 2)
|
||||
#define WCP15_PMCNTENSET(reg) MCR15(reg, 0, c9, c12, 1)
|
||||
#define WCP15_PMCR(reg) MCR15(reg, 0, c9, c12, 0)
|
||||
#define WCP15_PMINTENCLR(reg) MCR15(reg, 0, c9, c14, 2)
|
||||
#define WCP15_PMINTENSET(reg) MCR15(reg, 0, c9, c14, 1)
|
||||
#define WCP15_PMOVSR(reg) MCR15(reg, 0, c9, c12, 3)
|
||||
#define WCP15_PMRLDR(reg) MCR15(reg, 0, c9, c15, 4)
|
||||
#define WCP15_PMSELR(reg) MCR15(reg, 0, c9, c12, 5)
|
||||
#define WCP15_PMSWINC(reg) MCR15(reg, 0, c9, c12, 4)
|
||||
#define WCP15_PMUSERENR(reg) MCR15(reg, 0, c9, c14, 0)
|
||||
#define WCP15_PMXEVCNTCR(reg) MCR15(reg, 0, c9, c15, 0)
|
||||
#define WCP15_PMXEVCNTR(reg) MCR15(reg, 0, c9, c13, 2)
|
||||
#define WCP15_PMXEVCNTSR(reg) MCR15(reg, 0, c9, c15, 1)
|
||||
#define WCP15_PMXEVTYPER(reg) MCR15(reg, 0, c9, c13, 1)
|
||||
#define WCP15_LPM0EVTYPER(reg) MCR15(reg, 0, c15, c0, 0)
|
||||
#define WCP15_LPM1EVTYPER(reg) MCR15(reg, 1, c15, c0, 0)
|
||||
#define WCP15_LPM2EVTYPER(reg) MCR15(reg, 2, c15, c0, 0)
|
||||
#define WCP15_LPM3EVTYPER(reg) MCR15(reg, 3, c15, c0, 0)
|
||||
#define WCP15_L2LPMEVTYPER(reg) MCR15(reg, 3, c15, c2, 0)
|
||||
#define WCP15_VLPMEVTYPER(reg) MCR15(reg, 7, c11, c0, 0)
|
||||
#define WCP15_L2VR3F1(reg) MCR15(reg, 3, c15, c15, 1)
|
||||
|
||||
/*
|
||||
* READ the registers
|
||||
*/
|
||||
#define RCP15_SDER(reg) MRC15(reg, 0, c1, c1, 1)
|
||||
/*
|
||||
* Performance Monitor Registers
|
||||
*/
|
||||
#define RCP15_PMACTLR(reg) MRC15(reg, 0, c9, c15, 5)
|
||||
#define RCP15_PMCCNTCR(reg) MRC15(reg, 0, c9, c15, 2)
|
||||
#define RCP15_PMCCNTR(reg) MRC15(reg, 0, c9, c13, 0)
|
||||
#define RCP15_PMCCNTSR(reg) MRC15(reg, 0, c9, c13, 3)
|
||||
#define RCP15_PMCNTENCLR(reg) MRC15(reg, 0, c9, c12, 2)
|
||||
#define RCP15_PMCNTENSET(reg) MRC15(reg, 0, c9, c12, 1)
|
||||
#define RCP15_PMCR(reg) MRC15(reg, 0, c9, c12, 0)
|
||||
#define RCP15_PMINTENCLR(reg) MRC15(reg, 0, c9, c14, 2)
|
||||
#define RCP15_PMINTENSET(reg) MRC15(reg, 0, c9, c14, 1)
|
||||
#define RCP15_PMOVSR(reg) MRC15(reg, 0, c9, c12, 3)
|
||||
#define RCP15_PMRLDR(reg) MRC15(reg, 0, c9, c15, 4)
|
||||
#define RCP15_PMSELR(reg) MRC15(reg, 0, c9, c12, 5)
|
||||
#define RCP15_PMSWINC(reg) MRC15(reg, 0, c9, c12, 4)
|
||||
#define RCP15_PMUSERENR(reg) MRC15(reg, 0, c9, c14, 0)
|
||||
#define RCP15_PMXEVCNTCR(reg) MRC15(reg, 0, c9, c15, 0)
|
||||
#define RCP15_PMXEVCNTR(reg) MRC15(reg, 0, c9, c13, 2)
|
||||
#define RCP15_PMXEVCNTSR(reg) MRC15(reg, 0, c9, c15, 1)
|
||||
#define RCP15_PMXEVTYPER(reg) MRC15(reg, 0, c9, c13, 1)
|
||||
#define RCP15_LPM0EVTYPER(reg) MRC15(reg, 0, c15, c0, 0)
|
||||
#define RCP15_LPM1EVTYPER(reg) MRC15(reg, 1, c15, c0, 0)
|
||||
#define RCP15_LPM2EVTYPER(reg) MRC15(reg, 2, c15, c0, 0)
|
||||
#define RCP15_LPM3EVTYPER(reg) MRC15(reg, 3, c15, c0, 0)
|
||||
#define RCP15_L2LPMEVTYPER(reg) MRC15(reg, 3, c15, c2, 0)
|
||||
#define RCP15_VLPMEVTYPER(reg) MRC15(reg, 7, c11, c0, 0)
|
||||
#define RCP15_CONTEXTIDR(reg) MRC15(reg, 0, c13, c0, 1)
|
||||
#define RCP15_L2CR0(reg) MRC15(reg, 3, c15, c0, 1)
|
||||
#define RCP15_L2VR3F1(reg) MRC15(reg, 3, c15, c15, 1)
|
||||
|
||||
#endif
|
||||
|
||||
103
arch/arm/perfmon/l2_cp15_registers.h
Normal file
103
arch/arm/perfmon/l2_cp15_registers.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Code Aurora nor
|
||||
* the names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
cp15_registers.h
|
||||
|
||||
DESCRIPTION: define macros for reading and writing to the cp registers
|
||||
for the ARMv7
|
||||
|
||||
REV/DATE: Fri Mar 18 15:54:32 EST 2005
|
||||
*/
|
||||
|
||||
#ifndef __l2_cp15_registers__
|
||||
#define __l2_cp15_registers__
|
||||
|
||||
#include "mcrmrc.h"
|
||||
|
||||
#define WCP15_SDER(reg) MCR15(reg, 0, c1, c1, 1)
|
||||
/*
|
||||
* Performance Monitor Registers
|
||||
*/
|
||||
#define WCP15_L2MPCR(reg) MCR15(reg, 3, c15, c0, 4)
|
||||
#define WCP15_L2PMCCNTCR(reg) MCR15(reg, 3, c15, c4, 4)
|
||||
#define WCP15_L2PMCCNTR(reg) MCR15(reg, 3, c15, c4, 5)
|
||||
#define WCP15_L2PMCCNTSR(reg) MCR15(reg, 3, c15, c4, 6)
|
||||
#define WCP15_L2PMCNTENCLR(reg) MCR15(reg, 3, c15, c4, 2)
|
||||
#define WCP15_L2PMCNTENSET(reg) MCR15(reg, 3, c15, c4, 3)
|
||||
#define WCP15_L2PMCR(reg) MCR15(reg, 3, c15, c4, 0)
|
||||
#define WCP15_L2PMINTENCLR(reg) MCR15(reg, 3, c15, c5, 0)
|
||||
#define WCP15_L2PMINTENSET(reg) MCR15(reg, 3, c15, c5, 1)
|
||||
#define WCP15_L2PMOVSR(reg) MCR15(reg, 3, c15, c4, 1)
|
||||
#define WCP15_L2PMRLDR(reg) MCR15(reg, 3, c15, c4, 7)
|
||||
#define WCP15_L2PMSELR(reg) MCR15(reg, 3, c15, c6, 0)
|
||||
#define WCP15_L2PMXEVCNTCR(reg) MCR15(reg, 3, c15, c6, 4)
|
||||
#define WCP15_L2PMXEVCNTR(reg) MCR15(reg, 3, c15, c6, 5)
|
||||
#define WCP15_L2PMXEVCNTSR(reg) MCR15(reg, 3, c15, c6, 6)
|
||||
#define WCP15_L2PMXEVTYPER(reg) MCR15(reg, 3, c15, c6, 7)
|
||||
#define WCP15_L2PMXEVFILTER(reg) MCR15(reg, 3, c15, c6, 3)
|
||||
#define WCP15_L2PMEVTYPER0(reg) MCR15(reg, 3, c15, c7, 0)
|
||||
#define WCP15_L2PMEVTYPER1(reg) MCR15(reg, 3, c15, c7, 1)
|
||||
#define WCP15_L2PMEVTYPER2(reg) MCR15(reg, 3, c15, c7, 2)
|
||||
#define WCP15_L2PMEVTYPER3(reg) MCR15(reg, 3, c15, c7, 3)
|
||||
#define WCP15_L2PMEVTYPER4(reg) MCR15(reg, 3, c15, c7, 4)
|
||||
#define WCP15_L2VR3F1(reg) MCR15(reg, 3, c15, c15, 1)
|
||||
|
||||
/*
|
||||
* READ the registers
|
||||
*/
|
||||
#define RCP15_SDER(reg) MRC15(reg, 0, c1, c1, 1)
|
||||
/*
|
||||
* Performance Monitor Registers
|
||||
*/
|
||||
#define RCP15_L2MPCR(reg) MRC15(reg, 3, c15, c0, 4)
|
||||
#define RCP15_L2PMCCNTCR(reg) MRC15(reg, 3, c15, c4, 4)
|
||||
#define RCP15_L2PMCCNTR(reg) MRC15(reg, 3, c15, c4, 5)
|
||||
#define RCP15_L2PMCCNTSR(reg) MRC15(reg, 3, c15, c4, 6)
|
||||
#define RCP15_L2PMCNTENCLR(reg) MRC15(reg, 3, c15, c4, 2)
|
||||
#define RCP15_L2PMCNTENSET(reg) MRC15(reg, 3, c15, c4, 3)
|
||||
#define RCP15_L2PMCR(reg) MRC15(reg, 3, c15, c4, 0)
|
||||
#define RCP15_L2PMINTENCLR(reg) MRC15(reg, 3, c15, c5, 0)
|
||||
#define RCP15_L2PMINTENSET(reg) MRC15(reg, 3, c15, c5, 1)
|
||||
#define RCP15_L2PMOVSR(reg) MRC15(reg, 3, c15, c4, 1)
|
||||
#define RCP15_L2PMRLDR(reg) MRC15(reg, 3, c15, c4, 7)
|
||||
#define RCP15_L2PMSELR(reg) MRC15(reg, 3, c15, c6, 0)
|
||||
#define RCP15_L2PMXEVCNTCR(reg) MRC15(reg, 3, c15, c6, 4)
|
||||
#define RCP15_L2PMXEVCNTR(reg) MRC15(reg, 3, c15, c6, 5)
|
||||
#define RCP15_L2PMXEVCNTSR(reg) MRC15(reg, 3, c15, c6, 6)
|
||||
#define RCP15_L2PMXEVTYPER(reg) MRC15(reg, 3, c15, c6, 7)
|
||||
#define RCP15_L2PMXEVFILTER(reg) MRC15(reg, 3, c15, c6, 3)
|
||||
#define RCP15_L2PMEVTYPER0(reg) MRC15(reg, 3, c15, c7, 0)
|
||||
#define RCP15_L2PMEVTYPER1(reg) MRC15(reg, 3, c15, c7, 1)
|
||||
#define RCP15_L2PMEVTYPER2(reg) MRC15(reg, 3, c15, c7, 2)
|
||||
#define RCP15_L2PMEVTYPER3(reg) MRC15(reg, 3, c15, c7, 3)
|
||||
#define RCP15_L2PMEVTYPER4(reg) MRC15(reg, 3, c15, c7, 4)
|
||||
#define RCP15_L2VR3F1(reg) MRC15(reg, 3, c15, c15, 1)
|
||||
|
||||
#endif
|
||||
|
||||
101
arch/arm/perfmon/mcrmrc.h
Normal file
101
arch/arm/perfmon/mcrmrc.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Code Aurora nor
|
||||
* the names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
mrcmcr.h
|
||||
|
||||
DESCRIPTION: Convenience macros for access the cp registers in the arm.
|
||||
|
||||
REV/DATE: Fri Mar 18 16:34:44 EST 2005
|
||||
*/
|
||||
|
||||
#ifndef __mrcmcr__h_
|
||||
#define __mrcmcr__h_
|
||||
|
||||
/*
|
||||
* Define some convenience macros to acccess the cp registers from c code
|
||||
* Lots of macro trickery here.
|
||||
*
|
||||
* Takes the same format as the asm instructions and unfortunatly you cannot
|
||||
* use variables to select the crn, crn or op fields...
|
||||
*
|
||||
* For those unfamiliar with the # and string stuff.
|
||||
* # creates a string from the value and any two strings that are beside
|
||||
* are concatenated...thus these create one big asm string for the
|
||||
* inline asm code.
|
||||
*
|
||||
* When compiled these compile to single asm instructions (fast) but
|
||||
* without all the hassel of __asm__ __volatile__ (...) =r
|
||||
*
|
||||
* Format is:
|
||||
*
|
||||
* unsigned long reg; // destination variable
|
||||
* MRC(reg, p15, 0, c1, c0, 0 );
|
||||
*
|
||||
* MRC read control register
|
||||
* MCR control register write
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some assembly macros so we can use the same macros as in the C version.
|
||||
* Turns the ASM code a little C-ish but keeps the code consistent and in
|
||||
* one location...
|
||||
*/
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
|
||||
#define MRC(reg, processor, op1, crn, crm, op2) \
|
||||
(mrc processor , op1 , reg, crn , crm , op2)
|
||||
|
||||
#define MCR(reg, processor, op1, crn, crm, op2) \
|
||||
(mcr processor , op1 , reg, crn , crm , op2)
|
||||
|
||||
/*
|
||||
* C version of the macros.
|
||||
*/
|
||||
#else
|
||||
|
||||
#define MRC(reg, processor, op1, crn, crm, op2) \
|
||||
__asm__ __volatile__ ( \
|
||||
" mrc " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \
|
||||
: "=r" (reg))
|
||||
|
||||
#define MCR(reg, processor, op1, crn, crm, op2) \
|
||||
__asm__ __volatile__ ( \
|
||||
" mcr " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \
|
||||
: : "r" (reg))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Easy access convenience function to read CP15 registers from c code
|
||||
*/
|
||||
#define MRC15(reg, op1, crn, crm, op2) MRC(reg, p15, op1, crn, crm, op2)
|
||||
#define MCR15(reg, op1, crn, crm, op2) MCR(reg, p15, op1, crn, crm, op2)
|
||||
|
||||
#endif
|
||||
764
arch/arm/perfmon/per-axi.c
Normal file
764
arch/arm/perfmon/per-axi.c
Normal file
@@ -0,0 +1,764 @@
|
||||
/* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
per-axi
|
||||
DESCRIPTION
|
||||
Functions related to AXI bus performance counter manipulations.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include "asm/uaccess.h"
|
||||
#include "per-axi.h"
|
||||
#include "perf.h"
|
||||
|
||||
/*
|
||||
Definitions for AXI register addresses, macros to set and get register values
|
||||
*/
|
||||
#define AXI_BASE_SIZE 0x00004000
|
||||
#define AXI_REG_BASE (AXI_BASE + 0x00000000)
|
||||
#define AXI_REG_BASE_PHYS 0xa8200000
|
||||
|
||||
#define __inpdw(port) ioread32(port)
|
||||
#define in_dword_masked(addr, mask) (__inpdw(addr) & (mask))
|
||||
#define __outpdw(port, val) (iowrite32((uint32_t) (val), port))
|
||||
#define out_dword(addr, val) __outpdw(addr, val)
|
||||
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR \
|
||||
(AXI_REG_BASE + 0x00003434)
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR, \
|
||||
HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_RMSK)
|
||||
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR (AXI_REG_BASE + 0x00003438)
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR, \
|
||||
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_RMSK)
|
||||
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_ADDR (AXI_REG_BASE + 0x00003428)
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG1_ADDR (AXI_REG_BASE + 0x0000342c)
|
||||
#define HWIO_AXI_MONITOR_TENURE_SELECTION_REG_ADDR (AXI_REG_BASE + 0x00003430)
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_ETC_BMSK 0x4000
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_ECC_BMSK 0x2000
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_EEC1_BMSK 0x800
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_EEC0_BMSK 0x200
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(v) \
|
||||
out_dword(HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR, v)
|
||||
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(v) \
|
||||
out_dword(HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR, v)
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_OUT(v) \
|
||||
out_dword(HWIO_AXI_MONITOR_SELECTION_REG0_ADDR, v)
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG1_OUT(v) \
|
||||
out_dword(HWIO_AXI_MONITOR_SELECTION_REG1_ADDR, v)
|
||||
#define HWIO_AXI_MONITOR_TENURE_SELECTION_REG_OUT(v) \
|
||||
out_dword(HWIO_AXI_MONITOR_TENURE_SELECTION_REG_ADDR, v)
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_SELECTION_REG0_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_SELECTION_REG0_ADDR, \
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_RMSK)
|
||||
|
||||
#define HWIO_AXI_CONFIGURATION_REG_ADDR (AXI_REG_BASE + 0x00000008)
|
||||
#define HWIO_AXI_CONFIGURATION_REG_OUT(v) \
|
||||
out_dword(HWIO_AXI_CONFIGURATION_REG_ADDR, v)
|
||||
#define HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK 0x0
|
||||
#define HWIO_AXI_CONFIGURATION_REG_DISABLE 0x2
|
||||
#define AXI_EVTSEL_ENABLE_MASK 0x6a00
|
||||
#define AXI_EVTSEL_DISABLE_MASK 0x95ff
|
||||
#define AXI_EVTSEL_RESET_MASK 0xfe40
|
||||
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_ADDR (AXI_REG_BASE + 0x00003450)
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_EVENT_LOWER_REG0_ADDR, \
|
||||
HWIO_AXI_MONITOR_EVENT_LOWER_REG0_RMSK)
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_ADDR (AXI_REG_BASE + 0x00003454)
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_EVENT_UPPER_REG0_ADDR, \
|
||||
HWIO_AXI_MONITOR_EVENT_UPPER_REG0_RMSK)
|
||||
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_ADDR (AXI_REG_BASE + 0x00003458)
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_EVENT_LOWER_REG1_ADDR, \
|
||||
HWIO_AXI_MONITOR_EVENT_LOWER_REG1_RMSK)
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_ADDR (AXI_REG_BASE + 0x0000345c)
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_EVENT_UPPER_REG1_ADDR, \
|
||||
HWIO_AXI_MONITOR_EVENT_UPPER_REG1_RMSK)
|
||||
|
||||
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR (AXI_REG_BASE + 0x00003448)
|
||||
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR, \
|
||||
HWIO_AXI_MONITOR_TENURE_LOWER_REG_RMSK)
|
||||
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR (AXI_REG_BASE + 0x00003444)
|
||||
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR, \
|
||||
HWIO_AXI_MONITOR_TENURE_UPPER_REG_RMSK)
|
||||
|
||||
#define HWIO_AXI_MONITOR_MIN_REG_ADDR (AXI_REG_BASE + 0x0000343c)
|
||||
#define HWIO_AXI_MONITOR_MIN_REG_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_MIN_REG_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_MIN_REG_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_MIN_REG_ADDR, \
|
||||
HWIO_AXI_MONITOR_MIN_REG_RMSK)
|
||||
#define HWIO_AXI_MONITOR_MAX_REG_ADDR (AXI_REG_BASE + 0x00003440)
|
||||
#define HWIO_AXI_MONITOR_MAX_REG_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_MAX_REG_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_MAX_REG_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_MAX_REG_ADDR, \
|
||||
HWIO_AXI_MONITOR_MAX_REG_RMSK)
|
||||
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_ADDR (AXI_REG_BASE + 0x0000344c)
|
||||
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_RMSK 0xffff
|
||||
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_SHFT 0
|
||||
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_IN \
|
||||
in_dword_masked(HWIO_AXI_MONITOR_LAST_TENURE_REG_ADDR, \
|
||||
HWIO_AXI_MONITOR_LAST_TENURE_REG_RMSK)
|
||||
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_OUT(v) \
|
||||
out_dword(HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR, v)
|
||||
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_OUT(v) \
|
||||
out_dword(HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR, v)
|
||||
|
||||
#define HWIO_AXI_RESET_ALL 0x9400
|
||||
#define HWIO_AXI_ENABLE_ALL_NOCYCLES 0x4a00
|
||||
#define HWIO_AXI_DISABLE_ALL 0xb500
|
||||
uint32_t AXI_BASE;
|
||||
|
||||
unsigned int is_first = 1;
|
||||
struct perf_mon_axi_data pm_axi_info;
|
||||
struct perf_mon_axi_cnts axi_cnts;
|
||||
|
||||
/*
|
||||
FUNCTION get_axi_sel_reg0
|
||||
|
||||
DESCRIPTION
|
||||
Retrieve the value of AXI_SEL_REG0
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
AXI_SEL_REG0
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long get_axi_sel_reg0(void)
|
||||
{
|
||||
return pm_axi_info.sel_reg0;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION get_axi_sel_reg1
|
||||
|
||||
DESCRIPTION
|
||||
Retrieve the value of AXI_SEL_REG1
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
AXI_SEL_REG1
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long get_axi_sel_reg1(void)
|
||||
{
|
||||
return pm_axi_info.sel_reg1;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION get_axi_ten_sel_reg
|
||||
|
||||
DESCRIPTION
|
||||
Retrieve the value of AXI_TEN_REG
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
AXI_TEN_REG
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long get_axi_ten_sel_reg(void)
|
||||
{
|
||||
return pm_axi_info.ten_sel_reg;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION get_axi_valid
|
||||
|
||||
DESCRIPTION
|
||||
Retrieve the value of AXI valid bit
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
AXI Valid bit
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long get_axi_valid(void)
|
||||
{
|
||||
return pm_axi_info.valid;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION get_axi_enable
|
||||
|
||||
DESCRIPTION
|
||||
Retrieve the value of AXI enable bit
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
AXI enable bit
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long get_axi_enable(void)
|
||||
{
|
||||
return pm_axi_info.enable;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION get_axi_clear
|
||||
|
||||
DESCRIPTION
|
||||
Retrieve the value of AXI clear bit
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
AXI clear bit
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long get_axi_clear(void)
|
||||
{
|
||||
return pm_axi_info.clear;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_cnts_write
|
||||
|
||||
DESCRIPTION
|
||||
Write handler for the /proc axi results directory.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
Number of characters to output.
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
int pm_axi_cnts_write(struct file *file, const char *buff,
|
||||
unsigned long cnt, void *data)
|
||||
{
|
||||
char *newbuf;
|
||||
struct PerfMonAxiCnts *p =
|
||||
(struct PerfMonAxiCnts *)data;
|
||||
|
||||
if (p == 0)
|
||||
return cnt;
|
||||
/*
|
||||
* Alloc the user data in kernel space. and then copy user to kernel
|
||||
*/
|
||||
newbuf = kmalloc(cnt + 1, GFP_KERNEL);
|
||||
if (0 == newbuf)
|
||||
return cnt;
|
||||
if (copy_from_user(newbuf, buff, cnt) != 0) {
|
||||
printk(KERN_INFO "%s copy_from_user failed\n", __func__);
|
||||
return cnt;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_update_cnts
|
||||
|
||||
DESCRIPTION
|
||||
Read the current AXI counter values. Check for overflows and
|
||||
adjust the values stored accordingly.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_axi_update_cnts(void)
|
||||
{
|
||||
if (is_first) {
|
||||
pm_axi_start();
|
||||
} else {
|
||||
if (pm_axi_info.valid == 1) {
|
||||
pm_axi_info.valid = 0;
|
||||
pm_axi_update();
|
||||
} else {
|
||||
pm_axi_enable();
|
||||
}
|
||||
}
|
||||
is_first = 0;
|
||||
axi_cnts.cycles += pm_get_axi_cycle_count();
|
||||
axi_cnts.cnt0 += pm_get_axi_evt0_count();
|
||||
axi_cnts.cnt1 += pm_get_axi_evt1_count();
|
||||
axi_cnts.tenure_total += pm_get_axi_ten_total_count();
|
||||
|
||||
axi_cnts.tenure_min = pm_get_axi_ten_min_count();
|
||||
axi_cnts.tenure_max = pm_get_axi_ten_max_count();
|
||||
axi_cnts.tenure_last = pm_get_axi_ten_last_count();
|
||||
|
||||
pm_axi_start();
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_clear_cnts
|
||||
|
||||
DESCRIPTION
|
||||
Clear the locally stored AXI counter values.
|
||||
Also clear the AXI counter registers.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_axi_clear_cnts(void)
|
||||
{
|
||||
axi_cnts.cycles = 0;
|
||||
axi_cnts.cnt0 = 0;
|
||||
axi_cnts.cnt1 = 0;
|
||||
axi_cnts.tenure_total = 0;
|
||||
axi_cnts.tenure_min = 0;
|
||||
axi_cnts.tenure_max = 0;
|
||||
axi_cnts.tenure_last = 0;
|
||||
pm_axi_start();
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_read_decimal
|
||||
|
||||
DESCRIPTION
|
||||
Read handler for the /proc axi results directory in decimal format.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
Number of characters to output.
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
int pm_axi_read_decimal(char *page, char **start, off_t off, int count,
|
||||
int *eof, void *data)
|
||||
{
|
||||
struct perf_mon_axi_cnts *p = (struct perf_mon_axi_cnts *)data;
|
||||
|
||||
return sprintf(page, "cnt0:%llu cnt1:%llu tenure:%llu ten_max:%llu \
|
||||
ten_min:%llu ten_last:%llu cycles:%llu\n",
|
||||
p->cnt0,
|
||||
p->cnt1,
|
||||
p->tenure_total,
|
||||
p->tenure_max,
|
||||
p->tenure_min,
|
||||
p->tenure_last,
|
||||
p->cycles);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_read_hex
|
||||
|
||||
DESCRIPTION
|
||||
Read handler for the /proc axi results directory in hex format.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
Number of characters to output.
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
int pm_axi_read_hex(char *page, char **start, off_t off, int count,
|
||||
int *eof, void *data)
|
||||
{
|
||||
struct perf_mon_axi_cnts *p = (struct perf_mon_axi_cnts *)data;
|
||||
|
||||
return sprintf(page, "cnt0:%llx cnt1:%llx tenure:%llx ten_max:%llx \
|
||||
ten_min:%llx ten_last:%llx cycles:%llx\n",
|
||||
p->cnt0,
|
||||
p->cnt1,
|
||||
p->tenure_total,
|
||||
p->tenure_max,
|
||||
p->tenure_min,
|
||||
p->tenure_last,
|
||||
p->cycles);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_set_proc_entry
|
||||
|
||||
DESCRIPTION
|
||||
Create a generic entry for the /proc axi settings directory.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_axi_set_proc_entry(char *name, unsigned long *var,
|
||||
struct proc_dir_entry *d, int hex)
|
||||
{
|
||||
struct proc_dir_entry *pe;
|
||||
pe = create_proc_entry(name, 0777, d);
|
||||
if (0 == pe)
|
||||
return;
|
||||
if (hex) {
|
||||
pe->read_proc = per_process_read;
|
||||
pe->write_proc = per_process_write_hex;
|
||||
} else {
|
||||
pe->read_proc = per_process_read_decimal;
|
||||
pe->write_proc = per_process_write_dec;
|
||||
}
|
||||
pe->data = (void *)var;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_get_cnt_proc_entry
|
||||
|
||||
DESCRIPTION
|
||||
Create a generic entry for the /proc axi results directory.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_axi_get_cnt_proc_entry(char *name, struct perf_mon_axi_cnts *var,
|
||||
struct proc_dir_entry *d, int hex)
|
||||
{
|
||||
struct proc_dir_entry *pe;
|
||||
pe = create_proc_entry(name, 0777, d);
|
||||
if (0 == pe)
|
||||
return;
|
||||
if (hex) {
|
||||
pe->read_proc = pm_axi_read_hex;
|
||||
pe->write_proc = pm_axi_cnts_write;
|
||||
} else {
|
||||
pe->read_proc = pm_axi_read_decimal;
|
||||
pe->write_proc = pm_axi_cnts_write;
|
||||
}
|
||||
pe->data = (void *)var;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_clear_tenure
|
||||
|
||||
DESCRIPTION
|
||||
Clear AXI tenure cntr manually. Temporary solution till hardware bug
|
||||
is fixed
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_axi_clear_tenure(void)
|
||||
{
|
||||
HWIO_AXI_MONITOR_TENURE_UPPER_REG_OUT(0x0);
|
||||
HWIO_AXI_MONITOR_TENURE_LOWER_REG_OUT(0x0);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_init
|
||||
|
||||
DESCRIPTION
|
||||
Map AXI region to virtual memory.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_axi_init()
|
||||
{
|
||||
/*Map the AXI regs*/
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
{
|
||||
/*Map the AXI regs*/
|
||||
AXI_BASE = (uint32_t)ioremap(AXI_REG_BASE_PHYS, AXI_BASE_SIZE);
|
||||
if (!AXI_BASE)
|
||||
printk(KERN_ERR "Mem map failed\n");
|
||||
}
|
||||
#else
|
||||
{
|
||||
AXI_BASE = (uint32_t)kmalloc(AXI_BASE_SIZE, GFP_KERNEL);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_start
|
||||
|
||||
DESCRIPTION
|
||||
Set event0, event1 and tenure registers based on the /proc entries.
|
||||
Set cycle cntr to fffffffe to start counters.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void
|
||||
pm_axi_start()
|
||||
{
|
||||
unsigned long sel_reg0, sel_reg1, ten_sel_reg;
|
||||
sel_reg0 = get_axi_sel_reg0();
|
||||
sel_reg1 = get_axi_sel_reg1();
|
||||
ten_sel_reg = get_axi_ten_sel_reg();
|
||||
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||||
/*Set AXI Cycle Counter to enable AXI Monitors*/
|
||||
HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(0xffff);
|
||||
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(0xfffe);
|
||||
/*Set master/slave*/
|
||||
HWIO_AXI_MONITOR_SELECTION_REG1_OUT(sel_reg1);
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_RESET_ALL);
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_ENABLE_ALL_NOCYCLES);
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||||
| sel_reg0);
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||||
| HWIO_AXI_MONITOR_SELECTION_REG0_ECC_BMSK);
|
||||
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_update
|
||||
|
||||
DESCRIPTION
|
||||
Set event0, event1 and tenure registers based on the /proc entries.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void
|
||||
pm_axi_update()
|
||||
{
|
||||
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||||
| HWIO_AXI_RESET_ALL);
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||||
& HWIO_AXI_DISABLE_ALL);
|
||||
pm_axi_start();
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_disable
|
||||
|
||||
DESCRIPTION
|
||||
Disable all cntrs.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void
|
||||
pm_axi_disable(void)
|
||||
{
|
||||
unsigned long sel_reg0;
|
||||
/*Disable cntrs*/
|
||||
sel_reg0 = get_axi_sel_reg0();
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(sel_reg0 & AXI_EVTSEL_DISABLE_MASK);
|
||||
/*Disable clk*/
|
||||
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_DISABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_enable
|
||||
|
||||
DESCRIPTION
|
||||
Enable all cntrs.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void
|
||||
pm_axi_enable(void)
|
||||
{
|
||||
unsigned long sel_reg0;
|
||||
/*Enable cntrs*/
|
||||
sel_reg0 = get_axi_sel_reg0();
|
||||
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(sel_reg0 | 0x6a00);
|
||||
/*Enable clk*/
|
||||
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_axi_disable_cnts
|
||||
|
||||
DESCRIPTION
|
||||
Read cycle cntr value
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long
|
||||
pm_get_axi_cycle_count(void)
|
||||
{
|
||||
if (HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN == 0x0 &&
|
||||
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN == 0x0) {
|
||||
/*Set AXI Cycle Counter to enable AXI Monitors*/
|
||||
HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(0xffff);
|
||||
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(0xfffe);
|
||||
}
|
||||
return 0xfffffffe - ((HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN << 16)
|
||||
+ HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_get_axi_evt0_count
|
||||
|
||||
DESCRIPTION
|
||||
Read Event0 cntr value
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long
|
||||
pm_get_axi_evt0_count(void)
|
||||
{
|
||||
return (HWIO_AXI_MONITOR_EVENT_UPPER_REG0_IN << 16)
|
||||
+ HWIO_AXI_MONITOR_EVENT_LOWER_REG0_IN;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_get_axi_evt1_count
|
||||
|
||||
DESCRIPTION
|
||||
Read Event1 cntr value
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long
|
||||
pm_get_axi_evt1_count(void)
|
||||
{
|
||||
return (HWIO_AXI_MONITOR_EVENT_UPPER_REG1_IN << 16)
|
||||
+ HWIO_AXI_MONITOR_EVENT_LOWER_REG1_IN;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_get_axi_ten_min_count
|
||||
|
||||
DESCRIPTION
|
||||
Read min tenure cntr value
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long
|
||||
pm_get_axi_ten_min_count(void)
|
||||
{
|
||||
return HWIO_AXI_MONITOR_MIN_REG_IN;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_get_axi_ten_max_count
|
||||
|
||||
DESCRIPTION
|
||||
Read max tenure cntr value
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long
|
||||
pm_get_axi_ten_max_count(void)
|
||||
{
|
||||
return HWIO_AXI_MONITOR_MAX_REG_IN;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_get_axi_ten_total_count
|
||||
|
||||
DESCRIPTION
|
||||
Read total tenure cntr value
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long
|
||||
pm_get_axi_ten_total_count(void)
|
||||
{
|
||||
return (HWIO_AXI_MONITOR_TENURE_UPPER_REG_IN << 16)
|
||||
+ HWIO_AXI_MONITOR_TENURE_LOWER_REG_IN;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_get_axi_ten_last_count
|
||||
|
||||
DESCRIPTION
|
||||
Read last tenure cntr value
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
unsigned long
|
||||
pm_get_axi_ten_last_count(void)
|
||||
{
|
||||
return HWIO_AXI_MONITOR_LAST_TENURE_REG_IN;
|
||||
}
|
||||
91
arch/arm/perfmon/per-axi.h
Normal file
91
arch/arm/perfmon/per-axi.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Code Aurora nor
|
||||
* the names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*per-axi
|
||||
*DESCRIPTION
|
||||
*Header File for Functions related to AXI bus performance counter manipulations.
|
||||
*/
|
||||
|
||||
#ifndef __PER_AXI_H__
|
||||
#define __PER_AXI_H__
|
||||
unsigned long pm_get_axi_cycle_count(void);
|
||||
unsigned long pm_get_axi_evt0_count(void);
|
||||
unsigned long pm_get_axi_evt1_count(void);
|
||||
unsigned long pm_get_axi_evt2_count(void);
|
||||
unsigned long pm_get_axi_ten_min_count(void);
|
||||
unsigned long pm_get_axi_ten_max_count(void);
|
||||
unsigned long pm_get_axi_ten_total_count(void);
|
||||
unsigned long pm_get_axi_ten_last_count(void);
|
||||
|
||||
unsigned long get_axi_sel_reg0(void);
|
||||
unsigned long get_axi_sel_seg1(void);
|
||||
unsigned long get_axi_ten_sel_reg(void);
|
||||
unsigned long get_axi_valid(void);
|
||||
unsigned long get_axi_enable(void);
|
||||
unsigned long get_axi_clear(void);
|
||||
|
||||
void pm_axi_clear_cnts(void);
|
||||
void pm_axi_update_cnts(void);
|
||||
|
||||
void pm_axi_init(void);
|
||||
void pm_axi_start(void);
|
||||
void pm_axi_update(void);
|
||||
void pm_axi_disable(void);
|
||||
void pm_axi_enable(void);
|
||||
|
||||
struct perf_mon_axi_cnts{
|
||||
unsigned long long cycles;
|
||||
unsigned long long cnt0;
|
||||
unsigned long long cnt1;
|
||||
unsigned long long tenure_total;
|
||||
unsigned long long tenure_min;
|
||||
unsigned long long tenure_max;
|
||||
unsigned long long tenure_last;
|
||||
};
|
||||
|
||||
struct perf_mon_axi_data{
|
||||
struct proc_dir_entry *proc;
|
||||
unsigned long enable;
|
||||
unsigned long clear;
|
||||
unsigned long valid;
|
||||
unsigned long sel_reg0;
|
||||
unsigned long sel_reg1;
|
||||
unsigned long ten_sel_reg;
|
||||
unsigned long refresh;
|
||||
};
|
||||
|
||||
extern struct perf_mon_axi_data pm_axi_info;
|
||||
extern struct perf_mon_axi_cnts axi_cnts;
|
||||
|
||||
void pm_axi_set_proc_entry(char *name, unsigned long *var,
|
||||
struct proc_dir_entry *d, int hex);
|
||||
void pm_axi_get_cnt_proc_entry(char *name, struct perf_mon_axi_cnts *var,
|
||||
struct proc_dir_entry *d, int hex);
|
||||
|
||||
#endif
|
||||
1256
arch/arm/perfmon/per-process-perf.c
Normal file
1256
arch/arm/perfmon/per-process-perf.c
Normal file
File diff suppressed because it is too large
Load Diff
64
arch/arm/perfmon/per.c
Normal file
64
arch/arm/perfmon/per.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
per.c
|
||||
|
||||
DESCRIPTION: Performance count interface for linux via proc in the T32
|
||||
command file style
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/time.h>
|
||||
#include "linux/proc_fs.h"
|
||||
#include "linux/kernel_stat.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include "cp15_registers.h"
|
||||
#include "perf.h"
|
||||
|
||||
#define PM_PER_ERR -1
|
||||
/*
|
||||
FUNCTION perf_if_proc_init
|
||||
|
||||
DESCRIPTION Initialize the proc interface for thje performance data.
|
||||
*/
|
||||
static __init int per_init(void)
|
||||
{
|
||||
|
||||
if (atomic_read(&pm_op_lock) == 1) {
|
||||
printk(KERN_INFO "Can not load KSAPI, monitors are in use\n");
|
||||
return PM_PER_ERR;
|
||||
}
|
||||
atomic_set(&pm_op_lock, 1);
|
||||
per_process_perf_init();
|
||||
printk(KERN_INFO "ksapi init\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit per_exit(void)
|
||||
{
|
||||
per_process_perf_exit();
|
||||
printk(KERN_INFO "ksapi exit\n");
|
||||
atomic_set(&pm_op_lock, 0);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
module_init(per_init);
|
||||
module_exit(per_exit);
|
||||
86
arch/arm/perfmon/perf-function-hooks.c
Normal file
86
arch/arm/perfmon/perf-function-hooks.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* perf-function-hooks.c
|
||||
* DESCRIPTION
|
||||
* Hooks for ksapi.ko
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/time.h>
|
||||
#include "linux/proc_fs.h"
|
||||
#include "linux/kernel_stat.h"
|
||||
#include "asm/uaccess.h"
|
||||
#include <linux/proc_fs.h>
|
||||
#include "cp15_registers.h"
|
||||
#include <asm/perftypes.h>
|
||||
#include "perf.h"
|
||||
|
||||
/*
|
||||
* Function Pointers for when the module is installed...
|
||||
* Should we use a single "ready" variable for the testing
|
||||
* in the functions below, will be safer when module is removed
|
||||
* testing for a locked variable...
|
||||
*/
|
||||
VPVF pp_interrupt_out_ptr;
|
||||
VPVF pp_interrupt_in_ptr;
|
||||
VPULF pp_process_remove_ptr;
|
||||
unsigned int pp_loaded;
|
||||
EXPORT_SYMBOL(pp_loaded);
|
||||
atomic_t pm_op_lock;
|
||||
EXPORT_SYMBOL(pm_op_lock);
|
||||
|
||||
/*
|
||||
FUNCTION VARIOUS
|
||||
|
||||
DESCRIPTION
|
||||
Hooks to callinto the module functions after they are loaded. The
|
||||
above pointers will be set and then these functions are ready to be
|
||||
called.
|
||||
|
||||
DEPENDENCIES
|
||||
THe per preocess performance monitor needs to be loaded ...
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void perf_mon_interrupt_out(void)
|
||||
{
|
||||
if (pp_loaded)
|
||||
(*pp_interrupt_out_ptr)();
|
||||
}
|
||||
EXPORT_SYMBOL(pp_interrupt_out_ptr);
|
||||
|
||||
void perf_mon_interrupt_in(void)
|
||||
{
|
||||
if (pp_loaded)
|
||||
(*pp_interrupt_in_ptr)();
|
||||
}
|
||||
EXPORT_SYMBOL(pp_interrupt_in_ptr);
|
||||
|
||||
void per_process_remove(unsigned long pid)
|
||||
{
|
||||
if (pp_loaded)
|
||||
(*pp_process_remove_ptr)(pid);
|
||||
}
|
||||
EXPORT_SYMBOL(pp_process_remove_ptr);
|
||||
764
arch/arm/perfmon/perf-smp.c
Normal file
764
arch/arm/perfmon/perf-smp.c
Normal file
@@ -0,0 +1,764 @@
|
||||
/* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
perf-smp.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 "l2_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 L2_PM_ERR -1
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Global control bits
|
||||
------------------------------------------------------------------------*/
|
||||
#define PM_L2_GLOBAL_ENABLE (1<<0)
|
||||
#define PM_L2_EVENT_RESET (1<<1)
|
||||
#define PM_L2_CYCLE_RESET (1<<2)
|
||||
#define PM_L2_CLKDIV (1<<3)
|
||||
#define PM_L2_GLOBAL_TRACE (1<<4)
|
||||
#define PM_L2_DISABLE_PROHIBIT (1<<5)
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
* Enable and clear bits for each event/trigger
|
||||
----------------------------------------------------------------------------*/
|
||||
#define PM_L2EV0_ENABLE (1<<0)
|
||||
#define PM_L2EV1_ENABLE (1<<1)
|
||||
#define PM_L2EV2_ENABLE (1<<2)
|
||||
#define PM_L2EV3_ENABLE (1<<3)
|
||||
#define PM_L2_COUNT_ENABLE (1<<31)
|
||||
#define PM_L2_ALL_ENABLE (0x8000000F)
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Overflow actions
|
||||
------------------------------------------------------------------------------*/
|
||||
#define PM_L2_OVERFLOW_NOACTION (0)
|
||||
#define PM_L2_OVERFLOW_HALT (1)
|
||||
#define PM_L2_OVERFLOW_STOP (2)
|
||||
#define PM_L2_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 L2PM_EVT_PM0_EVT0 0x00
|
||||
#define L2PM_EVT_PM0_EVT1 0x01
|
||||
#define L2PM_EVT_PM0_EVT2 0x02
|
||||
#define L2PM_EVT_PM0_EVT3 0x03
|
||||
#define L2PM_EVT_PM1_EVT0 0x04
|
||||
#define L2PM_EVT_PM1_EVT1 0x05
|
||||
#define L2PM_EVT_PM1_EVT2 0x06
|
||||
#define L2PM_EVT_PM1_EVT3 0x07
|
||||
#define L2PM_EVT_PM2_EVT0 0x08
|
||||
#define L2PM_EVT_PM2_EVT1 0x09
|
||||
#define L2PM_EVT_PM2_EVT2 0x0a
|
||||
#define L2PM_EVT_PM2_EVT3 0x0b
|
||||
#define L2PM_EVT_PM3_EVT0 0x0c
|
||||
#define L2PM_EVT_PM3_EVT1 0x0d
|
||||
#define L2PM_EVT_PM3_EVT2 0x0e
|
||||
#define L2PM_EVT_PM3_EVT3 0x0f
|
||||
#define L2PM_EVT_PM4_EVT0 0x10
|
||||
#define L2PM_EVT_PM4_EVT1 0x11
|
||||
#define L2PM_EVT_PM4_EVT2 0x12
|
||||
#define L2PM_EVT_PM4_EVT3 0x13
|
||||
|
||||
/*
|
||||
Type Declarations
|
||||
*/
|
||||
|
||||
/*
|
||||
Local Object Definitions
|
||||
*/
|
||||
|
||||
unsigned long l2_pm_cycle_overflow_count;
|
||||
unsigned long l2_pm_overflow_count[PM_NUM_COUNTERS];
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Max number of events read from the config registers
|
||||
---------------------------------------------------------------------------*/
|
||||
static int pm_l2_max_events;
|
||||
|
||||
static int irqid;
|
||||
|
||||
/*
|
||||
Function Definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 disable 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_l2_group_stop(unsigned long mask)
|
||||
{
|
||||
WCP15_L2PMCNTENCLR(mask);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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_l2_group_start(unsigned long mask)
|
||||
{
|
||||
WCP15_L2PMCNTENSET(mask);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_get_overflow(int index)
|
||||
{
|
||||
unsigned long overflow = 0;
|
||||
|
||||
/*
|
||||
* Range check
|
||||
*/
|
||||
if (index > pm_l2_max_events)
|
||||
return L2_PM_ERR;
|
||||
RCP15_L2PMOVSR(overflow);
|
||||
|
||||
return overflow & (1<<index);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_get_cycle_overflow(void)
|
||||
{
|
||||
unsigned long overflow = 0;
|
||||
|
||||
RCP15_L2PMOVSR(overflow);
|
||||
return overflow & PM_L2_COUNT_ENABLE;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_pm_reset_overflow
|
||||
|
||||
DESCRIPTION Reset the cycle counter overflow bit.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
None
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void l2_pm_reset_overflow(int index)
|
||||
{
|
||||
WCP15_L2PMOVSR(1<<index);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_pm_reset_cycle_overflow
|
||||
|
||||
DESCRIPTION Reset the cycle counter overflow bit.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
None
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void l2_pm_reset_cycle_overflow(void)
|
||||
{
|
||||
WCP15_L2PMOVSR(PM_L2_COUNT_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_get_cycle_count(void)
|
||||
{
|
||||
unsigned long cnt = 0;
|
||||
RCP15_L2PMCCNTR(cnt);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_reset_cycle_count(void)
|
||||
{
|
||||
WCP15_L2PMCNTENCLR(PM_L2_COUNT_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_cycle_div_64(int enable)
|
||||
{
|
||||
unsigned long enables = 0;
|
||||
|
||||
RCP15_L2PMCR(enables);
|
||||
if (enable)
|
||||
WCP15_L2PMCR(enables | PM_L2_CLKDIV);
|
||||
else
|
||||
WCP15_L2PMCR(enables & ~PM_L2_CLKDIV);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_enable_cycle_counter(void)
|
||||
{
|
||||
/*
|
||||
* Enable the counter.
|
||||
*/
|
||||
WCP15_L2PMCNTENSET(PM_L2_COUNT_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_disable_counter(int index)
|
||||
{
|
||||
/*
|
||||
* Range check
|
||||
*/
|
||||
if (index > pm_l2_max_events)
|
||||
return;
|
||||
WCP15_L2PMCNTENCLR(1<<index);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_pm_enable_counter
|
||||
|
||||
DESCRIPTION Enable the counter with the index passed.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
none.
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void l2_pm_enable_counter(int index)
|
||||
{
|
||||
/*
|
||||
* Range check
|
||||
*/
|
||||
if (index > pm_l2_max_events)
|
||||
return;
|
||||
WCP15_L2PMCNTENSET(1<<index);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_set_count(int index, unsigned long new_value)
|
||||
{
|
||||
unsigned long reg = 0;
|
||||
|
||||
/*
|
||||
* Range check
|
||||
*/
|
||||
if (index > pm_l2_max_events)
|
||||
return L2_PM_ERR;
|
||||
|
||||
/*
|
||||
* Lock, select the index and read the count...unlock
|
||||
*/
|
||||
PM_LOCK();
|
||||
WCP15_L2PMSELR(index);
|
||||
WCP15_L2PMXEVCNTR(new_value);
|
||||
PM_UNLOCK();
|
||||
return reg;
|
||||
}
|
||||
|
||||
int l2_pm_reset_count(int index)
|
||||
{
|
||||
return l2_pm_set_count(index, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_pm_get_count(int index)
|
||||
{
|
||||
unsigned long reg = 0;
|
||||
|
||||
/*
|
||||
* Range check
|
||||
*/
|
||||
if (index > pm_l2_max_events)
|
||||
return L2_PM_ERR;
|
||||
|
||||
/*
|
||||
* Lock, select the index and read the count...unlock
|
||||
*/
|
||||
PM_LOCK();
|
||||
WCP15_L2PMSELR(index);
|
||||
RCP15_L2PMXEVCNTR(reg);
|
||||
PM_UNLOCK();
|
||||
return reg;
|
||||
}
|
||||
|
||||
unsigned long get_filter_code(unsigned long event)
|
||||
{
|
||||
if (event == 0x0 || event == 0x4 || event == 0x08
|
||||
|| event == 0x0c || event == 0x10)
|
||||
return 0x0001003f;
|
||||
else if (event == 0x1 || event == 0x5 || event == 0x09
|
||||
|| event == 0x0d || event == 0x11)
|
||||
return 0x0002003f;
|
||||
else if (event == 0x2 || event == 0x6 || event == 0x0a
|
||||
|| event == 0x0e || event == 0x12)
|
||||
return 0x0004003f;
|
||||
else if (event == 0x3 || event == 0x7 || event == 0x0b
|
||||
|| event == 0x0f || event == 0x13)
|
||||
return 0x0008003f;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l2_pm_set_event(int index, unsigned long event)
|
||||
{
|
||||
unsigned long reg = 0;
|
||||
|
||||
/*
|
||||
* Range check
|
||||
*/
|
||||
if (index > pm_l2_max_events)
|
||||
return L2_PM_ERR;
|
||||
|
||||
/*
|
||||
* Lock, select the index and read the count...unlock
|
||||
*/
|
||||
PM_LOCK();
|
||||
WCP15_L2PMSELR(index);
|
||||
WCP15_L2PMXEVTYPER(event);
|
||||
/* WCP15_L2PMXEVFILTER(get_filter_code(event)); */
|
||||
WCP15_L2PMXEVFILTER(0x000f003f);
|
||||
PM_UNLOCK();
|
||||
return reg;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_set_local_bu
|
||||
|
||||
DESCRIPTION Set the local BU triggers. Note that the MSB determines if
|
||||
these are enabled or not.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
NONE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_set_local_bu(unsigned long value)
|
||||
{
|
||||
WCP15_L2PMEVTYPER0(value);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_set_local_cb
|
||||
|
||||
DESCRIPTION Set the local CB triggers. Note that the MSB determines if
|
||||
these are enabled or not.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
NONE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_set_local_cb(unsigned long value)
|
||||
{
|
||||
WCP15_L2PMEVTYPER1(value);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_set_local_mp
|
||||
|
||||
DESCRIPTION Set the local MP triggers. Note that the MSB determines if
|
||||
these are enabled or not.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
NONE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_set_local_mp(unsigned long value)
|
||||
{
|
||||
WCP15_L2PMEVTYPER2(value);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_set_local_sp
|
||||
|
||||
DESCRIPTION Set the local SP triggers. Note that the MSB determines if
|
||||
these are enabled or not.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
NONE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_set_local_sp(unsigned long value)
|
||||
{
|
||||
WCP15_L2PMEVTYPER3(value);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION pm_set_local_scu
|
||||
|
||||
DESCRIPTION Set the local SCU triggers. Note that the MSB determines if
|
||||
these are enabled or not.
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
NONE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
void pm_set_local_scu(unsigned long value)
|
||||
{
|
||||
WCP15_L2PMEVTYPER4(value);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_pm_isr
|
||||
|
||||
DESCRIPTION:
|
||||
Performance Monitor interrupt service routine to capture overflows
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
SIDE EFFECTS
|
||||
*/
|
||||
static irqreturn_t l2_pm_isr(int irq, void *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PM_NUM_COUNTERS; i++) {
|
||||
if (l2_pm_get_overflow(i)) {
|
||||
l2_pm_overflow_count[i]++;
|
||||
l2_pm_reset_overflow(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (l2_pm_get_cycle_overflow()) {
|
||||
l2_pm_cycle_overflow_count++;
|
||||
l2_pm_reset_cycle_overflow();
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
void l2_pm_stop_all(void)
|
||||
{
|
||||
WCP15_L2PMCNTENCLR(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void l2_pm_reset_all(void)
|
||||
{
|
||||
WCP15_L2PMCR(0xF);
|
||||
WCP15_L2PMOVSR(PM_L2_ALL_ENABLE); /* overflow clear */
|
||||
}
|
||||
|
||||
void l2_pm_start_all(void)
|
||||
{
|
||||
WCP15_L2PMCNTENSET(PM_L2_ALL_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION l2_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 l2_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;
|
||||
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
irqid = INT_ARM11_PM;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_MSM7X30
|
||||
irqid = INT_ARM11_PM;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_MSM8X60
|
||||
irqid = CPU_SICCPUXPERFMONIRPTREQ;
|
||||
#endif
|
||||
RCP15_L2PMCR(reg);
|
||||
imp = (reg>>24) & 0xFF;
|
||||
id = (reg>>16) & 0xFF;
|
||||
pm_l2_max_events = num = (reg>>11) & 0xFF;
|
||||
PRINT("V7 MP L2SCU Performance 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_L2PMCR(enables);
|
||||
WCP15_L2PMCR(enables | PM_L2_GLOBAL_ENABLE | PM_L2_EVENT_RESET |
|
||||
PM_L2_CYCLE_RESET | PM_L2_CLKDIV);
|
||||
|
||||
/*
|
||||
* Enable access from user space
|
||||
*/
|
||||
|
||||
/*
|
||||
* Install interrupt handler and the enable the interrupts
|
||||
*/
|
||||
l2_pm_reset_cycle_overflow();
|
||||
l2_pm_reset_overflow(0);
|
||||
l2_pm_reset_overflow(1);
|
||||
l2_pm_reset_overflow(2);
|
||||
l2_pm_reset_overflow(3);
|
||||
l2_pm_reset_overflow(4);
|
||||
|
||||
if (0 != request_irq(irqid, l2_pm_isr, 0, "l2perfmon", 0))
|
||||
printk(KERN_ERR "%s:%d request_irq returned error\n",
|
||||
__FILE__, __LINE__);
|
||||
WCP15_L2PMINTENSET(PM_L2_ALL_ENABLE);
|
||||
/*
|
||||
* Enable the cycle counter. Default, count 1:1 no divisor.
|
||||
*/
|
||||
l2_pm_enable_cycle_counter();
|
||||
|
||||
}
|
||||
|
||||
void l2_pm_free_irq(void)
|
||||
{
|
||||
free_irq(irqid, 0);
|
||||
}
|
||||
|
||||
void l2_pm_deinitialize(void)
|
||||
{
|
||||
unsigned long enables = 0;
|
||||
RCP15_L2PMCR(enables);
|
||||
WCP15_L2PMCR(enables & ~PM_L2_GLOBAL_ENABLE);
|
||||
}
|
||||
|
||||
1019
arch/arm/perfmon/perf-v7.c
Normal file
1019
arch/arm/perfmon/perf-v7.c
Normal file
File diff suppressed because it is too large
Load Diff
101
arch/arm/perfmon/perf.h
Normal file
101
arch/arm/perfmon/perf.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Code Aurora nor
|
||||
* the names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
perf.h
|
||||
|
||||
DESCRIPTION: Reads and writes the performance monitoring registers in the ARM
|
||||
by using the MRC and MCR instructions.
|
||||
*/
|
||||
#ifndef PERF_H
|
||||
#define PERF_H
|
||||
extern unsigned long perf_get_cycles(void);
|
||||
extern void perf_set_count1(unsigned long val);
|
||||
extern void perf_set_count0(unsigned long val);
|
||||
extern unsigned long perf_get_count1(void);
|
||||
extern unsigned long perf_get_count0(void);
|
||||
extern unsigned long perf_get_ctrl(void);
|
||||
extern void perf_set_ctrl(void);
|
||||
extern void perf_set_ctrl_with(unsigned long v);
|
||||
extern void perf_enable_counting(void);
|
||||
extern void perf_disable_counting(void);
|
||||
extern void perf_set_divider(int d);
|
||||
extern unsigned long perf_get_overflow(void);
|
||||
extern void perf_clear_overflow(unsigned long bit);
|
||||
extern void perf_export_event(unsigned long bit);
|
||||
extern void perf_reset_counts(void);
|
||||
extern int perf_set_event(unsigned long index, unsigned long val);
|
||||
extern unsigned long perf_get_count(unsigned long index);
|
||||
extern void perf_set_cycles(unsigned long c);
|
||||
|
||||
extern void pm_stop_all(void);
|
||||
extern void l2_pm_stop_all(void);
|
||||
extern void pm_start_all(void);
|
||||
extern void l2_pm_start_all(void);
|
||||
extern void pm_reset_all(void);
|
||||
extern void l2_pm_reset_all(void);
|
||||
extern void pm_set_event(unsigned long monitorIndex, unsigned long eventIndex);
|
||||
extern void l2_pm_set_event(unsigned long monitorIndex,
|
||||
unsigned long eventIndex);
|
||||
extern unsigned long pm_get_count(unsigned long monitorIndex);
|
||||
extern unsigned long l2_pm_get_count(unsigned long monitorIndex);
|
||||
extern unsigned long pm_get_cycle_count(void);
|
||||
extern unsigned long l2_pm_get_cycle_count(void);
|
||||
extern char *pm_find_event_name(unsigned long index);
|
||||
extern void pm_set_local_iu(unsigned long events);
|
||||
extern void pm_set_local_xu(unsigned long events);
|
||||
extern void pm_set_local_su(unsigned long events);
|
||||
extern void pm_set_local_l2(unsigned long events);
|
||||
extern void pm_set_local_vu(unsigned long events);
|
||||
extern void pm_set_local_bu(unsigned long events);
|
||||
extern void pm_set_local_cb(unsigned long events);
|
||||
extern void pm_set_local_mp(unsigned long events);
|
||||
extern void pm_set_local_sp(unsigned long events);
|
||||
extern void pm_set_local_scu(unsigned long events);
|
||||
extern void pm_initialize(void);
|
||||
extern void pm_deinitialize(void);
|
||||
extern void l2_pm_initialize(void);
|
||||
extern void l2_pm_deinitialize(void);
|
||||
extern void pm_free_irq(void);
|
||||
extern void l2_pm_free_irq(void);
|
||||
|
||||
extern int per_process_perf_init(void);
|
||||
extern void per_process_perf_exit(void);
|
||||
int per_process_read(char *page, char **start, off_t off, int count,
|
||||
int *eof, void *data);
|
||||
int per_process_write_hex(struct file *file, const char *buff,
|
||||
unsigned long cnt, void *data);
|
||||
int per_process_read_decimal(char *page, char **start, off_t off, int count,
|
||||
int *eof, void *data);
|
||||
int per_process_write_dec(struct file *file, const char *buff,
|
||||
unsigned long cnt, void *data);
|
||||
void perfmon_register_callback(void);
|
||||
void _per_process_switch(unsigned long oldPid, unsigned long newPid);
|
||||
extern unsigned int pp_loaded;
|
||||
extern atomic_t pm_op_lock;
|
||||
#endif /*PERF_H*/
|
||||
Reference in New Issue
Block a user