55 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
59 #include <linux/watchdog.h>
61 #include <linux/bitops.h>
62 #include <linux/kernel.h>
63 #include <linux/module.h>
64 #include <linux/string.h>
77 static unsigned int timeout_cnt;
80 static unsigned int max_timeout_sec;
83 static unsigned int timeout_sec;
86 static int do_coundown;
87 static unsigned int countdown_reset;
88 static unsigned int per_cpu_countdown[
NR_CPUS];
97 "Watchdog heartbeat in seconds. (0 < heartbeat, default="
103 "Watchdog cannot be stopped once started (default="
106 static unsigned long octeon_wdt_is_open;
120 #define C0_CVMMEMCTL 11, 7
121 #define C0_STATUS 12, 0
122 #define C0_EBASE 15, 1
123 #define C0_DESAVE 31, 0
127 static void __init octeon_wdt_build_stage1(
void)
131 u32 *
p = nmi_stage1_insns;
132 #ifdef CONFIG_HOTPLUG_CPU
147 #ifdef CONFIG_HOTPLUG_CPU
154 #ifdef CONFIG_HOTPLUG_CPU
157 uasm_i_andi(&p,
K0,
K0, 0xf);
159 uasm_i_dsll_safe(&p,
K0,
K0, 3 + 16);
160 uasm_i_ori(&p,
K0,
K0, 0x8001);
161 uasm_i_dsll_safe(&p,
K0,
K0, 16);
162 uasm_i_ori(&p,
K0,
K0, 0x0700);
163 uasm_i_drotr_safe(&p,
K0,
K0, 32);
170 uasm_i_ld(&p,
K0, 0x500,
K0);
180 uasm_i_cache(&p, 1, 0, 0);
185 uasm_i_dins(&p,
K0, 0, 0, 6);
187 uasm_i_ori(&p,
K0,
K0, 0x1c0 | 54);
196 #ifdef CONFIG_HOTPLUG_CPU
199 UASM_i_LA(&p,
K0, (
long)octeon_bootloader_entry_addr);
205 len = (
int)(p - nmi_stage1_insns);
206 pr_debug(
"Synthesized NMI stage 1 handler (%d instructions)\n", len);
210 for (i = 0; i < len; i++)
211 pr_debug(
"\t.word 0x%08x\n", nmi_stage1_insns[i]);
215 panic(
"NMI stage 1 handler exceeds 32 instructions, was %d\n", len);
218 static int cpu2core(
int cpu)
223 return cvmx_get_core_num();
227 static int core2cpu(
int coreid)
246 unsigned int core = cvmx_get_core_num();
247 int cpu = core2cpu(core);
250 if (per_cpu_countdown[cpu] > 0) {
252 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
253 per_cpu_countdown[
cpu]--;
257 cpumask_clear_cpu(cpu, &irq_enabled_cpus);
261 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
274 static void octeon_wdt_write_string(
const char *
str)
287 static void octeon_wdt_write_hex(
u64 value,
int digits)
291 for (d = 0; d < digits; d++) {
292 v = (value >> ((digits - d - 1) * 4)) & 0xf;
301 "$0",
"at",
"v0",
"v1",
"a0",
"a1",
"a2",
"a3",
302 "a4",
"a5",
"a6",
"a7",
"t0",
"t1",
"t2",
"t3",
303 "s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
304 "t8",
"t9",
"k0",
"k1",
"gp",
"sp",
"s8",
"ra"
324 unsigned int coreid = cvmx_get_core_num();
335 __delay(100000000ull * coreid);
337 octeon_wdt_write_string(
"\r\n*** NMI Watchdog interrupt on Core 0x");
338 octeon_wdt_write_hex(coreid, 1);
339 octeon_wdt_write_string(
" ***\r\n");
340 for (i = 0; i < 32; i++) {
341 octeon_wdt_write_string(
"\t");
342 octeon_wdt_write_string(reg_name[i]);
343 octeon_wdt_write_string(
"\t0x");
344 octeon_wdt_write_hex(reg[i], 16);
346 octeon_wdt_write_string(
"\r\n");
348 octeon_wdt_write_string(
"\terr_epc\t0x");
349 octeon_wdt_write_hex(cp0_error_epc, 16);
351 octeon_wdt_write_string(
"\tepc\t0x");
352 octeon_wdt_write_hex(cp0_epc, 16);
353 octeon_wdt_write_string(
"\r\n");
355 octeon_wdt_write_string(
"\tstatus\t0x");
356 octeon_wdt_write_hex(cp0_status, 16);
357 octeon_wdt_write_string(
"\tcause\t0x");
358 octeon_wdt_write_hex(cp0_cause, 16);
359 octeon_wdt_write_string(
"\r\n");
361 octeon_wdt_write_string(
"\tsum0\t0x");
363 octeon_wdt_write_string(
"\ten0\t0x");
365 octeon_wdt_write_string(
"\r\n");
367 octeon_wdt_write_string(
"*** Chip soft reset soon ***\r\n");
370 static void octeon_wdt_disable_interrupt(
int cpu)
376 core = cpu2core(cpu);
381 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
385 cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
390 static void octeon_wdt_setup_interrupt(
int cpu)
396 core = cpu2core(cpu);
400 cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
402 per_cpu_countdown[
cpu] = countdown_reset;
408 panic(
"octeon_wdt: Couldn't obtain irq %d", irq);
410 cpumask_set_cpu(cpu, &irq_enabled_cpus);
413 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
417 ciu_wdog.s.len = timeout_cnt;
419 cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
423 unsigned long action,
void *hcpu)
425 unsigned int cpu = (
unsigned long)hcpu;
429 octeon_wdt_disable_interrupt(cpu);
433 octeon_wdt_setup_interrupt(cpu);
441 static void octeon_wdt_ping(
void)
447 coreid = cpu2core(cpu);
448 cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
449 per_cpu_countdown[
cpu] = countdown_reset;
450 if ((countdown_reset || !do_coundown) &&
455 cpumask_set_cpu(cpu, &irq_enabled_cpus);
460 static void octeon_wdt_calc_parameters(
int t)
462 unsigned int periods;
464 timeout_sec = max_timeout_sec;
471 while ((t % timeout_sec) != 0)
474 periods = t / timeout_sec;
481 countdown_reset = periods > 2 ? periods - 2 : 0;
486 static int octeon_wdt_set_heartbeat(
int t)
495 octeon_wdt_calc_parameters(t);
498 coreid = cpu2core(cpu);
499 cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
501 ciu_wdog.s.len = timeout_cnt;
503 cvmx_write_csr(CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
504 cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
522 size_t count, loff_t *ppos)
531 for (i = 0; i !=
count; i++) {
556 static long octeon_wdt_ioctl(
struct file *file,
unsigned int cmd,
567 .firmware_version = 1,
568 .identity =
"OCTEON",
583 if (octeon_wdt_set_heartbeat(new_heartbeat))
602 static int octeon_wdt_open(
struct inode *
inode,
struct file *file)
626 static int octeon_wdt_release(
struct inode *inode,
struct file *file)
632 pr_crit(
"WDT device closed unexpectedly. WDT will not stop!\n");
642 .write = octeon_wdt_write,
643 .unlocked_ioctl = octeon_wdt_ioctl,
644 .open = octeon_wdt_open,
645 .release = octeon_wdt_release,
648 static struct miscdevice octeon_wdt_miscdev = {
651 .fops = &octeon_wdt_fops,
655 .notifier_call = octeon_wdt_cpu_callback,
664 static int __init octeon_wdt_init(
void)
683 }
while (timeout_cnt > 65535);
689 pr_info(
"Initial granularity %d Sec\n", timeout_sec);
693 pr_err(
"cannot register miscdev on minor=%d (err=%d)\n",
699 octeon_wdt_build_stage1();
702 ptr = (
u64 *) nmi_stage1_insns;
703 for (i = 0; i < 16; i++) {
709 cpumask_clear(&irq_enabled_cpus);
712 octeon_wdt_setup_interrupt(cpu);
722 static
void __exit octeon_wdt_cleanup(
void)
731 int core = cpu2core(cpu);
733 cvmx_write_csr(CVMX_CIU_WDOGX(core), 0);