/** * @file op_model_v6-7.c * ARM V6 and V7 Performance Monitor models * * Based on op_model_xscale.c * * @remark Copyright 2007 ARM SMP Development Team * @remark Copyright 2000-2004 Deepak Saxena * @remark Copyright 2000-2004 MontaVista Software Inc * @remark Copyright 2004 Dave Jiang * @remark Copyright 2004 Intel Corporation * @remark Copyright 2004 Zwane Mwaikambo * @remark Copyright 2004 OProfile Authors * * @remark Read the file COPYING * * @author Tony Lindgren */ #include #include #include #include #include #include #include #include #include #include "op_counter.h" #include "op_arm_model.h" #include "op_arm11.h" #include "op_v7.h" #include "op_scu.h" #include "op_l2x0.h" static int arm11_irqs[] = { [0] = IRQ_PMU_CPU0, #ifdef CONFIG_SMP #if CONFIG_NR_CPUS>=2 [1] = IRQ_PMU_CPU1, #endif #if CONFIG_NR_CPUS>=3 [2] = IRQ_PMU_CPU2, #endif #if CONFIG_NR_CPUS>=4 [3] = IRQ_PMU_CPU3 #endif #endif }; static int v7_irqs[] = { [0] = IRQ_PMU_CPU0, #ifdef CONFIG_SMP #if CONFIG_NR_CPUS>=2 [1] = IRQ_PMU_CPU1, #endif #if CONFIG_NR_CPUS>=3 [2] = IRQ_PMU_CPU2, #endif #if CONFIG_NR_CPUS>=4 [3] = IRQ_PMU_CPU3 #endif #endif }; /* * Functions and struct to enable calling a function on all CPUs in an SMP * system. This works on a non-SMP system too (i.e. just calls the function!) */ 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; get_cpu(); if (is_smp()) smp_call_function(em_func, &data, 1); em_func(&data); put_cpu(); return data.ret; } /* * Why isn't there a function to route an IRQ to a specific CPU in * genirq? */ #ifdef CONFIG_SMP void em_route_irq(int irq, unsigned int cpu) { irq_set_affinity(irq, get_cpu_mask(cpu)); } #endif /* * ARM V6 Oprofile callbacks */ static void v6_stop(void) { em_call_function(arm11_stop_pmu); arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); if (is_smp()) scu_stop(); if (have_l2x0()) l2x0_ec_stop(); } static int v6_start(void) { int ret; #ifdef CONFIG_SMP unsigned i; if (is_smp()) { /* * Send SCU and CP15 PMU interrupts to the "owner" CPU. */ for (i=0; i