blob: c3302ec606f171f37d371ebb176f3785989376b5 [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 Moskovchenko7035f652012-05-31 17:48:01 -070038/* Log everything but TLB MH events */
39#define CESR_LOG_EVENT_MASK 0x000000FF
40
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080041#define L2ESR_IND_ADDR 0x204
42#define L2ESYNR0_IND_ADDR 0x208
43#define L2ESYNR1_IND_ADDR 0x209
44#define L2EAR0_IND_ADDR 0x20C
45#define L2EAR1_IND_ADDR 0x20D
46
47#define L2ESR_MPDCD BIT(0)
48#define L2ESR_MPSLV BIT(1)
49#define L2ESR_TSESB BIT(2)
50#define L2ESR_TSEDB BIT(3)
51#define L2ESR_DSESB BIT(4)
52#define L2ESR_DSEDB BIT(5)
53#define L2ESR_MSE BIT(6)
54#define L2ESR_MPLDREXNOK BIT(8)
55
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -070056#define L2ESR_ACCESS_ERR_MASK 0xFFFC
57
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080058#define L2ESR_CPU_MASK 0x0F
59#define L2ESR_CPU_SHIFT 16
60
61#ifdef CONFIG_MSM_L1_ERR_PANIC
62#define ERP_L1_ERR(a) panic(a)
63#else
64#define ERP_L1_ERR(a) do { } while (0)
65#endif
66
67#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC
68#define ERP_PORT_ERR(a) panic(a)
69#else
70#define ERP_PORT_ERR(a) WARN(1, a)
71#endif
72
73#ifdef CONFIG_MSM_L2_ERP_1BIT_PANIC
74#define ERP_1BIT_ERR(a) panic(a)
75#else
76#define ERP_1BIT_ERR(a) do { } while (0)
77#endif
78
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -070079#ifdef CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS
80#define print_access_errors() 1
81#else
82#define print_access_errors() 0
83#endif
84
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080085#ifdef CONFIG_MSM_L2_ERP_2BIT_PANIC
86#define ERP_2BIT_ERR(a) panic(a)
87#else
88#define ERP_2BIT_ERR(a) do { } while (0)
89#endif
90
91#define MODULE_NAME "msm_cache_erp"
92
Stepan Moskovchenkoaa15fd12012-06-18 16:51:13 -070093#define ERP_LOG_MAGIC_ADDR 0x6A4
Stepan Moskovchenko7035f652012-05-31 17:48:01 -070094#define ERP_LOG_MAGIC 0x11C39893
95
Stepan Moskovchenko07552e12012-02-29 20:09:32 -080096struct msm_l1_err_stats {
97 unsigned int dctpe;
98 unsigned int dcdpe;
99 unsigned int ictpe;
100 unsigned int icdpe;
101 unsigned int dcte;
102 unsigned int icte;
103 unsigned int tlbmh;
104};
105
106struct msm_l2_err_stats {
107 unsigned int mpdcd;
108 unsigned int mpslv;
109 unsigned int tsesb;
110 unsigned int tsedb;
111 unsigned int dsesb;
112 unsigned int dsedb;
113 unsigned int mse;
114 unsigned int mplxrexnok;
115};
116
117static DEFINE_PER_CPU(struct msm_l1_err_stats, msm_l1_erp_stats);
118static struct msm_l2_err_stats msm_l2_erp_stats;
119
120static int l1_erp_irq, l2_erp_irq;
121static struct proc_dir_entry *procfs_entry;
122
Stepan Moskovchenko7035f652012-05-31 17:48:01 -0700123#ifdef CONFIG_MSM_L1_ERR_LOG
124static struct proc_dir_entry *procfs_log_entry;
125#endif
126
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800127static inline unsigned int read_cesr(void)
128{
129 unsigned int cesr;
130 asm volatile ("mrc p15, 7, %0, c15, c0, 1" : "=r" (cesr));
131 return cesr;
132}
133
134static inline void write_cesr(unsigned int cesr)
135{
136 asm volatile ("mcr p15, 7, %[cesr], c15, c0, 1" : : [cesr]"r" (cesr));
137}
138
139static inline unsigned int read_cesynr(void)
140{
141 unsigned int cesynr;
142 asm volatile ("mrc p15, 7, %0, c15, c0, 3" : "=r" (cesynr));
143 return cesynr;
144}
145
146static int proc_read_status(char *page, char **start, off_t off, int count,
147 int *eof, void *data)
148{
149 struct msm_l1_err_stats *l1_stats;
150 char *p = page;
151 int len, cpu, ret, bytes_left = PAGE_SIZE;
152
153 for_each_present_cpu(cpu) {
154 l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
155
156 ret = snprintf(p, bytes_left,
157 "CPU %d:\n" \
158 "\tD-cache tag parity errors:\t%u\n" \
159 "\tD-cache data parity errors:\t%u\n" \
160 "\tI-cache tag parity errors:\t%u\n" \
161 "\tI-cache data parity errors:\t%u\n" \
162 "\tD-cache timing errors:\t\t%u\n" \
163 "\tI-cache timing errors:\t\t%u\n" \
164 "\tTLB multi-hit errors:\t\t%u\n\n", \
165 cpu,
166 l1_stats->dctpe,
167 l1_stats->dcdpe,
168 l1_stats->ictpe,
169 l1_stats->icdpe,
170 l1_stats->dcte,
171 l1_stats->icte,
172 l1_stats->tlbmh);
173 p += ret;
174 bytes_left -= ret;
175 }
176
177 p += snprintf(p, bytes_left,
178 "L2 master port decode errors:\t\t%u\n" \
179 "L2 master port slave errors:\t\t%u\n" \
180 "L2 tag soft errors, single-bit:\t\t%u\n" \
181 "L2 tag soft errors, double-bit:\t\t%u\n" \
182 "L2 data soft errors, single-bit:\t%u\n" \
183 "L2 data soft errors, double-bit:\t%u\n" \
184 "L2 modified soft errors:\t\t%u\n" \
185 "L2 master port LDREX NOK errors:\t%u\n",
186 msm_l2_erp_stats.mpdcd,
187 msm_l2_erp_stats.mpslv,
188 msm_l2_erp_stats.tsesb,
189 msm_l2_erp_stats.tsedb,
190 msm_l2_erp_stats.dsesb,
191 msm_l2_erp_stats.dsedb,
192 msm_l2_erp_stats.mse,
193 msm_l2_erp_stats.mplxrexnok);
194
195 len = (p - page) - off;
196 if (len < 0)
197 len = 0;
198
199 *eof = (len <= count) ? 1 : 0;
200 *start = page + off;
201
202 return len;
203}
204
Stepan Moskovchenko7035f652012-05-31 17:48:01 -0700205#ifdef CONFIG_MSM_L1_ERR_LOG
206static int proc_read_log(char *page, char **start, off_t off, int count,
207 int *eof, void *data)
208{
209 char *p = page;
210 int len, log_value;
211 log_value = __raw_readl(MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR) ==
212 ERP_LOG_MAGIC ? 1 : 0;
213
214 p += snprintf(p, PAGE_SIZE, "%d\n", log_value);
215
216 len = (p - page) - off;
217 if (len < 0)
218 len = 0;
219
220 *eof = (len <= count) ? 1 : 0;
221 *start = page + off;
222
223 return len;
224}
225
226static void log_cpu_event(void)
227{
228 __raw_writel(ERP_LOG_MAGIC, MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR);
229 mb();
230}
231
232static int procfs_event_log_init(void)
233{
234 procfs_log_entry = create_proc_entry("cpu/msm_erp_log", S_IRUGO, NULL);
235
236 if (!procfs_log_entry)
237 return -ENODEV;
238 procfs_log_entry->read_proc = proc_read_log;
239 return 0;
240}
241
242#else
243static inline void log_cpu_event(void) { }
244static inline int procfs_event_log_init(void) { return 0; }
245#endif
246
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800247static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
248{
249 struct msm_l1_err_stats *l1_stats = dev_id;
250 unsigned int cesr = read_cesr();
251 unsigned int i_cesynr, d_cesynr;
Stepan Moskovchenko6482c432012-04-30 13:34:23 -0700252 unsigned int cpu = smp_processor_id();
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700253 int print_regs = cesr & CESR_PRINT_MASK;
Stepan Moskovchenko7035f652012-05-31 17:48:01 -0700254 int log_event = cesr & CESR_LOG_EVENT_MASK;
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800255
Stepan Moskovchenko6482c432012-04-30 13:34:23 -0700256 void *const saw_bases[] = {
257 MSM_SAW0_BASE,
258 MSM_SAW1_BASE,
259 MSM_SAW2_BASE,
260 MSM_SAW3_BASE,
261 };
262
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700263 if (print_regs) {
Stepan Moskovchenko6482c432012-04-30 13:34:23 -0700264 pr_alert("L1 / TLB Error detected on CPU %d!\n", cpu);
265 pr_alert("\tCESR = 0x%08x\n", cesr);
266 pr_alert("\tCPU speed = %lu\n", acpuclk_get_rate(cpu));
267 pr_alert("\tMIDR = 0x%08x\n", read_cpuid_id());
268 pr_alert("\tPTE fuses = 0x%08x\n",
269 readl_relaxed(MSM_QFPROM_BASE + 0xC0));
270 pr_alert("\tPMIC_VREG = 0x%08x\n",
271 readl_relaxed(saw_bases[cpu] + 0x14));
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700272 }
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800273
274 if (cesr & CESR_DCTPE) {
275 pr_alert("D-cache tag parity error\n");
276 l1_stats->dctpe++;
277 }
278
279 if (cesr & CESR_DCDPE) {
280 pr_alert("D-cache data parity error\n");
281 l1_stats->dcdpe++;
282 }
283
284 if (cesr & CESR_ICTPE) {
285 pr_alert("I-cache tag parity error\n");
286 l1_stats->ictpe++;
287 }
288
289 if (cesr & CESR_ICDPE) {
290 pr_alert("I-cache data parity error\n");
291 l1_stats->icdpe++;
292 }
293
294 if (cesr & CESR_DCTE) {
295 pr_alert("D-cache timing error\n");
296 l1_stats->dcte++;
297 }
298
299 if (cesr & CESR_ICTE) {
300 pr_alert("I-cache timing error\n");
301 l1_stats->icte++;
302 }
303
304 if (cesr & CESR_TLBMH) {
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700305 asm ("mcr p15, 0, r0, c8, c7, 0");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800306 l1_stats->tlbmh++;
307 }
308
309 if (cesr & (CESR_ICTPE | CESR_ICDPE | CESR_ICTE)) {
310 i_cesynr = read_cesynr();
311 pr_alert("I-side CESYNR = 0x%08x\n", i_cesynr);
312 write_cesr(CESR_I_MASK);
313
314 /*
315 * Clear the I-side bits from the captured CESR value so that we
316 * don't accidentally clear any new I-side errors when we do
317 * the CESR write-clear operation.
318 */
319 cesr &= ~CESR_I_MASK;
320 }
321
322 if (cesr & (CESR_DCTPE | CESR_DCDPE | CESR_DCTE)) {
323 d_cesynr = read_cesynr();
324 pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
325 }
326
Stepan Moskovchenko7035f652012-05-31 17:48:01 -0700327 if (log_event)
328 log_cpu_event();
329
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800330 /* Clear the interrupt bits we processed */
331 write_cesr(cesr);
332
Stepan Moskovchenkobddae7c2012-04-25 14:48:21 -0700333 if (print_regs)
334 ERP_L1_ERR("L1 cache error detected");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800335
336 return IRQ_HANDLED;
337}
338
339static irqreturn_t msm_l2_erp_irq(int irq, void *dev_id)
340{
341 unsigned int l2esr;
342 unsigned int l2esynr0;
343 unsigned int l2esynr1;
344 unsigned int l2ear0;
345 unsigned int l2ear1;
346 int soft_error = 0;
347 int port_error = 0;
348 int unrecoverable = 0;
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700349 int print_alert;
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800350
351 l2esr = get_l2_indirect_reg(L2ESR_IND_ADDR);
352 l2esynr0 = get_l2_indirect_reg(L2ESYNR0_IND_ADDR);
353 l2esynr1 = get_l2_indirect_reg(L2ESYNR1_IND_ADDR);
354 l2ear0 = get_l2_indirect_reg(L2EAR0_IND_ADDR);
355 l2ear1 = get_l2_indirect_reg(L2EAR1_IND_ADDR);
356
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700357 print_alert = print_access_errors() || (l2esr & L2ESR_ACCESS_ERR_MASK);
358
359 if (print_alert) {
360 pr_alert("L2 Error detected!\n");
361 pr_alert("\tL2ESR = 0x%08x\n", l2esr);
362 pr_alert("\tL2ESYNR0 = 0x%08x\n", l2esynr0);
363 pr_alert("\tL2ESYNR1 = 0x%08x\n", l2esynr1);
364 pr_alert("\tL2EAR0 = 0x%08x\n", l2ear0);
365 pr_alert("\tL2EAR1 = 0x%08x\n", l2ear1);
366 pr_alert("\tCPU bitmap = 0x%x\n", (l2esr >> L2ESR_CPU_SHIFT) &
367 L2ESR_CPU_MASK);
368 }
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800369
370 if (l2esr & L2ESR_MPDCD) {
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700371 if (print_alert)
372 pr_alert("L2 master port decode error\n");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800373 port_error++;
374 msm_l2_erp_stats.mpdcd++;
375 }
376
377 if (l2esr & L2ESR_MPSLV) {
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700378 if (print_alert)
379 pr_alert("L2 master port slave error\n");
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800380 port_error++;
381 msm_l2_erp_stats.mpslv++;
382 }
383
384 if (l2esr & L2ESR_TSESB) {
385 pr_alert("L2 tag soft error, single-bit\n");
386 soft_error++;
387 msm_l2_erp_stats.tsesb++;
388 }
389
390 if (l2esr & L2ESR_TSEDB) {
391 pr_alert("L2 tag soft error, double-bit\n");
392 soft_error++;
393 unrecoverable++;
394 msm_l2_erp_stats.tsedb++;
395 }
396
397 if (l2esr & L2ESR_DSESB) {
398 pr_alert("L2 data soft error, single-bit\n");
399 soft_error++;
400 msm_l2_erp_stats.dsesb++;
401 }
402
403 if (l2esr & L2ESR_DSEDB) {
404 pr_alert("L2 data soft error, double-bit\n");
405 soft_error++;
406 unrecoverable++;
407 msm_l2_erp_stats.dsedb++;
408 }
409
410 if (l2esr & L2ESR_MSE) {
411 pr_alert("L2 modified soft error\n");
412 soft_error++;
413 msm_l2_erp_stats.mse++;
414 }
415
416 if (l2esr & L2ESR_MPLDREXNOK) {
417 pr_alert("L2 master port LDREX received Normal OK response\n");
418 port_error++;
419 msm_l2_erp_stats.mplxrexnok++;
420 }
421
Stepan Moskovchenkoe9a5dc12012-04-03 20:25:49 -0700422 if (port_error && print_alert)
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800423 ERP_PORT_ERR("L2 master port error detected");
424
425 if (soft_error && !unrecoverable)
426 ERP_1BIT_ERR("L2 single-bit error detected");
427
428 if (unrecoverable)
429 ERP_2BIT_ERR("L2 double-bit error detected, trouble ahead");
430
431 set_l2_indirect_reg(L2ESR_IND_ADDR, l2esr);
432 return IRQ_HANDLED;
433}
434
435static void enable_erp_irq_callback(void *info)
436{
437 enable_percpu_irq(l1_erp_irq, IRQ_TYPE_LEVEL_HIGH);
438}
439
440static void disable_erp_irq_callback(void *info)
441{
442 disable_percpu_irq(l1_erp_irq);
443}
444
445static int cache_erp_cpu_callback(struct notifier_block *nfb,
446 unsigned long action, void *hcpu)
447{
448 switch (action & (~CPU_TASKS_FROZEN)) {
449 case CPU_STARTING:
450 enable_erp_irq_callback(NULL);
451 break;
452
453 case CPU_DYING:
454 disable_erp_irq_callback(NULL);
455 break;
456 }
457 return NOTIFY_OK;
458}
459
460static struct notifier_block cache_erp_cpu_notifier = {
461 .notifier_call = cache_erp_cpu_callback,
462};
463
464static int msm_cache_erp_probe(struct platform_device *pdev)
465{
466 struct resource *r;
467 int ret, cpu;
468
469 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l1_irq");
470
471 if (!r) {
472 pr_err("Could not get L1 resource\n");
473 ret = -ENODEV;
474 goto fail;
475 }
476
477 l1_erp_irq = r->start;
478
479 ret = request_percpu_irq(l1_erp_irq, msm_l1_erp_irq, "MSM_L1",
480 &msm_l1_erp_stats);
481
482 if (ret) {
483 pr_err("Failed to request the L1 cache error interrupt\n");
484 goto fail;
485 }
486
487 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l2_irq");
488
489 if (!r) {
490 pr_err("Could not get L2 resource\n");
491 ret = -ENODEV;
492 goto fail_l1;
493 }
494
495 l2_erp_irq = r->start;
496 ret = request_irq(l2_erp_irq, msm_l2_erp_irq, 0, "MSM_L2", NULL);
497
498 if (ret) {
499 pr_err("Failed to request the L2 cache error interrupt\n");
500 goto fail_l1;
501 }
502
503 procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
504
505 if (!procfs_entry) {
506 pr_err("Failed to create procfs node for cache error reporting\n");
507 ret = -ENODEV;
508 goto fail_l2;
509 }
510
511 get_online_cpus();
512 register_hotcpu_notifier(&cache_erp_cpu_notifier);
513 for_each_cpu(cpu, cpu_online_mask)
514 smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
515 put_online_cpus();
516
517 procfs_entry->read_proc = proc_read_status;
Stepan Moskovchenko7035f652012-05-31 17:48:01 -0700518
519 ret = procfs_event_log_init();
520 if (ret)
521 pr_err("Failed to create procfs node for ERP log access\n");
522
Stepan Moskovchenko07552e12012-02-29 20:09:32 -0800523 return 0;
524
525fail_l2:
526 free_irq(l2_erp_irq, NULL);
527fail_l1:
528 free_percpu_irq(l1_erp_irq, NULL);
529fail:
530 return ret;
531}
532
533static int msm_cache_erp_remove(struct platform_device *pdev)
534{
535 int cpu;
536 if (procfs_entry)
537 remove_proc_entry("cpu/msm_cache_erp", NULL);
538
539 get_online_cpus();
540 unregister_hotcpu_notifier(&cache_erp_cpu_notifier);
541 for_each_cpu(cpu, cpu_online_mask)
542 smp_call_function_single(cpu, disable_erp_irq_callback, NULL,
543 1);
544 put_online_cpus();
545
546 free_percpu_irq(l1_erp_irq, NULL);
547
548 disable_irq(l2_erp_irq);
549 free_irq(l2_erp_irq, NULL);
550 return 0;
551}
552
553static struct platform_driver msm_cache_erp_driver = {
554 .probe = msm_cache_erp_probe,
555 .remove = msm_cache_erp_remove,
556 .driver = {
557 .name = MODULE_NAME,
558 .owner = THIS_MODULE,
559 },
560};
561
562static int __init msm_cache_erp_init(void)
563{
564 return platform_driver_register(&msm_cache_erp_driver);
565}
566
567static void __exit msm_cache_erp_exit(void)
568{
569 platform_driver_unregister(&msm_cache_erp_driver);
570}
571
572
573module_init(msm_cache_erp_init);
574module_exit(msm_cache_erp_exit);
575MODULE_LICENSE("GPL v2");
576MODULE_DESCRIPTION("MSM cache error reporting driver");