blob: 97225ac1bd94c86ba9043eb60831660aedac8f82 [file] [log] [blame]
Stepan Moskovchenko07552e12012-02-29 20:09:32 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/platform_device.h>
16#include <linux/module.h>
17#include <linux/errno.h>
18#include <linux/proc_fs.h>
19#include <linux/cpu.h>
Stepan Moskovchenko6482c432012-04-30 13:34:23 -070020#include <linux/io.h>
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080021#include <mach/msm-krait-l2-accessors.h>
Stepan Moskovchenko6482c432012-04-30 13:34:23 -070022#include <mach/msm_iomap.h>
23#include <asm/cputype.h>
24#include "acpuclock.h"
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080025
26#define CESR_DCTPE BIT(0)
27#define CESR_DCDPE BIT(1)
28#define CESR_ICTPE BIT(2)
29#define CESR_ICDPE BIT(3)
30#define CESR_DCTE (BIT(4) | BIT(5))
31#define CESR_ICTE (BIT(6) | BIT(7))
32#define CESR_TLBMH BIT(16)
33#define CESR_I_MASK 0x000000CC
34
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -070035/* Print a message for everything but TLB MH events */
36#define CESR_PRINT_MASK 0x000000FF
37
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080038#define L2ESR_IND_ADDR 0x204
39#define L2ESYNR0_IND_ADDR 0x208
40#define L2ESYNR1_IND_ADDR 0x209
41#define L2EAR0_IND_ADDR 0x20C
42#define L2EAR1_IND_ADDR 0x20D
43
44#define L2ESR_MPDCD BIT(0)
45#define L2ESR_MPSLV BIT(1)
46#define L2ESR_TSESB BIT(2)
47#define L2ESR_TSEDB BIT(3)
48#define L2ESR_DSESB BIT(4)
49#define L2ESR_DSEDB BIT(5)
50#define L2ESR_MSE BIT(6)
51#define L2ESR_MPLDREXNOK BIT(8)
52
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -070053#define L2ESR_ACCESS_ERR_MASK 0xFFFC
54
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080055#define L2ESR_CPU_MASK 0x0F
56#define L2ESR_CPU_SHIFT 16
57
58#ifdef CONFIG_MSM_L1_ERR_PANIC
59#define ERP_L1_ERR(a) panic(a)
60#else
61#define ERP_L1_ERR(a) do { } while (0)
62#endif
63
64#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC
65#define ERP_PORT_ERR(a) panic(a)
66#else
67#define ERP_PORT_ERR(a) WARN(1, a)
68#endif
69
70#ifdef CONFIG_MSM_L2_ERP_1BIT_PANIC
71#define ERP_1BIT_ERR(a) panic(a)
72#else
73#define ERP_1BIT_ERR(a) do { } while (0)
74#endif
75
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -070076#ifdef CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS
77#define print_access_errors() 1
78#else
79#define print_access_errors() 0
80#endif
81
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080082#ifdef CONFIG_MSM_L2_ERP_2BIT_PANIC
83#define ERP_2BIT_ERR(a) panic(a)
84#else
85#define ERP_2BIT_ERR(a) do { } while (0)
86#endif
87
88#define MODULE_NAME "msm_cache_erp"
89
90struct msm_l1_err_stats {
91 unsigned int dctpe;
92 unsigned int dcdpe;
93 unsigned int ictpe;
94 unsigned int icdpe;
95 unsigned int dcte;
96 unsigned int icte;
97 unsigned int tlbmh;
98};
99
100struct msm_l2_err_stats {
101 unsigned int mpdcd;
102 unsigned int mpslv;
103 unsigned int tsesb;
104 unsigned int tsedb;
105 unsigned int dsesb;
106 unsigned int dsedb;
107 unsigned int mse;
108 unsigned int mplxrexnok;
109};
110
111static DEFINE_PER_CPU(struct msm_l1_err_stats, msm_l1_erp_stats);
112static struct msm_l2_err_stats msm_l2_erp_stats;
113
114static int l1_erp_irq, l2_erp_irq;
115static struct proc_dir_entry *procfs_entry;
116
117static inline unsigned int read_cesr(void)
118{
119 unsigned int cesr;
120 asm volatile ("mrc p15, 7, %0, c15, c0, 1" : "=r" (cesr));
121 return cesr;
122}
123
124static inline void write_cesr(unsigned int cesr)
125{
126 asm volatile ("mcr p15, 7, %[cesr], c15, c0, 1" : : [cesr]"r" (cesr));
127}
128
129static inline unsigned int read_cesynr(void)
130{
131 unsigned int cesynr;
132 asm volatile ("mrc p15, 7, %0, c15, c0, 3" : "=r" (cesynr));
133 return cesynr;
134}
135
136static int proc_read_status(char *page, char **start, off_t off, int count,
137 int *eof, void *data)
138{
139 struct msm_l1_err_stats *l1_stats;
140 char *p = page;
141 int len, cpu, ret, bytes_left = PAGE_SIZE;
142
143 for_each_present_cpu(cpu) {
144 l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
145
146 ret = snprintf(p, bytes_left,
147 "CPU %d:\n" \
148 "\tD-cache tag parity errors:\t%u\n" \
149 "\tD-cache data parity errors:\t%u\n" \
150 "\tI-cache tag parity errors:\t%u\n" \
151 "\tI-cache data parity errors:\t%u\n" \
152 "\tD-cache timing errors:\t\t%u\n" \
153 "\tI-cache timing errors:\t\t%u\n" \
154 "\tTLB multi-hit errors:\t\t%u\n\n", \
155 cpu,
156 l1_stats->dctpe,
157 l1_stats->dcdpe,
158 l1_stats->ictpe,
159 l1_stats->icdpe,
160 l1_stats->dcte,
161 l1_stats->icte,
162 l1_stats->tlbmh);
163 p += ret;
164 bytes_left -= ret;
165 }
166
167 p += snprintf(p, bytes_left,
168 "L2 master port decode errors:\t\t%u\n" \
169 "L2 master port slave errors:\t\t%u\n" \
170 "L2 tag soft errors, single-bit:\t\t%u\n" \
171 "L2 tag soft errors, double-bit:\t\t%u\n" \
172 "L2 data soft errors, single-bit:\t%u\n" \
173 "L2 data soft errors, double-bit:\t%u\n" \
174 "L2 modified soft errors:\t\t%u\n" \
175 "L2 master port LDREX NOK errors:\t%u\n",
176 msm_l2_erp_stats.mpdcd,
177 msm_l2_erp_stats.mpslv,
178 msm_l2_erp_stats.tsesb,
179 msm_l2_erp_stats.tsedb,
180 msm_l2_erp_stats.dsesb,
181 msm_l2_erp_stats.dsedb,
182 msm_l2_erp_stats.mse,
183 msm_l2_erp_stats.mplxrexnok);
184
185 len = (p - page) - off;
186 if (len < 0)
187 len = 0;
188
189 *eof = (len <= count) ? 1 : 0;
190 *start = page + off;
191
192 return len;
193}
194
195static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
196{
197 struct msm_l1_err_stats *l1_stats = dev_id;
198 unsigned int cesr = read_cesr();
199 unsigned int i_cesynr, d_cesynr;
Stepan Moskovchenko6482c432012-04-30 13:34:23 -0700200 unsigned int cpu = smp_processor_id();
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700201 int print_regs = cesr & CESR_PRINT_MASK;
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800202
Stepan Moskovchenko6482c432012-04-30 13:34:23 -0700203 void *const saw_bases[] = {
204 MSM_SAW0_BASE,
205 MSM_SAW1_BASE,
206 MSM_SAW2_BASE,
207 MSM_SAW3_BASE,
208 };
209
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700210 if (print_regs) {
Stepan Moskovchenko6482c432012-04-30 13:34:23 -0700211 pr_alert("L1 / TLB Error detected on CPU %d!\n", cpu);
212 pr_alert("\tCESR = 0x%08x\n", cesr);
213 pr_alert("\tCPU speed = %lu\n", acpuclk_get_rate(cpu));
214 pr_alert("\tMIDR = 0x%08x\n", read_cpuid_id());
215 pr_alert("\tPTE fuses = 0x%08x\n",
216 readl_relaxed(MSM_QFPROM_BASE + 0xC0));
217 pr_alert("\tPMIC_VREG = 0x%08x\n",
218 readl_relaxed(saw_bases[cpu] + 0x14));
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700219 }
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800220
221 if (cesr & CESR_DCTPE) {
222 pr_alert("D-cache tag parity error\n");
223 l1_stats->dctpe++;
224 }
225
226 if (cesr & CESR_DCDPE) {
227 pr_alert("D-cache data parity error\n");
228 l1_stats->dcdpe++;
229 }
230
231 if (cesr & CESR_ICTPE) {
232 pr_alert("I-cache tag parity error\n");
233 l1_stats->ictpe++;
234 }
235
236 if (cesr & CESR_ICDPE) {
237 pr_alert("I-cache data parity error\n");
238 l1_stats->icdpe++;
239 }
240
241 if (cesr & CESR_DCTE) {
242 pr_alert("D-cache timing error\n");
243 l1_stats->dcte++;
244 }
245
246 if (cesr & CESR_ICTE) {
247 pr_alert("I-cache timing error\n");
248 l1_stats->icte++;
249 }
250
251 if (cesr & CESR_TLBMH) {
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700252 asm ("mcr p15, 0, r0, c8, c7, 0");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800253 l1_stats->tlbmh++;
254 }
255
256 if (cesr & (CESR_ICTPE | CESR_ICDPE | CESR_ICTE)) {
257 i_cesynr = read_cesynr();
258 pr_alert("I-side CESYNR = 0x%08x\n", i_cesynr);
259 write_cesr(CESR_I_MASK);
260
261 /*
262 * Clear the I-side bits from the captured CESR value so that we
263 * don't accidentally clear any new I-side errors when we do
264 * the CESR write-clear operation.
265 */
266 cesr &= ~CESR_I_MASK;
267 }
268
269 if (cesr & (CESR_DCTPE | CESR_DCDPE | CESR_DCTE)) {
270 d_cesynr = read_cesynr();
271 pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
272 }
273
274 /* Clear the interrupt bits we processed */
275 write_cesr(cesr);
276
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700277 if (print_regs)
278 ERP_L1_ERR("L1 cache error detected");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800279
280 return IRQ_HANDLED;
281}
282
283static irqreturn_t msm_l2_erp_irq(int irq, void *dev_id)
284{
285 unsigned int l2esr;
286 unsigned int l2esynr0;
287 unsigned int l2esynr1;
288 unsigned int l2ear0;
289 unsigned int l2ear1;
290 int soft_error = 0;
291 int port_error = 0;
292 int unrecoverable = 0;
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700293 int print_alert;
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800294
295 l2esr = get_l2_indirect_reg(L2ESR_IND_ADDR);
296 l2esynr0 = get_l2_indirect_reg(L2ESYNR0_IND_ADDR);
297 l2esynr1 = get_l2_indirect_reg(L2ESYNR1_IND_ADDR);
298 l2ear0 = get_l2_indirect_reg(L2EAR0_IND_ADDR);
299 l2ear1 = get_l2_indirect_reg(L2EAR1_IND_ADDR);
300
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700301 print_alert = print_access_errors() || (l2esr & L2ESR_ACCESS_ERR_MASK);
302
303 if (print_alert) {
304 pr_alert("L2 Error detected!\n");
305 pr_alert("\tL2ESR = 0x%08x\n", l2esr);
306 pr_alert("\tL2ESYNR0 = 0x%08x\n", l2esynr0);
307 pr_alert("\tL2ESYNR1 = 0x%08x\n", l2esynr1);
308 pr_alert("\tL2EAR0 = 0x%08x\n", l2ear0);
309 pr_alert("\tL2EAR1 = 0x%08x\n", l2ear1);
310 pr_alert("\tCPU bitmap = 0x%x\n", (l2esr >> L2ESR_CPU_SHIFT) &
311 L2ESR_CPU_MASK);
312 }
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800313
314 if (l2esr & L2ESR_MPDCD) {
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700315 if (print_alert)
316 pr_alert("L2 master port decode error\n");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800317 port_error++;
318 msm_l2_erp_stats.mpdcd++;
319 }
320
321 if (l2esr & L2ESR_MPSLV) {
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700322 if (print_alert)
323 pr_alert("L2 master port slave error\n");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800324 port_error++;
325 msm_l2_erp_stats.mpslv++;
326 }
327
328 if (l2esr & L2ESR_TSESB) {
329 pr_alert("L2 tag soft error, single-bit\n");
330 soft_error++;
331 msm_l2_erp_stats.tsesb++;
332 }
333
334 if (l2esr & L2ESR_TSEDB) {
335 pr_alert("L2 tag soft error, double-bit\n");
336 soft_error++;
337 unrecoverable++;
338 msm_l2_erp_stats.tsedb++;
339 }
340
341 if (l2esr & L2ESR_DSESB) {
342 pr_alert("L2 data soft error, single-bit\n");
343 soft_error++;
344 msm_l2_erp_stats.dsesb++;
345 }
346
347 if (l2esr & L2ESR_DSEDB) {
348 pr_alert("L2 data soft error, double-bit\n");
349 soft_error++;
350 unrecoverable++;
351 msm_l2_erp_stats.dsedb++;
352 }
353
354 if (l2esr & L2ESR_MSE) {
355 pr_alert("L2 modified soft error\n");
356 soft_error++;
357 msm_l2_erp_stats.mse++;
358 }
359
360 if (l2esr & L2ESR_MPLDREXNOK) {
361 pr_alert("L2 master port LDREX received Normal OK response\n");
362 port_error++;
363 msm_l2_erp_stats.mplxrexnok++;
364 }
365
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700366 if (port_error && print_alert)
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800367 ERP_PORT_ERR("L2 master port error detected");
368
369 if (soft_error && !unrecoverable)
370 ERP_1BIT_ERR("L2 single-bit error detected");
371
372 if (unrecoverable)
373 ERP_2BIT_ERR("L2 double-bit error detected, trouble ahead");
374
375 set_l2_indirect_reg(L2ESR_IND_ADDR, l2esr);
376 return IRQ_HANDLED;
377}
378
379static void enable_erp_irq_callback(void *info)
380{
381 enable_percpu_irq(l1_erp_irq, IRQ_TYPE_LEVEL_HIGH);
382}
383
384static void disable_erp_irq_callback(void *info)
385{
386 disable_percpu_irq(l1_erp_irq);
387}
388
389static int cache_erp_cpu_callback(struct notifier_block *nfb,
390 unsigned long action, void *hcpu)
391{
392 switch (action & (~CPU_TASKS_FROZEN)) {
393 case CPU_STARTING:
394 enable_erp_irq_callback(NULL);
395 break;
396
397 case CPU_DYING:
398 disable_erp_irq_callback(NULL);
399 break;
400 }
401 return NOTIFY_OK;
402}
403
404static struct notifier_block cache_erp_cpu_notifier = {
405 .notifier_call = cache_erp_cpu_callback,
406};
407
408static int msm_cache_erp_probe(struct platform_device *pdev)
409{
410 struct resource *r;
411 int ret, cpu;
412
413 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l1_irq");
414
415 if (!r) {
416 pr_err("Could not get L1 resource\n");
417 ret = -ENODEV;
418 goto fail;
419 }
420
421 l1_erp_irq = r->start;
422
423 ret = request_percpu_irq(l1_erp_irq, msm_l1_erp_irq, "MSM_L1",
424 &msm_l1_erp_stats);
425
426 if (ret) {
427 pr_err("Failed to request the L1 cache error interrupt\n");
428 goto fail;
429 }
430
431 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l2_irq");
432
433 if (!r) {
434 pr_err("Could not get L2 resource\n");
435 ret = -ENODEV;
436 goto fail_l1;
437 }
438
439 l2_erp_irq = r->start;
440 ret = request_irq(l2_erp_irq, msm_l2_erp_irq, 0, "MSM_L2", NULL);
441
442 if (ret) {
443 pr_err("Failed to request the L2 cache error interrupt\n");
444 goto fail_l1;
445 }
446
447 procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
448
449 if (!procfs_entry) {
450 pr_err("Failed to create procfs node for cache error reporting\n");
451 ret = -ENODEV;
452 goto fail_l2;
453 }
454
455 get_online_cpus();
456 register_hotcpu_notifier(&cache_erp_cpu_notifier);
457 for_each_cpu(cpu, cpu_online_mask)
458 smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
459 put_online_cpus();
460
461 procfs_entry->read_proc = proc_read_status;
462 return 0;
463
464fail_l2:
465 free_irq(l2_erp_irq, NULL);
466fail_l1:
467 free_percpu_irq(l1_erp_irq, NULL);
468fail:
469 return ret;
470}
471
472static int msm_cache_erp_remove(struct platform_device *pdev)
473{
474 int cpu;
475 if (procfs_entry)
476 remove_proc_entry("cpu/msm_cache_erp", NULL);
477
478 get_online_cpus();
479 unregister_hotcpu_notifier(&cache_erp_cpu_notifier);
480 for_each_cpu(cpu, cpu_online_mask)
481 smp_call_function_single(cpu, disable_erp_irq_callback, NULL,
482 1);
483 put_online_cpus();
484
485 free_percpu_irq(l1_erp_irq, NULL);
486
487 disable_irq(l2_erp_irq);
488 free_irq(l2_erp_irq, NULL);
489 return 0;
490}
491
492static struct platform_driver msm_cache_erp_driver = {
493 .probe = msm_cache_erp_probe,
494 .remove = msm_cache_erp_remove,
495 .driver = {
496 .name = MODULE_NAME,
497 .owner = THIS_MODULE,
498 },
499};
500
501static int __init msm_cache_erp_init(void)
502{
503 return platform_driver_register(&msm_cache_erp_driver);
504}
505
506static void __exit msm_cache_erp_exit(void)
507{
508 platform_driver_unregister(&msm_cache_erp_driver);
509}
510
511
512module_init(msm_cache_erp_init);
513module_exit(msm_cache_erp_exit);
514MODULE_LICENSE("GPL v2");
515MODULE_DESCRIPTION("MSM cache error reporting driver");