diff options
Diffstat (limited to 'arch/sparc/kernel/pcr.c')
-rw-r--r-- | arch/sparc/kernel/pcr.c | 172 |
1 files changed, 147 insertions, 25 deletions
diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index 0ce0dd2332aa..269af58497aa 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c | |||
@@ -13,23 +13,14 @@ | |||
13 | #include <asm/pil.h> | 13 | #include <asm/pil.h> |
14 | #include <asm/pcr.h> | 14 | #include <asm/pcr.h> |
15 | #include <asm/nmi.h> | 15 | #include <asm/nmi.h> |
16 | #include <asm/asi.h> | ||
16 | #include <asm/spitfire.h> | 17 | #include <asm/spitfire.h> |
17 | #include <asm/perfctr.h> | ||
18 | 18 | ||
19 | /* This code is shared between various users of the performance | 19 | /* This code is shared between various users of the performance |
20 | * counters. Users will be oprofile, pseudo-NMI watchdog, and the | 20 | * counters. Users will be oprofile, pseudo-NMI watchdog, and the |
21 | * perf_event support layer. | 21 | * perf_event support layer. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define PCR_SUN4U_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE) | ||
25 | #define PCR_N2_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \ | ||
26 | PCR_N2_TOE_OV1 | \ | ||
27 | (2 << PCR_N2_SL1_SHIFT) | \ | ||
28 | (0xff << PCR_N2_MASK1_SHIFT)) | ||
29 | |||
30 | u64 pcr_enable; | ||
31 | unsigned int picl_shift; | ||
32 | |||
33 | /* Performance counter interrupts run unmasked at PIL level 15. | 24 | /* Performance counter interrupts run unmasked at PIL level 15. |
34 | * Therefore we can't do things like wakeups and other work | 25 | * Therefore we can't do things like wakeups and other work |
35 | * that expects IRQ disabling to be adhered to in locking etc. | 26 | * that expects IRQ disabling to be adhered to in locking etc. |
@@ -60,39 +51,144 @@ void arch_irq_work_raise(void) | |||
60 | const struct pcr_ops *pcr_ops; | 51 | const struct pcr_ops *pcr_ops; |
61 | EXPORT_SYMBOL_GPL(pcr_ops); | 52 | EXPORT_SYMBOL_GPL(pcr_ops); |
62 | 53 | ||
63 | static u64 direct_pcr_read(void) | 54 | static u64 direct_pcr_read(unsigned long reg_num) |
64 | { | 55 | { |
65 | u64 val; | 56 | u64 val; |
66 | 57 | ||
67 | read_pcr(val); | 58 | WARN_ON_ONCE(reg_num != 0); |
59 | __asm__ __volatile__("rd %%pcr, %0" : "=r" (val)); | ||
68 | return val; | 60 | return val; |
69 | } | 61 | } |
70 | 62 | ||
71 | static void direct_pcr_write(u64 val) | 63 | static void direct_pcr_write(unsigned long reg_num, u64 val) |
64 | { | ||
65 | WARN_ON_ONCE(reg_num != 0); | ||
66 | __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (val)); | ||
67 | } | ||
68 | |||
69 | static u64 direct_pic_read(unsigned long reg_num) | ||
72 | { | 70 | { |
73 | write_pcr(val); | 71 | u64 val; |
72 | |||
73 | WARN_ON_ONCE(reg_num != 0); | ||
74 | __asm__ __volatile__("rd %%pic, %0" : "=r" (val)); | ||
75 | return val; | ||
76 | } | ||
77 | |||
78 | static void direct_pic_write(unsigned long reg_num, u64 val) | ||
79 | { | ||
80 | WARN_ON_ONCE(reg_num != 0); | ||
81 | |||
82 | /* Blackbird errata workaround. See commentary in | ||
83 | * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt() | ||
84 | * for more information. | ||
85 | */ | ||
86 | __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" | ||
87 | " nop\n\t" | ||
88 | ".align 64\n" | ||
89 | "99:wr %0, 0x0, %%pic\n\t" | ||
90 | "rd %%pic, %%g0" : : "r" (val)); | ||
91 | } | ||
92 | |||
93 | static u64 direct_picl_value(unsigned int nmi_hz) | ||
94 | { | ||
95 | u32 delta = local_cpu_data().clock_tick / nmi_hz; | ||
96 | |||
97 | return ((u64)((0 - delta) & 0xffffffff)) << 32; | ||
74 | } | 98 | } |
75 | 99 | ||
76 | static const struct pcr_ops direct_pcr_ops = { | 100 | static const struct pcr_ops direct_pcr_ops = { |
77 | .read = direct_pcr_read, | 101 | .read_pcr = direct_pcr_read, |
78 | .write = direct_pcr_write, | 102 | .write_pcr = direct_pcr_write, |
103 | .read_pic = direct_pic_read, | ||
104 | .write_pic = direct_pic_write, | ||
105 | .nmi_picl_value = direct_picl_value, | ||
106 | .pcr_nmi_enable = (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE), | ||
107 | .pcr_nmi_disable = PCR_PIC_PRIV, | ||
79 | }; | 108 | }; |
80 | 109 | ||
81 | static void n2_pcr_write(u64 val) | 110 | static void n2_pcr_write(unsigned long reg_num, u64 val) |
82 | { | 111 | { |
83 | unsigned long ret; | 112 | unsigned long ret; |
84 | 113 | ||
114 | WARN_ON_ONCE(reg_num != 0); | ||
85 | if (val & PCR_N2_HTRACE) { | 115 | if (val & PCR_N2_HTRACE) { |
86 | ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val); | 116 | ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val); |
87 | if (ret != HV_EOK) | 117 | if (ret != HV_EOK) |
88 | write_pcr(val); | 118 | direct_pcr_write(reg_num, val); |
89 | } else | 119 | } else |
90 | write_pcr(val); | 120 | direct_pcr_write(reg_num, val); |
121 | } | ||
122 | |||
123 | static u64 n2_picl_value(unsigned int nmi_hz) | ||
124 | { | ||
125 | u32 delta = local_cpu_data().clock_tick / (nmi_hz << 2); | ||
126 | |||
127 | return ((u64)((0 - delta) & 0xffffffff)) << 32; | ||
91 | } | 128 | } |
92 | 129 | ||
93 | static const struct pcr_ops n2_pcr_ops = { | 130 | static const struct pcr_ops n2_pcr_ops = { |
94 | .read = direct_pcr_read, | 131 | .read_pcr = direct_pcr_read, |
95 | .write = n2_pcr_write, | 132 | .write_pcr = n2_pcr_write, |
133 | .read_pic = direct_pic_read, | ||
134 | .write_pic = direct_pic_write, | ||
135 | .nmi_picl_value = n2_picl_value, | ||
136 | .pcr_nmi_enable = (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | | ||
137 | PCR_N2_TOE_OV1 | | ||
138 | (2 << PCR_N2_SL1_SHIFT) | | ||
139 | (0xff << PCR_N2_MASK1_SHIFT)), | ||
140 | .pcr_nmi_disable = PCR_PIC_PRIV, | ||
141 | }; | ||
142 | |||
143 | static u64 n4_pcr_read(unsigned long reg_num) | ||
144 | { | ||
145 | unsigned long val; | ||
146 | |||
147 | (void) sun4v_vt_get_perfreg(reg_num, &val); | ||
148 | |||
149 | return val; | ||
150 | } | ||
151 | |||
152 | static void n4_pcr_write(unsigned long reg_num, u64 val) | ||
153 | { | ||
154 | (void) sun4v_vt_set_perfreg(reg_num, val); | ||
155 | } | ||
156 | |||
157 | static u64 n4_pic_read(unsigned long reg_num) | ||
158 | { | ||
159 | unsigned long val; | ||
160 | |||
161 | __asm__ __volatile__("ldxa [%1] %2, %0" | ||
162 | : "=r" (val) | ||
163 | : "r" (reg_num * 0x8UL), "i" (ASI_PIC)); | ||
164 | |||
165 | return val; | ||
166 | } | ||
167 | |||
168 | static void n4_pic_write(unsigned long reg_num, u64 val) | ||
169 | { | ||
170 | __asm__ __volatile__("stxa %0, [%1] %2" | ||
171 | : /* no outputs */ | ||
172 | : "r" (val), "r" (reg_num * 0x8UL), "i" (ASI_PIC)); | ||
173 | } | ||
174 | |||
175 | static u64 n4_picl_value(unsigned int nmi_hz) | ||
176 | { | ||
177 | u32 delta = local_cpu_data().clock_tick / (nmi_hz << 2); | ||
178 | |||
179 | return ((u64)((0 - delta) & 0xffffffff)); | ||
180 | } | ||
181 | |||
182 | static const struct pcr_ops n4_pcr_ops = { | ||
183 | .read_pcr = n4_pcr_read, | ||
184 | .write_pcr = n4_pcr_write, | ||
185 | .read_pic = n4_pic_read, | ||
186 | .write_pic = n4_pic_write, | ||
187 | .nmi_picl_value = n4_picl_value, | ||
188 | .pcr_nmi_enable = (PCR_N4_PICNPT | PCR_N4_STRACE | | ||
189 | PCR_N4_UTRACE | PCR_N4_TOE | | ||
190 | (26 << PCR_N4_SL_SHIFT)), | ||
191 | .pcr_nmi_disable = PCR_N4_PICNPT, | ||
96 | }; | 192 | }; |
97 | 193 | ||
98 | static unsigned long perf_hsvc_group; | 194 | static unsigned long perf_hsvc_group; |
@@ -115,6 +211,10 @@ static int __init register_perf_hsvc(void) | |||
115 | perf_hsvc_group = HV_GRP_KT_CPU; | 211 | perf_hsvc_group = HV_GRP_KT_CPU; |
116 | break; | 212 | break; |
117 | 213 | ||
214 | case SUN4V_CHIP_NIAGARA4: | ||
215 | perf_hsvc_group = HV_GRP_VT_CPU; | ||
216 | break; | ||
217 | |||
118 | default: | 218 | default: |
119 | return -ENODEV; | 219 | return -ENODEV; |
120 | } | 220 | } |
@@ -139,6 +239,29 @@ static void __init unregister_perf_hsvc(void) | |||
139 | sun4v_hvapi_unregister(perf_hsvc_group); | 239 | sun4v_hvapi_unregister(perf_hsvc_group); |
140 | } | 240 | } |
141 | 241 | ||
242 | static int __init setup_sun4v_pcr_ops(void) | ||
243 | { | ||
244 | int ret = 0; | ||
245 | |||
246 | switch (sun4v_chip_type) { | ||
247 | case SUN4V_CHIP_NIAGARA1: | ||
248 | case SUN4V_CHIP_NIAGARA2: | ||
249 | case SUN4V_CHIP_NIAGARA3: | ||
250 | pcr_ops = &n2_pcr_ops; | ||
251 | break; | ||
252 | |||
253 | case SUN4V_CHIP_NIAGARA4: | ||
254 | pcr_ops = &n4_pcr_ops; | ||
255 | break; | ||
256 | |||
257 | default: | ||
258 | ret = -ENODEV; | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
142 | int __init pcr_arch_init(void) | 265 | int __init pcr_arch_init(void) |
143 | { | 266 | { |
144 | int err = register_perf_hsvc(); | 267 | int err = register_perf_hsvc(); |
@@ -148,15 +271,14 @@ int __init pcr_arch_init(void) | |||
148 | 271 | ||
149 | switch (tlb_type) { | 272 | switch (tlb_type) { |
150 | case hypervisor: | 273 | case hypervisor: |
151 | pcr_ops = &n2_pcr_ops; | 274 | err = setup_sun4v_pcr_ops(); |
152 | pcr_enable = PCR_N2_ENABLE; | 275 | if (err) |
153 | picl_shift = 2; | 276 | goto out_unregister; |
154 | break; | 277 | break; |
155 | 278 | ||
156 | case cheetah: | 279 | case cheetah: |
157 | case cheetah_plus: | 280 | case cheetah_plus: |
158 | pcr_ops = &direct_pcr_ops; | 281 | pcr_ops = &direct_pcr_ops; |
159 | pcr_enable = PCR_SUN4U_ENABLE; | ||
160 | break; | 282 | break; |
161 | 283 | ||
162 | case spitfire: | 284 | case spitfire: |