diff options
Diffstat (limited to 'arch/mips/oprofile/op_model_loongson2.c')
-rw-r--r-- | arch/mips/oprofile/op_model_loongson2.c | 60 |
1 files changed, 21 insertions, 39 deletions
diff --git a/arch/mips/oprofile/op_model_loongson2.c b/arch/mips/oprofile/op_model_loongson2.c index fa3bf661ae2..d0d24e04767 100644 --- a/arch/mips/oprofile/op_model_loongson2.c +++ b/arch/mips/oprofile/op_model_loongson2.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * License. See the file "COPYING" in the main directory of this archive | 9 | * License. See the file "COPYING" in the main directory of this archive |
10 | * for more details. | 10 | * for more details. |
11 | * | ||
12 | */ | 11 | */ |
13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
14 | #include <linux/oprofile.h> | 13 | #include <linux/oprofile.h> |
@@ -17,24 +16,18 @@ | |||
17 | #include <loongson.h> /* LOONGSON2_PERFCNT_IRQ */ | 16 | #include <loongson.h> /* LOONGSON2_PERFCNT_IRQ */ |
18 | #include "op_impl.h" | 17 | #include "op_impl.h" |
19 | 18 | ||
20 | /* | ||
21 | * a patch should be sent to oprofile with the loongson-specific support. | ||
22 | * otherwise, the oprofile tool will not recognize this and complain about | ||
23 | * "cpu_type 'unset' is not valid". | ||
24 | */ | ||
25 | #define LOONGSON2_CPU_TYPE "mips/loongson2" | 19 | #define LOONGSON2_CPU_TYPE "mips/loongson2" |
26 | 20 | ||
27 | #define LOONGSON2_COUNTER1_EVENT(event) ((event & 0x0f) << 5) | ||
28 | #define LOONGSON2_COUNTER2_EVENT(event) ((event & 0x0f) << 9) | ||
29 | |||
30 | #define LOONGSON2_PERFCNT_EXL (1UL << 0) | ||
31 | #define LOONGSON2_PERFCNT_KERNEL (1UL << 1) | ||
32 | #define LOONGSON2_PERFCNT_SUPERVISOR (1UL << 2) | ||
33 | #define LOONGSON2_PERFCNT_USER (1UL << 3) | ||
34 | #define LOONGSON2_PERFCNT_INT_EN (1UL << 4) | ||
35 | #define LOONGSON2_PERFCNT_OVERFLOW (1ULL << 31) | 21 | #define LOONGSON2_PERFCNT_OVERFLOW (1ULL << 31) |
36 | 22 | ||
37 | /* Loongson2 performance counter register */ | 23 | #define LOONGSON2_PERFCTRL_EXL (1UL << 0) |
24 | #define LOONGSON2_PERFCTRL_KERNEL (1UL << 1) | ||
25 | #define LOONGSON2_PERFCTRL_SUPERVISOR (1UL << 2) | ||
26 | #define LOONGSON2_PERFCTRL_USER (1UL << 3) | ||
27 | #define LOONGSON2_PERFCTRL_ENABLE (1UL << 4) | ||
28 | #define LOONGSON2_PERFCTRL_EVENT(idx, event) \ | ||
29 | (((event) & 0x0f) << ((idx) ? 9 : 5)) | ||
30 | |||
38 | #define read_c0_perfctrl() __read_64bit_c0_register($24, 0) | 31 | #define read_c0_perfctrl() __read_64bit_c0_register($24, 0) |
39 | #define write_c0_perfctrl(val) __write_64bit_c0_register($24, 0, val) | 32 | #define write_c0_perfctrl(val) __write_64bit_c0_register($24, 0, val) |
40 | #define read_c0_perfcnt() __read_64bit_c0_register($25, 0) | 33 | #define read_c0_perfcnt() __read_64bit_c0_register($25, 0) |
@@ -49,7 +42,6 @@ static struct loongson2_register_config { | |||
49 | 42 | ||
50 | static char *oprofid = "LoongsonPerf"; | 43 | static char *oprofid = "LoongsonPerf"; |
51 | static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id); | 44 | static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id); |
52 | /* Compute all of the registers in preparation for enabling profiling. */ | ||
53 | 45 | ||
54 | static void loongson2_reg_setup(struct op_counter_config *cfg) | 46 | static void loongson2_reg_setup(struct op_counter_config *cfg) |
55 | { | 47 | { |
@@ -57,41 +49,38 @@ static void loongson2_reg_setup(struct op_counter_config *cfg) | |||
57 | 49 | ||
58 | reg.reset_counter1 = 0; | 50 | reg.reset_counter1 = 0; |
59 | reg.reset_counter2 = 0; | 51 | reg.reset_counter2 = 0; |
60 | /* Compute the performance counter ctrl word. */ | 52 | |
61 | /* For now count kernel and user mode */ | 53 | /* |
54 | * Compute the performance counter ctrl word. | ||
55 | * For now, count kernel and user mode. | ||
56 | */ | ||
62 | if (cfg[0].enabled) { | 57 | if (cfg[0].enabled) { |
63 | ctrl |= LOONGSON2_COUNTER1_EVENT(cfg[0].event); | 58 | ctrl |= LOONGSON2_PERFCTRL_EVENT(0, cfg[0].event); |
64 | reg.reset_counter1 = 0x80000000ULL - cfg[0].count; | 59 | reg.reset_counter1 = 0x80000000ULL - cfg[0].count; |
65 | } | 60 | } |
66 | 61 | ||
67 | if (cfg[1].enabled) { | 62 | if (cfg[1].enabled) { |
68 | ctrl |= LOONGSON2_COUNTER2_EVENT(cfg[1].event); | 63 | ctrl |= LOONGSON2_PERFCTRL_EVENT(1, cfg[1].event); |
69 | reg.reset_counter2 = (0x80000000ULL - cfg[1].count); | 64 | reg.reset_counter2 = 0x80000000ULL - cfg[1].count; |
70 | } | 65 | } |
71 | 66 | ||
72 | if (cfg[0].enabled || cfg[1].enabled) { | 67 | if (cfg[0].enabled || cfg[1].enabled) { |
73 | ctrl |= LOONGSON2_PERFCNT_EXL | LOONGSON2_PERFCNT_INT_EN; | 68 | ctrl |= LOONGSON2_PERFCTRL_EXL | LOONGSON2_PERFCTRL_ENABLE; |
74 | if (cfg[0].kernel || cfg[1].kernel) | 69 | if (cfg[0].kernel || cfg[1].kernel) |
75 | ctrl |= LOONGSON2_PERFCNT_KERNEL; | 70 | ctrl |= LOONGSON2_PERFCTRL_KERNEL; |
76 | if (cfg[0].user || cfg[1].user) | 71 | if (cfg[0].user || cfg[1].user) |
77 | ctrl |= LOONGSON2_PERFCNT_USER; | 72 | ctrl |= LOONGSON2_PERFCTRL_USER; |
78 | } | 73 | } |
79 | 74 | ||
80 | reg.ctrl = ctrl; | 75 | reg.ctrl = ctrl; |
81 | 76 | ||
82 | reg.cnt1_enabled = cfg[0].enabled; | 77 | reg.cnt1_enabled = cfg[0].enabled; |
83 | reg.cnt2_enabled = cfg[1].enabled; | 78 | reg.cnt2_enabled = cfg[1].enabled; |
84 | |||
85 | } | 79 | } |
86 | 80 | ||
87 | /* Program all of the registers in preparation for enabling profiling. */ | ||
88 | |||
89 | static void loongson2_cpu_setup(void *args) | 81 | static void loongson2_cpu_setup(void *args) |
90 | { | 82 | { |
91 | uint64_t perfcount; | 83 | write_c0_perfcnt((reg.reset_counter2 << 32) | reg.reset_counter1); |
92 | |||
93 | perfcount = (reg.reset_counter2 << 32) | reg.reset_counter1; | ||
94 | write_c0_perfcnt(perfcount); | ||
95 | } | 84 | } |
96 | 85 | ||
97 | static void loongson2_cpu_start(void *args) | 86 | static void loongson2_cpu_start(void *args) |
@@ -114,15 +103,8 @@ static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id) | |||
114 | struct pt_regs *regs = get_irq_regs(); | 103 | struct pt_regs *regs = get_irq_regs(); |
115 | int enabled; | 104 | int enabled; |
116 | 105 | ||
117 | /* | ||
118 | * LOONGSON2 defines two 32-bit performance counters. | ||
119 | * To avoid a race updating the registers we need to stop the counters | ||
120 | * while we're messing with | ||
121 | * them ... | ||
122 | */ | ||
123 | |||
124 | /* Check whether the irq belongs to me */ | 106 | /* Check whether the irq belongs to me */ |
125 | enabled = read_c0_perfctrl() & LOONGSON2_PERFCNT_INT_EN; | 107 | enabled = read_c0_perfctrl() & LOONGSON2_PERFCTRL_ENABLE; |
126 | if (!enabled) | 108 | if (!enabled) |
127 | return IRQ_NONE; | 109 | return IRQ_NONE; |
128 | enabled = reg.cnt1_enabled | reg.cnt2_enabled; | 110 | enabled = reg.cnt1_enabled | reg.cnt2_enabled; |