diff options
Diffstat (limited to 'arch/mips/oprofile')
| -rw-r--r-- | arch/mips/oprofile/Makefile | 4 | ||||
| -rw-r--r-- | arch/mips/oprofile/common.c | 40 | ||||
| -rw-r--r-- | arch/mips/oprofile/op_model_loongson2.c | 10 | ||||
| -rw-r--r-- | arch/mips/oprofile/op_model_mipsxx.c | 108 | ||||
| -rw-r--r-- | arch/mips/oprofile/op_model_rm9000.c | 138 |
5 files changed, 115 insertions, 185 deletions
diff --git a/arch/mips/oprofile/Makefile b/arch/mips/oprofile/Makefile index 29f2f13eb31..9c0a6782c09 100644 --- a/arch/mips/oprofile/Makefile +++ b/arch/mips/oprofile/Makefile @@ -1,5 +1,3 @@ -ccflags-y := -Werror - obj-$(CONFIG_OPROFILE) += oprofile.o DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ @@ -14,5 +12,5 @@ oprofile-$(CONFIG_CPU_MIPS32) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_MIPS64) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_R10000) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_SB1) += op_model_mipsxx.o -oprofile-$(CONFIG_CPU_RM9000) += op_model_rm9000.o +oprofile-$(CONFIG_CPU_XLR) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_LOONGSON2) += op_model_loongson2.o diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index d1f2d4c52d4..e7473244947 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -12,11 +12,11 @@ #include <linux/oprofile.h> #include <linux/smp.h> #include <asm/cpu-info.h> +#include <asm/cpu-type.h> #include "op_impl.h" extern struct op_mips_model op_model_mipsxx_ops __weak; -extern struct op_mips_model op_model_rm9000_ops __weak; extern struct op_mips_model op_model_loongson2_ops __weak; static struct op_mips_model *model; @@ -28,13 +28,13 @@ static int op_mips_setup(void) /* Pre-compute the values to stuff in the hardware registers. */ model->reg_setup(ctr); - /* Configure the registers on all cpus. */ + /* Configure the registers on all cpus. */ on_each_cpu(model->cpu_setup, NULL, 1); - return 0; + return 0; } -static int op_mips_create_files(struct super_block *sb, struct dentry *root) +static int op_mips_create_files(struct dentry *root) { int i; @@ -43,16 +43,16 @@ static int op_mips_create_files(struct super_block *sb, struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); - - oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); - oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); - oprofilefs_create_ulong(sb, dir, "exl", &ctr[i].exl); + dir = oprofilefs_mkdir(root, buf); + + oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(dir, "event", &ctr[i].event); + oprofilefs_create_ulong(dir, "count", &ctr[i].count); + oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(dir, "user", &ctr[i].user); + oprofilefs_create_ulong(dir, "exl", &ctr[i].exl); /* Dummy. */ - oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); + oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); } return 0; @@ -78,23 +78,29 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) switch (current_cpu_type()) { case CPU_5KC: + case CPU_M14KC: + case CPU_M14KEC: case CPU_20KC: case CPU_24K: case CPU_25KF: case CPU_34K: case CPU_1004K: case CPU_74K: + case CPU_1074K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: + case CPU_P5600: + case CPU_M5150: + case CPU_LOONGSON1: case CPU_SB1: case CPU_SB1A: case CPU_R10000: case CPU_R12000: case CPU_R14000: + case CPU_XLR: lmodel = &op_model_mipsxx_ops; break; - case CPU_RM9000: - lmodel = &op_model_rm9000_ops; - break; case CPU_LOONGSON2: lmodel = &op_model_loongson2_ops; break; @@ -111,7 +117,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ops->create_files = op_mips_create_files; ops->setup = op_mips_setup; - //ops->shutdown = op_mips_shutdown; + //ops->shutdown = op_mips_shutdown; ops->start = op_mips_start; ops->stop = op_mips_stop; ops->cpu_type = lmodel->cpu_type; diff --git a/arch/mips/oprofile/op_model_loongson2.c b/arch/mips/oprofile/op_model_loongson2.c index 60d3ea60211..b249ec0bebb 100644 --- a/arch/mips/oprofile/op_model_loongson2.c +++ b/arch/mips/oprofile/op_model_loongson2.c @@ -18,13 +18,13 @@ #define LOONGSON2_CPU_TYPE "mips/loongson2" -#define LOONGSON2_PERFCNT_OVERFLOW (1ULL << 31) +#define LOONGSON2_PERFCNT_OVERFLOW (1ULL << 31) #define LOONGSON2_PERFCTRL_EXL (1UL << 0) -#define LOONGSON2_PERFCTRL_KERNEL (1UL << 1) -#define LOONGSON2_PERFCTRL_SUPERVISOR (1UL << 2) -#define LOONGSON2_PERFCTRL_USER (1UL << 3) -#define LOONGSON2_PERFCTRL_ENABLE (1UL << 4) +#define LOONGSON2_PERFCTRL_KERNEL (1UL << 1) +#define LOONGSON2_PERFCTRL_SUPERVISOR (1UL << 2) +#define LOONGSON2_PERFCTRL_USER (1UL << 3) +#define LOONGSON2_PERFCTRL_ENABLE (1UL << 4) #define LOONGSON2_PERFCTRL_EVENT(idx, event) \ (((event) & 0x0f) << ((idx) ? 9 : 5)) diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 54759f1669d..42821ae2d77 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -14,25 +14,39 @@ #include "op_impl.h" -#define M_PERFCTL_EXL (1UL << 0) -#define M_PERFCTL_KERNEL (1UL << 1) -#define M_PERFCTL_SUPERVISOR (1UL << 2) -#define M_PERFCTL_USER (1UL << 3) -#define M_PERFCTL_INTERRUPT_ENABLE (1UL << 4) +#define M_PERFCTL_EXL (1UL << 0) +#define M_PERFCTL_KERNEL (1UL << 1) +#define M_PERFCTL_SUPERVISOR (1UL << 2) +#define M_PERFCTL_USER (1UL << 3) +#define M_PERFCTL_INTERRUPT_ENABLE (1UL << 4) #define M_PERFCTL_EVENT(event) (((event) & 0x3ff) << 5) -#define M_PERFCTL_VPEID(vpe) ((vpe) << 16) +#define M_PERFCTL_VPEID(vpe) ((vpe) << 16) #define M_PERFCTL_MT_EN(filter) ((filter) << 20) -#define M_TC_EN_ALL M_PERFCTL_MT_EN(0) -#define M_TC_EN_VPE M_PERFCTL_MT_EN(1) -#define M_TC_EN_TC M_PERFCTL_MT_EN(2) -#define M_PERFCTL_TCID(tcid) ((tcid) << 22) -#define M_PERFCTL_WIDE (1UL << 30) -#define M_PERFCTL_MORE (1UL << 31) +#define M_TC_EN_ALL M_PERFCTL_MT_EN(0) +#define M_TC_EN_VPE M_PERFCTL_MT_EN(1) +#define M_TC_EN_TC M_PERFCTL_MT_EN(2) +#define M_PERFCTL_TCID(tcid) ((tcid) << 22) +#define M_PERFCTL_WIDE (1UL << 30) +#define M_PERFCTL_MORE (1UL << 31) -#define M_COUNTER_OVERFLOW (1UL << 31) +#define M_COUNTER_OVERFLOW (1UL << 31) + +/* Netlogic XLR specific, count events in all threads in a core */ +#define M_PERFCTL_COUNT_ALL_THREADS (1UL << 13) static int (*save_perf_irq)(void); +/* + * XLR has only one set of counters per core. Designate the + * first hardware thread in the core for setup and init. + * Skip CPUs with non-zero hardware thread id (4 hwt per core) + */ +#if defined(CONFIG_CPU_XLR) && defined(CONFIG_SMP) +#define oprofile_skip_cpu(c) ((cpu_logical_map(c) & 0x3) != 0) +#else +#define oprofile_skip_cpu(c) 0 +#endif + #ifdef CONFIG_MIPS_MT_SMP static int cpu_has_mipsmt_pertccounters; #define WHAT (M_TC_EN_VPE | \ @@ -129,7 +143,7 @@ static struct mipsxx_register_config { unsigned int counter[4]; } reg; -/* Compute all of the registers in preparation for enabling profiling. */ +/* Compute all of the registers in preparation for enabling profiling. */ static void mipsxx_reg_setup(struct op_counter_config *ctr) { @@ -145,23 +159,28 @@ static void mipsxx_reg_setup(struct op_counter_config *ctr) continue; reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) | - M_PERFCTL_INTERRUPT_ENABLE; + M_PERFCTL_INTERRUPT_ENABLE; if (ctr[i].kernel) reg.control[i] |= M_PERFCTL_KERNEL; if (ctr[i].user) reg.control[i] |= M_PERFCTL_USER; if (ctr[i].exl) reg.control[i] |= M_PERFCTL_EXL; + if (boot_cpu_type() == CPU_XLR) + reg.control[i] |= M_PERFCTL_COUNT_ALL_THREADS; reg.counter[i] = 0x80000000 - ctr[i].count; } } -/* Program all of the registers in preparation for enabling profiling. */ +/* Program all of the registers in preparation for enabling profiling. */ static void mipsxx_cpu_setup(void *args) { unsigned int counters = op_model_mipsxx_ops.num_counters; + if (oprofile_skip_cpu(smp_processor_id())) + return; + switch (counters) { case 4: w_c0_perfctrl3(0); @@ -183,6 +202,9 @@ static void mipsxx_cpu_start(void *args) { unsigned int counters = op_model_mipsxx_ops.num_counters; + if (oprofile_skip_cpu(smp_processor_id())) + return; + switch (counters) { case 4: w_c0_perfctrl3(WHAT | reg.control[3]); @@ -200,6 +222,9 @@ static void mipsxx_cpu_stop(void *args) { unsigned int counters = op_model_mipsxx_ops.num_counters; + if (oprofile_skip_cpu(smp_processor_id())) + return; + switch (counters) { case 4: w_c0_perfctrl3(0); @@ -298,6 +323,11 @@ static void reset_counters(void *arg) } } +static irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id) +{ + return mipsxx_perfcount_handler(); +} + static int __init mipsxx_init(void) { int counters; @@ -317,6 +347,14 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.num_counters = counters; switch (current_cpu_type()) { + case CPU_M14KC: + op_model_mipsxx_ops.cpu_type = "mips/M14Kc"; + break; + + case CPU_M14KEC: + op_model_mipsxx_ops.cpu_type = "mips/M14KEc"; + break; + case CPU_20KC: op_model_mipsxx_ops.cpu_type = "mips/20K"; break; @@ -330,20 +368,31 @@ static int __init mipsxx_init(void) break; case CPU_1004K: -#if 0 - /* FIXME: report as 34K for now */ - op_model_mipsxx_ops.cpu_type = "mips/1004K"; - break; -#endif - case CPU_34K: op_model_mipsxx_ops.cpu_type = "mips/34K"; break; + case CPU_1074K: case CPU_74K: op_model_mipsxx_ops.cpu_type = "mips/74K"; break; + case CPU_INTERAPTIV: + op_model_mipsxx_ops.cpu_type = "mips/interAptiv"; + break; + + case CPU_PROAPTIV: + op_model_mipsxx_ops.cpu_type = "mips/proAptiv"; + break; + + case CPU_P5600: + op_model_mipsxx_ops.cpu_type = "mips/P5600"; + break; + + case CPU_M5150: + op_model_mipsxx_ops.cpu_type = "mips/M5150"; + break; + case CPU_5KC: op_model_mipsxx_ops.cpu_type = "mips/5K"; break; @@ -365,6 +414,14 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.cpu_type = "mips/sb1"; break; + case CPU_LOONGSON1: + op_model_mipsxx_ops.cpu_type = "mips/loongson1"; + break; + + case CPU_XLR: + op_model_mipsxx_ops.cpu_type = "mips/xlr"; + break; + default: printk(KERN_ERR "Profiling unsupported for this CPU\n"); @@ -374,6 +431,10 @@ static int __init mipsxx_init(void) save_perf_irq = perf_irq; perf_irq = mipsxx_perfcount_handler; + if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq)) + return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int, + 0, "Perfcounter", save_perf_irq); + return 0; } @@ -381,6 +442,9 @@ static void mipsxx_exit(void) { int counters = op_model_mipsxx_ops.num_counters; + if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq)) + free_irq(cp0_perfcount_irq, save_perf_irq); + counters = counters_per_cpu_to_total(counters); on_each_cpu(reset_counters, (void *)(long)counters, 1); diff --git a/arch/mips/oprofile/op_model_rm9000.c b/arch/mips/oprofile/op_model_rm9000.c deleted file mode 100644 index 3aa81384966..00000000000 --- a/arch/mips/oprofile/op_model_rm9000.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004 by Ralf Baechle - */ -#include <linux/init.h> -#include <linux/oprofile.h> -#include <linux/interrupt.h> -#include <linux/smp.h> - -#include "op_impl.h" - -#define RM9K_COUNTER1_EVENT(event) ((event) << 0) -#define RM9K_COUNTER1_SUPERVISOR (1ULL << 7) -#define RM9K_COUNTER1_KERNEL (1ULL << 8) -#define RM9K_COUNTER1_USER (1ULL << 9) -#define RM9K_COUNTER1_ENABLE (1ULL << 10) -#define RM9K_COUNTER1_OVERFLOW (1ULL << 15) - -#define RM9K_COUNTER2_EVENT(event) ((event) << 16) -#define RM9K_COUNTER2_SUPERVISOR (1ULL << 23) -#define RM9K_COUNTER2_KERNEL (1ULL << 24) -#define RM9K_COUNTER2_USER (1ULL << 25) -#define RM9K_COUNTER2_ENABLE (1ULL << 26) -#define RM9K_COUNTER2_OVERFLOW (1ULL << 31) - -extern unsigned int rm9000_perfcount_irq; - -static struct rm9k_register_config { - unsigned int control; - unsigned int reset_counter1; - unsigned int reset_counter2; -} reg; - -/* Compute all of the registers in preparation for enabling profiling. */ - -static void rm9000_reg_setup(struct op_counter_config *ctr) -{ - unsigned int control = 0; - - /* Compute the performance counter control word. */ - /* For now count kernel and user mode */ - if (ctr[0].enabled) - control |= RM9K_COUNTER1_EVENT(ctr[0].event) | - RM9K_COUNTER1_KERNEL | - RM9K_COUNTER1_USER | - RM9K_COUNTER1_ENABLE; - if (ctr[1].enabled) - control |= RM9K_COUNTER2_EVENT(ctr[1].event) | - RM9K_COUNTER2_KERNEL | - RM9K_COUNTER2_USER | - RM9K_COUNTER2_ENABLE; - reg.control = control; - - reg.reset_counter1 = 0x80000000 - ctr[0].count; - reg.reset_counter2 = 0x80000000 - ctr[1].count; -} - -/* Program all of the registers in preparation for enabling profiling. */ - -static void rm9000_cpu_setup(void *args) -{ - uint64_t perfcount; - - perfcount = ((uint64_t) reg.reset_counter2 << 32) | reg.reset_counter1; - write_c0_perfcount(perfcount); -} - -static void rm9000_cpu_start(void *args) -{ - /* Start all counters on current CPU */ - write_c0_perfcontrol(reg.control); -} - -static void rm9000_cpu_stop(void *args) -{ - /* Stop all counters on current CPU */ - write_c0_perfcontrol(0); -} - -static irqreturn_t rm9000_perfcount_handler(int irq, void *dev_id) -{ - unsigned int control = read_c0_perfcontrol(); - struct pt_regs *regs = get_irq_regs(); - uint32_t counter1, counter2; - uint64_t counters; - - /* - * RM9000 combines two 32-bit performance counters into a single - * 64-bit coprocessor zero register. To avoid a race updating the - * registers we need to stop the counters while we're messing with - * them ... - */ - write_c0_perfcontrol(0); - - counters = read_c0_perfcount(); - counter1 = counters; - counter2 = counters >> 32; - - if (control & RM9K_COUNTER1_OVERFLOW) { - oprofile_add_sample(regs, 0); - counter1 = reg.reset_counter1; - } - if (control & RM9K_COUNTER2_OVERFLOW) { - oprofile_add_sample(regs, 1); - counter2 = reg.reset_counter2; - } - - counters = ((uint64_t)counter2 << 32) | counter1; - write_c0_perfcount(counters); - write_c0_perfcontrol(reg.control); - - return IRQ_HANDLED; -} - -static int __init rm9000_init(void) -{ - return request_irq(rm9000_perfcount_irq, rm9000_perfcount_handler, - 0, "Perfcounter", NULL); -} - -static void rm9000_exit(void) -{ - free_irq(rm9000_perfcount_irq, NULL); -} - -struct op_mips_model op_model_rm9000_ops = { - .reg_setup = rm9000_reg_setup, - .cpu_setup = rm9000_cpu_setup, - .init = rm9000_init, - .exit = rm9000_exit, - .cpu_start = rm9000_cpu_start, - .cpu_stop = rm9000_cpu_stop, - .cpu_type = "mips/rm9000", - .num_counters = 2 -}; |
