Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
1
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
1618fdd
Documentation
arch
alpha
arm
boot
common
configs
include
kernel
lib
mach-aaec2000
mach-at91
mach-bcmring
mach-clps711x
mach-davinci
mach-dove
mach-ebsa110
mach-ep93xx
mach-footbridge
mach-gemini
mach-h720x
mach-integrator
mach-iop13xx
mach-iop32x
mach-iop33x
mach-ixp2000
mach-ixp23xx
mach-ixp4xx
mach-kirkwood
mach-ks8695
mach-l7200
mach-lh7a40x
mach-loki
mach-mmp
mach-msm
mach-mv78xx0
mach-mx1
mach-mx2
mach-mx25
mach-mx3
mach-mxc91231
mach-netx
mach-nomadik
mach-ns9xxx
mach-omap1
mach-omap2
mach-orion5x
mach-pnx4008
mach-pxa
mach-realview
mach-rpc
mach-s3c2400
mach-s3c2410
mach-s3c2412
mach-s3c2440
mach-s3c2442
mach-s3c2443
mach-s3c24a0
mach-s3c6400
mach-s3c6410
mach-s5pc100
mach-sa1100
mach-shark
mach-stmp378x
mach-stmp37xx
mach-u300
mach-ux500
mach-versatile
mach-w90x900
mm
nwfpe
oprofile
Makefile
backtrace.c
common.c
op_arm_model.h
op_counter.h
op_model_arm11_core.c
op_model_arm11_core.h
op_model_mpcore.c
op_model_mpcore.h
op_model_v6.c
op_model_v7.c
op_model_v7.h
op_model_xscale.c
plat-iop
plat-mxc
plat-nomadik
plat-omap
plat-orion
plat-pxa
plat-s3c
plat-s3c24xx
plat-s3c64xx
plat-s5pc1xx
plat-samsung
plat-stmp3xxx
tools
vfp
Kconfig
Kconfig-nommu
Kconfig.debug
Makefile
avr32
blackfin
cris
frv
h8300
ia64
m32r
m68k
m68knommu
microblaze
mips
mn10300
parisc
powerpc
s390
score
sh
sparc
um
x86
xtensa
.gitignore
Kconfig
block
crypto
drivers
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
arch
/
arm
/
oprofile
/
op_model_mpcore.c
Copy path
Blame
Blame
Latest commit
History
History
306 lines (262 loc) · 6.76 KB
Breadcrumbs
linux
/
arch
/
arm
/
oprofile
/
op_model_mpcore.c
Top
File metadata and controls
Code
Blame
306 lines (262 loc) · 6.76 KB
Raw
/** * @file op_model_mpcore.c * MPCORE Event Monitor Driver * @remark Copyright 2004 ARM SMP Development Team * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com> * @remark Copyright 2000-2004 MontaVista Software Inc * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com> * @remark Copyright 2004 Intel Corporation * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk> * @remark Copyright 2004 Oprofile Authors * * @remark Read the file COPYING * * @author Zwane Mwaikambo * * Counters: * 0: PMN0 on CPU0, per-cpu configurable event counter * 1: PMN1 on CPU0, per-cpu configurable event counter * 2: CCNT on CPU0 * 3: PMN0 on CPU1 * 4: PMN1 on CPU1 * 5: CCNT on CPU1 * 6: PMN0 on CPU1 * 7: PMN1 on CPU1 * 8: CCNT on CPU1 * 9: PMN0 on CPU1 * 10: PMN1 on CPU1 * 11: CCNT on CPU1 * 12-19: configurable SCU event counters */ /* #define DEBUG */ #include <linux/types.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/sched.h> #include <linux/oprofile.h> #include <linux/interrupt.h> #include <linux/smp.h> #include <linux/io.h> #include <asm/irq.h> #include <asm/mach/irq.h> #include <mach/hardware.h> #include <mach/board-eb.h> #include <asm/system.h> #include <asm/pmu.h> #include "op_counter.h" #include "op_arm_model.h" #include "op_model_arm11_core.h" #include "op_model_mpcore.h" /* * MPCore SCU event monitor support */ #define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_EB11MP_SCU_BASE + 0x10) /* * Bitmask of used SCU counters */ static unsigned int scu_em_used; static const struct pmu_irqs *pmu_irqs; /* * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number) */ static inline void scu_reset_counter(struct eventmonitor __iomem *emc, unsigned int n) { writel(-(u32)counter_config[SCU_COUNTER(n)].count, &emc->MC[n]); } static inline void scu_set_event(struct eventmonitor __iomem *emc, unsigned int n, u32 event) { event &= 0xff; writeb(event, &emc->MCEB[n]); } /* * SCU counters' IRQ handler (one IRQ per counter => 2 IRQs per CPU) */ static irqreturn_t scu_em_interrupt(int irq, void *arg) { struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; unsigned int cnt; cnt = irq - IRQ_EB11MP_PMU_SCU0; oprofile_add_sample(get_irq_regs(), SCU_COUNTER(cnt)); scu_reset_counter(emc, cnt); /* Clear overflow flag for this counter */ writel(1 << (cnt + 16), &emc->PMCR); return IRQ_HANDLED; } /* Configure just the SCU counters that the user has requested */ static void scu_setup(void) { struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; unsigned int i; scu_em_used = 0; for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (counter_config[SCU_COUNTER(i)].enabled && counter_config[SCU_COUNTER(i)].event) { scu_set_event(emc, i, 0); /* disable counter for now */ scu_em_used |= 1 << i; } } } static int scu_start(void) { struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; unsigned int temp, i; unsigned long event; int ret = 0; /* * request the SCU counter interrupts that we need */ for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) { ret = request_irq(IRQ_EB11MP_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED, "SCU PMU", NULL); if (ret) { printk(KERN_ERR "oprofile: unable to request IRQ%u for SCU Event Monitor\n", IRQ_EB11MP_PMU_SCU0 + i); goto err_free_scu; } } } /* * clear overflow and enable interrupt for all used counters */ temp = readl(&emc->PMCR); for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) { scu_reset_counter(emc, i); event = counter_config[SCU_COUNTER(i)].event; scu_set_event(emc, i, event); /* clear overflow/interrupt */ temp |= 1 << (i + 16); /* enable interrupt*/ temp |= 1 << (i + 8); } } /* Enable all 8 counters */ temp |= PMCR_E; writel(temp, &emc->PMCR); return 0; err_free_scu: while (i--) free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL); return ret; } static void scu_stop(void) { struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; unsigned int temp, i; /* Disable counter interrupts */ /* Don't disable all 8 counters (with the E bit) as they may be in use */ temp = readl(&emc->PMCR); for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) temp &= ~(1 << (i + 8)); } writel(temp, &emc->PMCR); /* Free counter interrupts and reset counters */ for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) { scu_reset_counter(emc, i); free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL); } } } struct em_function_data { int (*fn)(void); int ret; }; static void em_func(void *data) { struct em_function_data *d = data; int ret = d->fn(); if (ret) d->ret = ret; } static int em_call_function(int (*fn)(void)) { struct em_function_data data; data.fn = fn; data.ret = 0; preempt_disable(); smp_call_function(em_func, &data, 1); em_func(&data); preempt_enable(); return data.ret; } /* * Glue to stick the individual ARM11 PMUs and the SCU * into the oprofile framework. */ static int em_setup_ctrs(void) { int ret; /* Configure CPU counters by cross-calling to the other CPUs */ ret = em_call_function(arm11_setup_pmu); if (ret == 0) scu_setup(); return 0; } static int em_start(void) { int ret; pmu_irqs = reserve_pmu(); if (IS_ERR(pmu_irqs)) { ret = PTR_ERR(pmu_irqs); goto out; } ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); if (ret == 0) { em_call_function(arm11_start_pmu); ret = scu_start(); if (ret) { arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); } else { release_pmu(pmu_irqs); pmu_irqs = NULL; } } out: return ret; } static void em_stop(void) { em_call_function(arm11_stop_pmu); arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); scu_stop(); release_pmu(pmu_irqs); } /* * Why isn't there a function to route an IRQ to a specific CPU in * genirq? */ static void em_route_irq(int irq, unsigned int cpu) { struct irq_desc *desc = irq_desc + irq; const struct cpumask *mask = cpumask_of(cpu); spin_lock_irq(&desc->lock); cpumask_copy(desc->affinity, mask); desc->chip->set_affinity(irq, mask); spin_unlock_irq(&desc->lock); } static int em_setup(void) { /* * Send SCU PMU interrupts to the "owner" CPU. */ em_route_irq(IRQ_EB11MP_PMU_SCU0, 0); em_route_irq(IRQ_EB11MP_PMU_SCU1, 0); em_route_irq(IRQ_EB11MP_PMU_SCU2, 1); em_route_irq(IRQ_EB11MP_PMU_SCU3, 1); em_route_irq(IRQ_EB11MP_PMU_SCU4, 2); em_route_irq(IRQ_EB11MP_PMU_SCU5, 2); em_route_irq(IRQ_EB11MP_PMU_SCU6, 3); em_route_irq(IRQ_EB11MP_PMU_SCU7, 3); return init_pmu(); } struct op_arm_model_spec op_mpcore_spec = { .init = em_setup, .num_counters = MPCORE_NUM_COUNTERS, .setup_ctrs = em_setup_ctrs, .start = em_start, .stop = em_stop, .name = "arm/mpcore", };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
You can’t perform that action at this time.