Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[ARM] oprofile: add ARM11 core support

Add basic support for the ARM11 profiling hardware. This is shared
between the ARM11 UP and ARM11 SMP oprofile support code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Russell King and committed by
Russell King
c265a762 62d0cfcb

+211 -1
+3
arch/arm/oprofile/Kconfig
··· 19 19 20 20 If unsure, say N. 21 21 22 + config OPROFILE_ARM11_CORE 23 + bool 24 + 22 25 endmenu 23 26
+1 -1
arch/arm/oprofile/Makefile
··· 8 8 9 9 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o 10 10 oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o 11 - 11 + oprofile-$(CONFIG_OPROFILE_ARM11_CORE) += op_model_arm11_core.o
+162
arch/arm/oprofile/op_model_arm11_core.c
··· 1 + /** 2 + * @file op_model_arm11_core.c 3 + * ARM11 Event Monitor Driver 4 + * @remark Copyright 2004 ARM SMP Development Team 5 + */ 6 + #include <linux/types.h> 7 + #include <linux/errno.h> 8 + #include <linux/oprofile.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/irq.h> 11 + #include <linux/smp.h> 12 + 13 + #include "op_counter.h" 14 + #include "op_arm_model.h" 15 + #include "op_model_arm11_core.h" 16 + 17 + /* 18 + * ARM11 PMU support 19 + */ 20 + static inline void arm11_write_pmnc(u32 val) 21 + { 22 + /* upper 4bits and 7, 11 are write-as-0 */ 23 + val &= 0x0ffff77f; 24 + asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val)); 25 + } 26 + 27 + static inline u32 arm11_read_pmnc(void) 28 + { 29 + u32 val; 30 + asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val)); 31 + return val; 32 + } 33 + 34 + static void arm11_reset_counter(unsigned int cnt) 35 + { 36 + u32 val = -(u32)counter_config[CPU_COUNTER(smp_processor_id(), cnt)].count; 37 + switch (cnt) { 38 + case CCNT: 39 + asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val)); 40 + break; 41 + 42 + case PMN0: 43 + asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val)); 44 + break; 45 + 46 + case PMN1: 47 + asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val)); 48 + break; 49 + } 50 + } 51 + 52 + int arm11_setup_pmu(void) 53 + { 54 + unsigned int cnt; 55 + u32 pmnc; 56 + 57 + if (arm11_read_pmnc() & PMCR_E) { 58 + printk(KERN_ERR "oprofile: CPU%u PMU still enabled when setup new event counter.\n", smp_processor_id()); 59 + return -EBUSY; 60 + } 61 + 62 + /* initialize PMNC, reset overflow, D bit, C bit and P bit. */ 63 + arm11_write_pmnc(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT | 64 + PMCR_C | PMCR_P); 65 + 66 + for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) { 67 + unsigned long event; 68 + 69 + if (!counter_config[CPU_COUNTER(smp_processor_id(), cnt)].enabled) 70 + continue; 71 + 72 + event = counter_config[CPU_COUNTER(smp_processor_id(), cnt)].event & 255; 73 + 74 + /* 75 + * Set event (if destined for PMNx counters) 76 + */ 77 + if (cnt == PMN0) { 78 + pmnc |= event << 20; 79 + } else if (cnt == PMN1) { 80 + pmnc |= event << 12; 81 + } 82 + 83 + /* 84 + * We don't need to set the event if it's a cycle count 85 + * Enable interrupt for this counter 86 + */ 87 + pmnc |= PMCR_IEN_PMN0 << cnt; 88 + arm11_reset_counter(cnt); 89 + } 90 + arm11_write_pmnc(pmnc); 91 + 92 + return 0; 93 + } 94 + 95 + int arm11_start_pmu(void) 96 + { 97 + arm11_write_pmnc(arm11_read_pmnc() | PMCR_E); 98 + return 0; 99 + } 100 + 101 + int arm11_stop_pmu(void) 102 + { 103 + unsigned int cnt; 104 + 105 + arm11_write_pmnc(arm11_read_pmnc() & ~PMCR_E); 106 + 107 + for (cnt = PMN0; cnt <= CCNT; cnt++) 108 + arm11_reset_counter(cnt); 109 + 110 + return 0; 111 + } 112 + 113 + /* 114 + * CPU counters' IRQ handler (one IRQ per CPU) 115 + */ 116 + static irqreturn_t arm11_pmu_interrupt(int irq, void *arg) 117 + { 118 + struct pt_regs *regs = get_irq_regs(); 119 + unsigned int cnt; 120 + u32 pmnc; 121 + 122 + pmnc = arm11_read_pmnc(); 123 + 124 + for (cnt = PMN0; cnt <= CCNT; cnt++) { 125 + if ((pmnc & (PMCR_OFL_PMN0 << cnt)) && (pmnc & (PMCR_IEN_PMN0 << cnt))) { 126 + arm11_reset_counter(cnt); 127 + oprofile_add_sample(regs, CPU_COUNTER(smp_processor_id(), cnt)); 128 + } 129 + } 130 + /* Clear counter flag(s) */ 131 + arm11_write_pmnc(pmnc); 132 + return IRQ_HANDLED; 133 + } 134 + 135 + int arm11_request_interrupts(int *irqs, int nr) 136 + { 137 + unsigned int i; 138 + int ret = 0; 139 + 140 + for(i = 0; i < nr; i++) { 141 + ret = request_irq(irqs[i], arm11_pmu_interrupt, IRQF_DISABLED, "CP15 PMU", NULL); 142 + if (ret != 0) { 143 + printk(KERN_ERR "oprofile: unable to request IRQ%u for MPCORE-EM\n", 144 + irqs[i]); 145 + break; 146 + } 147 + } 148 + 149 + if (i != nr) 150 + while (i-- != 0) 151 + free_irq(irqs[i], NULL); 152 + 153 + return ret; 154 + } 155 + 156 + void arm11_release_interrupts(int *irqs, int nr) 157 + { 158 + unsigned int i; 159 + 160 + for (i = 0; i < nr; i++) 161 + free_irq(irqs[i], NULL); 162 + }
+45
arch/arm/oprofile/op_model_arm11_core.h
··· 1 + /** 2 + * @file op_model_arm11_core.h 3 + * ARM11 Event Monitor Driver 4 + * @remark Copyright 2004 ARM SMP Development Team 5 + * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com> 6 + * @remark Copyright 2000-2004 MontaVista Software Inc 7 + * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com> 8 + * @remark Copyright 2004 Intel Corporation 9 + * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk> 10 + * @remark Copyright 2004 Oprofile Authors 11 + * 12 + * @remark Read the file COPYING 13 + * 14 + * @author Zwane Mwaikambo 15 + */ 16 + #ifndef OP_MODEL_ARM11_CORE_H 17 + #define OP_MODEL_ARM11_CORE_H 18 + 19 + /* 20 + * Per-CPU PMCR 21 + */ 22 + #define PMCR_E (1 << 0) /* Enable */ 23 + #define PMCR_P (1 << 1) /* Count reset */ 24 + #define PMCR_C (1 << 2) /* Cycle counter reset */ 25 + #define PMCR_D (1 << 3) /* Cycle counter counts every 64th cpu cycle */ 26 + #define PMCR_IEN_PMN0 (1 << 4) /* Interrupt enable count reg 0 */ 27 + #define PMCR_IEN_PMN1 (1 << 5) /* Interrupt enable count reg 1 */ 28 + #define PMCR_IEN_CCNT (1 << 6) /* Interrupt enable cycle counter */ 29 + #define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */ 30 + #define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */ 31 + #define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */ 32 + 33 + #define PMN0 0 34 + #define PMN1 1 35 + #define CCNT 2 36 + 37 + #define CPU_COUNTER(cpu, counter) ((cpu) * 3 + (counter)) 38 + 39 + int arm11_setup_pmu(void); 40 + int arm11_start_pmu(void); 41 + int arm11_stop_pmu(void); 42 + int arm11_request_interrupts(int *, int); 43 + void arm11_release_interrupts(int *, int); 44 + 45 + #endif