blob: deb613883e127a9b1daa083bd9c03f202dca4482 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * Copyright: (C) Copyright 2015 Marvell International Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * publishhed by the Free Software Foundation.
7 *
8 * Author: Yan Markman (ymarkman@marvell.com)
9 *
10 * Utilities for ramdump.c debug capability extension:
11 * - Kernel-RO CRC16 check and reporting on panic
12 * - Control /dev/ramdump_ctl for ramdump enable/disable, panic, crc check...
13 */
14#define _RAMDUMP_UTIL_C
15
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/delay.h>
19#include <linux/fs.h>
20#include <linux/device.h>
21#include <linux/cdev.h>
22#include <linux/miscdevice.h>
23#include <linux/kthread.h>
24#include <linux/crc16.h>
25#include <asm/uaccess.h>
26#include <asm-generic/sections.h>
27#include <soc/asr/addr-map.h>
28#include <linux/io.h>
29#include <linux/sched/clock.h>
30#include <soc/asr/ramdump.h>
31#include <soc/asr/ramdump_util.h>
32#include <soc/asr/ramdump_miscdevice.h>
33#include <soc/asr/regs-timers.h>
34#ifdef CONFIG_PXA_MIPSRAM
35#include <linux/mipsram.h>
36#endif
37
38/* need to make sure all kernel modules are loaded before
39* calculating the kernel CRC16 value, as kernel modules often
40* invokes static_key APIs and dirties the kernel code area
41*/
42#define RDP_CRC16_CALC_SLP_SEC (64)
43
44extern int k_signal_panic_guid_set(int set_uid, int *sig_guid_array, int size);
45
46static int sysdbg_cdev_create_register(const char *dev_name,
47 const struct file_operations *fops);
48
49#ifndef CONFIG_CRC16
50int get_kernel_text_crc16_valid(void) { return 1; }
51u16 get_kernel_text_crc16_on_panic(void) {}
52int get_kernel_text_crc16_threaded_req(void) { return 0; }
53#else
54
55/* RAM consistency checker (also usable as Kernel-ID)
56 * applied over ReadOnly area - Kernel TEXT
57 * Called once on startup for "good reference" and once on panic
58 * "On panic" calculation has latency ~320mS
59 * "startup" called by late_initcall() and done over special "kcrc" kthread
60 * The CPU is 100% loaded, so delay calculation for 2sec and do it by
61 * chunks 32kB. Exit thread upon finish.
62 */
63static char *crc_txt = "KERNEL-TEXT-CRC:";
64static u16 kernel_text_crc16_buf[2];
65
66int get_kernel_text_crc16_valid(void)
67{
68 if (!kernel_text_crc16_buf[1])
69 return -2; /* not accounted */
70 if (kernel_text_crc16_buf[0] &&
71 (kernel_text_crc16_buf[0] != kernel_text_crc16_buf[1]))
72 return -1;
73 return 0;
74}
75
76/* "one-shot" blocking with very long latency */
77u16 get_kernel_text_crc16_on_panic(void)
78{
79 u16 crc;
80 /* first parameter is - previous CRC value */
81 crc = crc16(0, (u8*)&_text, (size_t)&_etext - (size_t)&_text);
82 kernel_text_crc16_buf[1] = crc;
83 pr_err("%s orig/panic = 0x%x/0x%x\n", crc_txt,
84 kernel_text_crc16_buf[0], kernel_text_crc16_buf[1]);
85 return crc;
86}
87
88/* short latency pices with sleep - to be called by a thread only */
89static int get_kernel_text_crc16_sleep(void *data)
90{
91 const int chunk = 0x8000;
92 u16 crc;
93 int len, size;
94 u8 *p;
95 int initcall_run = ((int)data == 1);
96
97 if (initcall_run) {
98 /* Kernel-RO is modified by NET-pack
99 * Delay crc-account for 10sec
100 */
101 ssleep(RDP_CRC16_CALC_SLP_SEC);
102 }
103
104 if (!initcall_run && !kernel_text_crc16_buf[0]) {
105 pr_debug("%s kcrc_init not finished\n", crc_txt);
106 return 0;
107 }
108
109 crc = 0;
110 p = (u8*)&_text;
111 size = (size_t)&_etext - (size_t)&_text;
112
113 do {
114 len = (size > chunk) ? chunk : size;
115 crc = crc16(crc, p, len);
116 p += len;
117 size -= len;
118 msleep(8);
119 } while (size);
120
121 if (initcall_run) {
122 /* Run on init */
123 kernel_text_crc16_buf[0] = crc;
124 pr_info("%s 0x%x\n", crc_txt, crc);
125 } else {
126 /* Run from proc command */
127 kernel_text_crc16_buf[1] = crc;
128 pr_err("%s orig/run = 0x%x/0x%x\n", crc_txt,
129 kernel_text_crc16_buf[0], kernel_text_crc16_buf[1]);
130 }
131 return 0;
132}
133
134int get_kernel_text_crc16_threaded_req(void)
135{
136 pr_info("Kernel-RO CRC checking started. Takes about 4sec...\n");
137 kthread_run(get_kernel_text_crc16_sleep, NULL, "kcrc");
138 return 0;
139}
140
141static int kernel_text_crc16_init(void)
142{
143 kthread_run(get_kernel_text_crc16_sleep, (void*)1, "kcrc_init");
144 return 0;
145}
146late_initcall(kernel_text_crc16_init);
147#endif/*CONFIG_CRC16*/
148
149/*#define KERNEL_BAD_CRC_DEBUG*/
150#ifdef KERNEL_BAD_CRC_DEBUG
151/* If Kernel CRC is wrong need to debug this,
152 * but KERNEL RO is not saved in RAMDUMP.
153 * Let's force-copy the Kernel into predefined address
154 * and panic at once
155 */
156static int get_kernel_text_copy2ddr(void)
157{
158 unsigned long flags;
159 unsigned *src = (unsigned*)&_text;
160 unsigned *dst = (unsigned*)0xC2000000;
161 unsigned size = (unsigned)&_etext - (unsigned)&_text;
162
163 pr_err("Kernel size_0x%x copy from 0x%x to 0x%x\n",
164 size, (unsigned)src, (unsigned)dst);
165 size /= sizeof(int);
166 local_irq_save(flags);
167 while (size--)
168 *dst++ = *src++;
169 panic("Kernel-Copy");
170 return 0;
171}
172#endif
173
174#if !defined(CONFIG_CPU_ASR18XX) && !defined(CONFIG_CPU_ASR1901)
175void ramdump_clock_calibration(int full_calib) {}
176#else
177#define RD_LOOPS 100000
178#define RD_LOOPS_CCNT (RD_LOOPS * 6 + 33)
179#define RD_IRQ_CCNT 136 /* local_irq_save + restore */
180void ramdump_clock_calibration(int full_calib)
181{
182 unsigned long flags;
183 volatile unsigned cntr;
184 u64 ts_nsec0, ts_nsec1;
185 register unsigned int ccnt0, ccnt1;
186
187 if (full_calib)
188 pr_info("\n");
189 do {
190 /* Measure */
191 cntr = RD_LOOPS;
192 local_irq_save(flags);
193 ts_nsec0 = local_clock();
194 __asm__ __volatile__("mrc p15, 0, %0, c9, c13, 0" : "=r" (ccnt0));
195 if (full_calib) {
196 while(cntr--) /**/; /*no IRQs*/
197 } else {
198 local_irq_restore(flags);
199 while(cntr--) /**/;
200 local_irq_save(flags);
201 }
202 __asm__ __volatile__("mrc p15, 0, %0, c9, c13, 0" : "=r" (ccnt1));
203 ts_nsec1 = local_clock();
204 local_irq_restore(flags);
205 ts_nsec1 -= ts_nsec0;
206 ccnt1 -= ccnt0;
207 pr_info("Clocks %10u in %10u nsec = %dMHz\n",
208 ccnt1, (u32)ts_nsec1, (ccnt1 * 10)/((u32)ts_nsec1/100));
209 } while (full_calib--);
210 /* Known MIN job on 100.000 loops is 600.033 ccnt */
211 pr_info("CPI IDLE = %d%c\n",
212 ((RD_LOOPS_CCNT * 1000) / (ccnt1 - RD_IRQ_CCNT)) / 10, '%');
213}
214#endif/*CONFIG_CPU_ASR18XX*/
215
216/* We have 2 kinds of counters 32kHz used for timestamps:
217 * - In timer hw-module (one or more, free-running or interrupt)
218 * - Common 32kHz free running counter for AP/CP/MSA processors
219 * Kernel, MIPSRAMs, diag could use different.
220 * For offline analysis need to know delta.
221 * The clocks have different PLL-source, so delta may have drift
222 */
223struct rdp_ts_desc {
224 unsigned int cntr_tmr;
225 unsigned int cntr_cmn;
226 void __iomem *va_tmr;
227 void __iomem *va_cmn;
228 unsigned int pa_tmr;
229 unsigned int pa_cmn;
230};
231
232#define PMUTMR_CR(n) (0x28 + (n << 2))
233
234static struct rdp_ts_desc ramdump_timestamps = {
235 .pa_tmr = APB_PHYS_BASE + 0x14000 + TMR_CR(1), /*TIMER_0_1 CR*/
236#ifndef CONFIG_CPU_ASR18XX
237 .pa_cmn = APB_PHYS_BASE + 0x16000 + TMR_CR(0), /*TIMER_1_0 CR*/
238#elif defined(CONFIG_CPU_ASR1903)
239 .pa_cmn = APB_PHYS_BASE + 0x16000 + PMUTMR_CR(1), /*PMUTIMER_1 CR*/
240#else
241 .pa_cmn = APB_PHYS_BASE + 0x3A000 + TMR_CR(0), /*CP TIMER_1_0 CR*/
242#endif
243};
244
245static void rdp_ts_init(void)
246{
247 struct rdp_ts_desc *p = &ramdump_timestamps;
248 p->va_tmr = ioremap(p->pa_tmr, 0x4);
249 p->va_cmn = ioremap(p->pa_cmn, 0x4);
250 p->cntr_tmr = (p->va_tmr) ? __raw_readl(p->va_tmr) : 0;
251 p->cntr_cmn = (p->va_cmn) ? __raw_readl(p->va_cmn) : 0;
252 pr_info("TIMESTAMP 32kHz: timer-common = %u = 0x%08x - 0x%08x\n",
253 p->cntr_tmr - p->cntr_cmn, p->cntr_tmr, p->cntr_cmn);
254}
255
256static void rdp_ts_show(void)
257{
258 struct rdp_ts_desc *p = &ramdump_timestamps;
259 unsigned int tmr, cmn;
260 tmr = (p->va_tmr) ? __raw_readl(p->va_tmr) : 0;
261 cmn = (p->va_cmn) ? __raw_readl(p->va_cmn) : 0;
262 pr_info("TIMESTAMP 32kHz: timer-common = %u = 0x%08x - 0x%08x\n",
263 tmr - cmn, tmr, cmn);
264}
265
266#ifdef CONFIG_INPUT_88PM80X_ONKEY
267extern int (*pm80x_onkey_cb_ret0_to_continue)(unsigned int param);
268/* Helpfull for immediate panic and PM wake event debug */
269#ifdef CONFIG_PXA_MIPSRAM
270#define MIPS_RAM_ONKEY_TRACE() MIPS_RAM_ADD_TRACE(0x10101010) /* IO IO */
271#else
272#define MIPS_RAM_ONKEY_TRACE
273#endif
274
275static int ramdump_onkey_empty_evnt(unsigned int val)
276{
277#ifdef CONFIG_PXA_MIPSRAM
278 MIPS_RAM_ONKEY_TRACE();
279#endif
280 rdp_ts_show();
281 return -1; /* do nothing but empty event only */
282}
283static int ramdump_onkey_panic_cntr;
284static int ramdump_onkey_panic(unsigned int val)
285{
286#ifdef CONFIG_PXA_MIPSRAM
287 MIPS_RAM_ONKEY_TRACE();
288#endif
289 rdp_ts_show();
290 BUG_ON(!ramdump_onkey_panic_cntr--);
291 return -1;
292}
293#endif/*CONFIG_INPUT_88PM80X_ONKEY*/
294
295void ramdump_ignore_fatal_signals(int on_shutdown)
296{
297 /* This procedure is used on shutdown and is a "shortcut" alternative
298 * to the "conventional" /proc/sys/kernel/print-fatal-signals
299 * which is too long for shutdown
300 */
301 extern int print_fatal_signals;
302 if (ramdump_level <= RAMDUMP_LEVEL_PANIC_ONLY) {
303 if (on_shutdown)
304 print_fatal_signals = 0x10;
305 else
306 print_fatal_signals = 2;
307 }
308}
309
310/*** "ramdump_ctl" - RAMDUMP Enable/Disable control device ********/
311static int ramdump_ctl_read(struct file *filp, char __user *buf,
312 size_t count, loff_t *f_pos)
313{
314 int len;
315 char kbuf[24];
316
317 if (*f_pos)
318 return 0; /* second entry of same command */
319
320 /* Could be called as "cat /dev" or as read(1byte) from SW-code
321 * The output is different for these cases:
322 * - read(1byte) expects Row-Binary 1 byte
323 * (if ramdump_level<2 the User-Space-reader ignores error)
324 * - shell/system() read has count=4kB and obtains string
325 */
326 if (count == 1) {
327 len = count;
328 kbuf[0] = ramdump_level & 0xff;
329 } else {
330 len = sprintf(kbuf, "\t ramdump_enable=%d\n", ramdump_level);
331 }
332 *f_pos = len;
333 if (copy_to_user(buf, kbuf, len))
334 return -EFAULT;
335 return len;
336}
337
338static const char *tstPanic = "Force-Emulate Kernel panic";
339
340static int ramdump_ctl_write(struct file *filp, const char __user *buf,
341 size_t count, loff_t *f_pos)
342{
343 char in;
344 char desc_buf[80];
345 int copy_done, copy_left, i;
346
347 if ((count <= 0) || *f_pos)
348 return 0;
349 if (copy_from_user(&in, buf, 1))
350 return -EFAULT;
351 if (in == 'd') {
352 ramdump_level = 0;
353 ramdump_ignore_fatal_signals(0);
354 } else if (in == 'e') {
355 ramdump_level = RAMDUMP_LEVEL_FULL;
356 } else if (in == 'a') {
357 ramdump_level = RAMDUMP_LEVEL_FULL_IN_ADVANCE;
358 ramdump_prepare_in_advance();
359 } else if (in == 'p') {
360 ramdump_level = 0xf;
361 desc_buf[0] = 0;
362 if (!copy_from_user(&in, &buf[1], 1)) {
363 if (in == '_') {
364 copy_left = copy_from_user(desc_buf, &buf[2], 79);
365 copy_done = 79 - copy_left;
366 desc_buf[copy_done] = 0;
367 /* strip LF */
368 i = 0;
369 while (i < copy_done) {
370 if (desc_buf[i] == '\n')
371 desc_buf[i] = 0;
372 if (!desc_buf[i++])
373 break;
374 }
375 }
376 }
377 if (desc_buf[0]) {
378 panic("%s \'%s\'\n", tstPanic, desc_buf);
379 } else {
380 panic("%s\n", tstPanic);
381 }
382 } else if (in == 'B') {
383 ramdump_level = 0xB;
384 pr_err("\n %s (BUG)\n", tstPanic);
385 BUG();
386
387 } else if (in == 'c') {
388 /* CRC blocking account with long latency! */
389 get_kernel_text_crc16_on_panic();
390 i = get_kernel_text_crc16_valid();
391 if (i == -1) {
392 pr_err("!Bad Kernel CRC!\n");
393 return -ERANGE;
394 } else if (i == -2) {
395 pr_err("CRC not accounted\n");
396 return -EAGAIN;
397 }
398#ifdef KERNEL_BAD_CRC_DEBUG
399 } else if (in == 'C') {
400 get_kernel_text_copy2ddr();
401#endif
402 /* Frequency/Clock/CPU-IDLE */
403 } else if (in == 'i') {
404 ramdump_clock_calibration(0);
405 } else if (in == 'f') {
406 ramdump_clock_calibration(1);
407
408 } else if (in == 'j') {
409 pr_info("jiffies = %lu\n", jiffies);
410
411#ifdef CONFIG_INPUT_88PM80X_ONKEY
412 } else if (in == 'E') {
413 pr_info("OnKey DEBUG = EmptyEvent\n");
414 pm80x_onkey_cb_ret0_to_continue = ramdump_onkey_empty_evnt;
415 } else if (in == 'F') {
416 pr_info("OnKey DEBUG = Panic on First\n");
417 ramdump_onkey_panic_cntr = 0;
418 pm80x_onkey_cb_ret0_to_continue = ramdump_onkey_panic;
419 } else if (in == 'S') {
420 pr_info("OnKey DEBUG = Panic on Second\n");
421 ramdump_onkey_panic_cntr = 1;
422 pm80x_onkey_cb_ret0_to_continue = ramdump_onkey_panic;
423#endif
424
425 } else if ((in == 'g') || (in == 'u')) {
426 #define K_SIG_GUIDS_MAX 7 /*in signal.c, including 0=root */
427 int num, guid[K_SIG_GUIDS_MAX+1];
428 copy_left = copy_from_user(desc_buf, &buf[1], 79);
429 copy_done = 79 - copy_left;
430 desc_buf[79] = 0;
431 /* Set all entries to "-1", plus 1 extra to check input NUM */
432 memset(guid, 0xFF, sizeof(guid));
433 num = sscanf(desc_buf, "id=%d,%d,%d,%d,%d,%d,%d,%d",
434 &guid[0], &guid[1], &guid[2], &guid[3],
435 &guid[4], &guid[5], &guid[6], &guid[7]);
436 if ((num <= 0) || (num > K_SIG_GUIDS_MAX))
437 return -EIO;
438 if (k_signal_panic_guid_set((in == 'u'), guid, num) != num)
439 return -EIO;
440
441 } else if ((in >= '0') && (in <= '9')) {
442 ramdump_level = (unsigned)(in - '0');
443 ramdump_ignore_fatal_signals(0);/*level-check is inside*/
444
445 } else {
446 pr_info("ramdump_ctl: options\n"
447 " 0/1=e/d, p[anic], B[UG], a[dvance]\n"
448 " gid=1,2,3,4 or uid=1,2,3,4 set guid for panic on fatal-signals\n"
449 " j[iffies], i[IDLE], f[frequency]\n"
450 " c[crc check]\n"
451#ifdef CONFIG_INPUT_88PM80X_ONKEY
452 " OnKey: E[EmptyEvnt] F[FirstPanic] S[SecondPanic]\n"
453#endif
454 "\n");
455 return -EINVAL;
456 }
457 *f_pos = count;
458 return count;
459}
460
461static const struct file_operations ramdump_ctl_fops = {
462 .owner = THIS_MODULE,
463 .read = ramdump_ctl_read,
464 .write = ramdump_ctl_write,
465};
466
467static int __init ramdump_ctl_init(void)
468{
469 rdp_ts_init();
470 /* Create Register sysdbg-node (not a MISC) device */
471 return
472 sysdbg_cdev_create_register("ramdump_ctl", &ramdump_ctl_fops);
473}
474late_initcall(ramdump_ctl_init);
475
476
477
478/****************************************************************************
479 * RAMDUMP Devices are for System Debug ErrorHandling and Health Management
480 * Working MISC-Devices may be stack whilst working but RAMDUMP-devices
481 * must be always ok to guaranty system recovery and logging.
482 *
483 * Do not use MISC-Device for RAMDUMPs but use own
484 * Major-Node-Number for them. The devices are still "char"
485 */
486static int sysdbg_major;
487static int sysdbg_minor = -1;
488static char *sysdbg_class_name = (char*)"sysdbg";
489static struct class *sysdbg_class;
490
491static int sysdbg_cdev_create_register(const char *dev_name,
492 const struct file_operations *fops)
493{
494 struct cdev *cdev;
495 int err = 0;
496 dev_t dev = 0;
497 struct device *pdev;
498
499 if (!sysdbg_class)
500 sysdbg_class = class_create(THIS_MODULE, sysdbg_class_name);
501
502 sysdbg_minor++;
503
504 if (sysdbg_major) {
505 dev = MKDEV(sysdbg_major, sysdbg_minor);
506 err = register_chrdev_region(dev, 1, sysdbg_class_name);
507 } else {
508 err = alloc_chrdev_region(&dev, sysdbg_minor, 1, sysdbg_class_name);
509 sysdbg_major = MAJOR(dev);
510 }
511 if (err < 0) {
512 pr_err("%s:%s can't get major %d\n", sysdbg_class_name, dev_name,
513 sysdbg_major);
514 goto fail_1;
515 }
516 cdev = cdev_alloc();
517 if (!cdev) {
518 err = -ENOMEM;
519 goto fail_2;
520 }
521 dev = MKDEV(sysdbg_major, sysdbg_minor);
522 cdev->ops = fops;
523 cdev->owner = THIS_MODULE;
524 err = cdev_add(cdev, dev, 1);
525 if (!err) {
526 pdev = device_create(sysdbg_class, NULL, dev, NULL, dev_name);
527 if (pdev)
528 return 0;
529 }
530
531 /* ----- FAIL ------------------- */
532 /*device_destroy(sysdbg_class, devno) -- nothing to destroy*/
533 cdev_del(cdev);
534fail_2:
535 unregister_chrdev_region(dev, 1);
536 pr_err("%s:%s cdev err %d\n", sysdbg_class_name, dev_name, err);
537fail_1:
538 sysdbg_minor--;
539 /*class_destroy(sysdbg_class) - never destroy this class*/
540 return err;
541}
542
543/* GLOBAL alternator/wrappers */
544int sysdbg_misc_register(struct miscdevice * misc)
545{
546 return sysdbg_cdev_create_register(misc->name, misc->fops);
547}
548
549int sysdbg_misc_deregister(struct miscdevice * misc)
550{
551 pr_err("Class %s device %s shuld never be deleted\n",
552 sysdbg_class_name, misc->name);
553 return 0;
554}
555
556static int (*ramdump_seh_callback)(char *buf, int len);
557void ramdump_seh_callback_bind(void *send_msg_callback)
558{
559 ramdump_seh_callback = send_msg_callback;
560}
561EXPORT_SYMBOL(ramdump_seh_callback_bind);
562
563int ramdump_send_msg_to_seh (char *buf, int len)
564{
565 if (!ramdump_seh_callback)
566 return -1;
567 return /* num-sent bytes > 0 are valid */
568 ramdump_seh_callback(buf, len);
569}
570EXPORT_SYMBOL(ramdump_send_msg_to_seh);
571