aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2010-07-24 13:16:05 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-08-05 08:26:22 -0400
commit4c076fb41ac93bc0cbd55f2a731cc31337804acb (patch)
tree679bfb3a2177a9ffa9b07be44903f44418b84bd4 /drivers/watchdog
parent96ffa02d219f50a52e0482ad85130858c61efc63 (diff)
WATCHDOG: Add watchdog driver for OCTEON SOCs
The OCTEON is a MIPS64 based SOC family with an on chip watchdog unit. The driver is split into two source files one for the C code and one for assembly. Assembly is needed to handle the NMI and then print the machine state before the reboot is triggered. Signed-off-by: David Daney <ddaney@caviumnetworks.com> Cc: Wim Van Sebroeck <wim@iguana.be> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Russell King <rmk+kernel@arm.linux.org.uk> Cc: Tony Lindgren <tony@atomide.com> Cc: Marc Zyngier <maz@misterjones.org> Cc: Thierry Reding <thierry.reding@avionic-design.de> Cc: Sam Ravnborg <sam@ravnborg.org> To: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org, Patchwork: https://patchwork.linux-mips.org/patch/1503/ Signed-off-by: Wim Van Sebroeck <wim@iguana.be> Signed-off-by: Ralf Baechle <ralf@linux-mips.org> create mode 100644 drivers/watchdog/octeon-wdt-main.c create mode 100644 drivers/watchdog/octeon-wdt-nmi.S
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig18
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/octeon-wdt-main.c745
-rw-r--r--drivers/watchdog/octeon-wdt-nmi.S64
4 files changed, 829 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index afcfacc9bbe2..b04b18468932 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -875,6 +875,24 @@ config TXX9_WDT
875 help 875 help
876 Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. 876 Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
877 877
878config OCTEON_WDT
879 tristate "Cavium OCTEON SOC family Watchdog Timer"
880 depends on CPU_CAVIUM_OCTEON
881 default y
882 select EXPORT_UASM if OCTEON_WDT = m
883 help
884 Hardware driver for OCTEON's on chip watchdog timer.
885 Enables the watchdog for all cores running Linux. It
886 installs a NMI handler and pokes the watchdog based on an
887 interrupt. On first expiration of the watchdog, the
888 interrupt handler pokes it. The second expiration causes an
889 NMI that prints a message. The third expiration causes a
890 global soft reset.
891
892 When userspace has /dev/watchdog open, no poking is done
893 from the first interrupt, it is then only poked when the
894 device is written.
895
878# PARISC Architecture 896# PARISC Architecture
879 897
880# POWERPC Architecture 898# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 72f3e2073f8e..e30289a5e367 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -114,6 +114,8 @@ obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
114obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o 114obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
115obj-$(CONFIG_AR7_WDT) += ar7_wdt.o 115obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
116obj-$(CONFIG_TXX9_WDT) += txx9wdt.o 116obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
117obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
118octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
117 119
118# PARISC Architecture 120# PARISC Architecture
119 121
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
new file mode 100644
index 000000000000..2a410170eca6
--- /dev/null
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -0,0 +1,745 @@
1/*
2 * Octeon Watchdog driver
3 *
4 * Copyright (C) 2007, 2008, 2009, 2010 Cavium Networks
5 *
6 * Some parts derived from wdt.c
7 *
8 * (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
9 * All Rights Reserved.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
17 * warranty for any of this software. This material is provided
18 * "AS-IS" and at no charge.
19 *
20 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
21 *
22 * This file is subject to the terms and conditions of the GNU General Public
23 * License. See the file "COPYING" in the main directory of this archive
24 * for more details.
25 *
26 *
27 * The OCTEON watchdog has a maximum timeout of 2^32 * io_clock.
28 * For most systems this is less than 10 seconds, so to allow for
29 * software to request longer watchdog heartbeats, we maintain software
30 * counters to count multiples of the base rate. If the system locks
31 * up in such a manner that we can not run the software counters, the
32 * only result is a watchdog reset sooner than was requested. But
33 * that is OK, because in this case userspace would likely not be able
34 * to do anything anyhow.
35 *
36 * The hardware watchdog interval we call the period. The OCTEON
37 * watchdog goes through several stages, after the first period an
38 * irq is asserted, then if it is not reset, after the next period NMI
39 * is asserted, then after an additional period a chip wide soft reset.
40 * So for the software counters, we reset watchdog after each period
41 * and decrement the counter. But for the last two periods we need to
42 * let the watchdog progress to the NMI stage so we disable the irq
43 * and let it proceed. Once in the NMI, we print the register state
44 * to the serial port and then wait for the reset.
45 *
46 * A watchdog is maintained for each CPU in the system, that way if
47 * one CPU suffers a lockup, we also get a register dump and reset.
48 * The userspace ping resets the watchdog on all CPUs.
49 *
50 * Before userspace opens the watchdog device, we still run the
51 * watchdogs to catch any lockups that may be kernel related.
52 *
53 */
54
55#include <linux/miscdevice.h>
56#include <linux/interrupt.h>
57#include <linux/watchdog.h>
58#include <linux/cpumask.h>
59#include <linux/bitops.h>
60#include <linux/kernel.h>
61#include <linux/module.h>
62#include <linux/string.h>
63#include <linux/delay.h>
64#include <linux/cpu.h>
65#include <linux/smp.h>
66#include <linux/fs.h>
67
68#include <asm/mipsregs.h>
69#include <asm/uasm.h>
70
71#include <asm/octeon/octeon.h>
72
73/* The count needed to achieve timeout_sec. */
74static unsigned int timeout_cnt;
75
76/* The maximum period supported. */
77static unsigned int max_timeout_sec;
78
79/* The current period. */
80static unsigned int timeout_sec;
81
82/* Set to non-zero when userspace countdown mode active */
83static int do_coundown;
84static unsigned int countdown_reset;
85static unsigned int per_cpu_countdown[NR_CPUS];
86
87static cpumask_t irq_enabled_cpus;
88
89#define WD_TIMO 60 /* Default heartbeat = 60 seconds */
90
91static int heartbeat = WD_TIMO;
92module_param(heartbeat, int, S_IRUGO);
93MODULE_PARM_DESC(heartbeat,
94 "Watchdog heartbeat in seconds. (0 < heartbeat, default="
95 __MODULE_STRING(WD_TIMO) ")");
96
97static int nowayout = WATCHDOG_NOWAYOUT;
98module_param(nowayout, int, S_IRUGO);
99MODULE_PARM_DESC(nowayout,
100 "Watchdog cannot be stopped once started (default="
101 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
102
103static unsigned long octeon_wdt_is_open;
104static char expect_close;
105
106static u32 __initdata nmi_stage1_insns[64];
107/* We need one branch and therefore one relocation per target label. */
108static struct uasm_label __initdata labels[5];
109static struct uasm_reloc __initdata relocs[5];
110
111enum lable_id {
112 label_enter_bootloader = 1
113};
114
115/* Some CP0 registers */
116#define K0 26
117#define C0_CVMMEMCTL 11, 7
118#define C0_STATUS 12, 0
119#define C0_EBASE 15, 1
120#define C0_DESAVE 31, 0
121
122void octeon_wdt_nmi_stage2(void);
123
124static void __init octeon_wdt_build_stage1(void)
125{
126 int i;
127 int len;
128 u32 *p = nmi_stage1_insns;
129#ifdef CONFIG_HOTPLUG_CPU
130 struct uasm_label *l = labels;
131 struct uasm_reloc *r = relocs;
132#endif
133
134 /*
135 * For the next few instructions running the debugger may
136 * cause corruption of k0 in the saved registers. Since we're
137 * about to crash, nobody probably cares.
138 *
139 * Save K0 into the debug scratch register
140 */
141 uasm_i_dmtc0(&p, K0, C0_DESAVE);
142
143 uasm_i_mfc0(&p, K0, C0_STATUS);
144#ifdef CONFIG_HOTPLUG_CPU
145 uasm_il_bbit0(&p, &r, K0, ilog2(ST0_NMI), label_enter_bootloader);
146#endif
147 /* Force 64-bit addressing enabled */
148 uasm_i_ori(&p, K0, K0, ST0_UX | ST0_SX | ST0_KX);
149 uasm_i_mtc0(&p, K0, C0_STATUS);
150
151#ifdef CONFIG_HOTPLUG_CPU
152 uasm_i_mfc0(&p, K0, C0_EBASE);
153 /* Coreid number in K0 */
154 uasm_i_andi(&p, K0, K0, 0xf);
155 /* 8 * coreid in bits 16-31 */
156 uasm_i_dsll_safe(&p, K0, K0, 3 + 16);
157 uasm_i_ori(&p, K0, K0, 0x8001);
158 uasm_i_dsll_safe(&p, K0, K0, 16);
159 uasm_i_ori(&p, K0, K0, 0x0700);
160 uasm_i_drotr_safe(&p, K0, K0, 32);
161 /*
162 * Should result in: 0x8001,0700,0000,8*coreid which is
163 * CVMX_CIU_WDOGX(coreid) - 0x0500
164 *
165 * Now ld K0, CVMX_CIU_WDOGX(coreid)
166 */
167 uasm_i_ld(&p, K0, 0x500, K0);
168 /*
169 * If bit one set handle the NMI as a watchdog event.
170 * otherwise transfer control to bootloader.
171 */
172 uasm_il_bbit0(&p, &r, K0, 1, label_enter_bootloader);
173 uasm_i_nop(&p);
174#endif
175
176 /* Clear Dcache so cvmseg works right. */
177 uasm_i_cache(&p, 1, 0, 0);
178
179 /* Use K0 to do a read/modify/write of CVMMEMCTL */
180 uasm_i_dmfc0(&p, K0, C0_CVMMEMCTL);
181 /* Clear out the size of CVMSEG */
182 uasm_i_dins(&p, K0, 0, 0, 6);
183 /* Set CVMSEG to its largest value */
184 uasm_i_ori(&p, K0, K0, 0x1c0 | 54);
185 /* Store the CVMMEMCTL value */
186 uasm_i_dmtc0(&p, K0, C0_CVMMEMCTL);
187
188 /* Load the address of the second stage handler */
189 UASM_i_LA(&p, K0, (long)octeon_wdt_nmi_stage2);
190 uasm_i_jr(&p, K0);
191 uasm_i_dmfc0(&p, K0, C0_DESAVE);
192
193#ifdef CONFIG_HOTPLUG_CPU
194 uasm_build_label(&l, p, label_enter_bootloader);
195 /* Jump to the bootloader and restore K0 */
196 UASM_i_LA(&p, K0, (long)octeon_bootloader_entry_addr);
197 uasm_i_jr(&p, K0);
198 uasm_i_dmfc0(&p, K0, C0_DESAVE);
199#endif
200 uasm_resolve_relocs(relocs, labels);
201
202 len = (int)(p - nmi_stage1_insns);
203 pr_debug("Synthesized NMI stage 1 handler (%d instructions).\n", len);
204
205 pr_debug("\t.set push\n");
206 pr_debug("\t.set noreorder\n");
207 for (i = 0; i < len; i++)
208 pr_debug("\t.word 0x%08x\n", nmi_stage1_insns[i]);
209 pr_debug("\t.set pop\n");
210
211 if (len > 32)
212 panic("NMI stage 1 handler exceeds 32 instructions, was %d\n", len);
213}
214
215static int cpu2core(int cpu)
216{
217#ifdef CONFIG_SMP
218 return cpu_logical_map(cpu);
219#else
220 return cvmx_get_core_num();
221#endif
222}
223
224static int core2cpu(int coreid)
225{
226#ifdef CONFIG_SMP
227 return cpu_number_map(coreid);
228#else
229 return 0;
230#endif
231}
232
233/**
234 * Poke the watchdog when an interrupt is received
235 *
236 * @cpl:
237 * @dev_id:
238 *
239 * Returns
240 */
241static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
242{
243 unsigned int core = cvmx_get_core_num();
244 int cpu = core2cpu(core);
245
246 if (do_coundown) {
247 if (per_cpu_countdown[cpu] > 0) {
248 /* We're alive, poke the watchdog */
249 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
250 per_cpu_countdown[cpu]--;
251 } else {
252 /* Bad news, you are about to reboot. */
253 disable_irq_nosync(cpl);
254 cpumask_clear_cpu(cpu, &irq_enabled_cpus);
255 }
256 } else {
257 /* Not open, just ping away... */
258 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
259 }
260 return IRQ_HANDLED;
261}
262
263/* From setup.c */
264extern int prom_putchar(char c);
265
266/**
267 * Write a string to the uart
268 *
269 * @str: String to write
270 */
271static void octeon_wdt_write_string(const char *str)
272{
273 /* Just loop writing one byte at a time */
274 while (*str)
275 prom_putchar(*str++);
276}
277
278/**
279 * Write a hex number out of the uart
280 *
281 * @value: Number to display
282 * @digits: Number of digits to print (1 to 16)
283 */
284static void octeon_wdt_write_hex(u64 value, int digits)
285{
286 int d;
287 int v;
288 for (d = 0; d < digits; d++) {
289 v = (value >> ((digits - d - 1) * 4)) & 0xf;
290 if (v >= 10)
291 prom_putchar('a' + v - 10);
292 else
293 prom_putchar('0' + v);
294 }
295}
296
297const char *reg_name[] = {
298 "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
299 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
300 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
301 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
302};
303
304/**
305 * NMI stage 3 handler. NMIs are handled in the following manner:
306 * 1) The first NMI handler enables CVMSEG and transfers from
307 * the bootbus region into normal memory. It is careful to not
308 * destroy any registers.
309 * 2) The second stage handler uses CVMSEG to save the registers
310 * and create a stack for C code. It then calls the third level
311 * handler with one argument, a pointer to the register values.
312 * 3) The third, and final, level handler is the following C
313 * function that prints out some useful infomration.
314 *
315 * @reg: Pointer to register state before the NMI
316 */
317void octeon_wdt_nmi_stage3(u64 reg[32])
318{
319 u64 i;
320
321 unsigned int coreid = cvmx_get_core_num();
322 /*
323 * Save status and cause early to get them before any changes
324 * might happen.
325 */
326 u64 cp0_cause = read_c0_cause();
327 u64 cp0_status = read_c0_status();
328 u64 cp0_error_epc = read_c0_errorepc();
329 u64 cp0_epc = read_c0_epc();
330
331 /* Delay so output from all cores output is not jumbled together. */
332 __delay(100000000ull * coreid);
333
334 octeon_wdt_write_string("\r\n*** NMI Watchdog interrupt on Core 0x");
335 octeon_wdt_write_hex(coreid, 1);
336 octeon_wdt_write_string(" ***\r\n");
337 for (i = 0; i < 32; i++) {
338 octeon_wdt_write_string("\t");
339 octeon_wdt_write_string(reg_name[i]);
340 octeon_wdt_write_string("\t0x");
341 octeon_wdt_write_hex(reg[i], 16);
342 if (i & 1)
343 octeon_wdt_write_string("\r\n");
344 }
345 octeon_wdt_write_string("\terr_epc\t0x");
346 octeon_wdt_write_hex(cp0_error_epc, 16);
347
348 octeon_wdt_write_string("\tepc\t0x");
349 octeon_wdt_write_hex(cp0_epc, 16);
350 octeon_wdt_write_string("\r\n");
351
352 octeon_wdt_write_string("\tstatus\t0x");
353 octeon_wdt_write_hex(cp0_status, 16);
354 octeon_wdt_write_string("\tcause\t0x");
355 octeon_wdt_write_hex(cp0_cause, 16);
356 octeon_wdt_write_string("\r\n");
357
358 octeon_wdt_write_string("\tsum0\t0x");
359 octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
360 octeon_wdt_write_string("\ten0\t0x");
361 octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
362 octeon_wdt_write_string("\r\n");
363
364 octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
365}
366
367static void octeon_wdt_disable_interrupt(int cpu)
368{
369 unsigned int core;
370 unsigned int irq;
371 union cvmx_ciu_wdogx ciu_wdog;
372
373 core = cpu2core(cpu);
374
375 irq = OCTEON_IRQ_WDOG0 + core;
376
377 /* Poke the watchdog to clear out its state */
378 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
379
380 /* Disable the hardware. */
381 ciu_wdog.u64 = 0;
382 cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
383
384 free_irq(irq, octeon_wdt_poke_irq);
385}
386
387static void octeon_wdt_setup_interrupt(int cpu)
388{
389 unsigned int core;
390 unsigned int irq;
391 union cvmx_ciu_wdogx ciu_wdog;
392
393 core = cpu2core(cpu);
394
395 /* Disable it before doing anything with the interrupts. */
396 ciu_wdog.u64 = 0;
397 cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
398
399 per_cpu_countdown[cpu] = countdown_reset;
400
401 irq = OCTEON_IRQ_WDOG0 + core;
402
403 if (request_irq(irq, octeon_wdt_poke_irq,
404 IRQF_DISABLED, "octeon_wdt", octeon_wdt_poke_irq))
405 panic("octeon_wdt: Couldn't obtain irq %d", irq);
406
407 cpumask_set_cpu(cpu, &irq_enabled_cpus);
408
409 /* Poke the watchdog to clear out its state */
410 cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
411
412 /* Finally enable the watchdog now that all handlers are installed */
413 ciu_wdog.u64 = 0;
414 ciu_wdog.s.len = timeout_cnt;
415 ciu_wdog.s.mode = 3; /* 3 = Interrupt + NMI + Soft-Reset */
416 cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
417}
418
419static int octeon_wdt_cpu_callback(struct notifier_block *nfb,
420 unsigned long action, void *hcpu)
421{
422 unsigned int cpu = (unsigned long)hcpu;
423
424 switch (action) {
425 case CPU_DOWN_PREPARE:
426 octeon_wdt_disable_interrupt(cpu);
427 break;
428 case CPU_ONLINE:
429 case CPU_DOWN_FAILED:
430 octeon_wdt_setup_interrupt(cpu);
431 break;
432 default:
433 break;
434 }
435 return NOTIFY_OK;
436}
437
438static void octeon_wdt_ping(void)
439{
440 int cpu;
441 int coreid;
442
443 for_each_online_cpu(cpu) {
444 coreid = cpu2core(cpu);
445 cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
446 per_cpu_countdown[cpu] = countdown_reset;
447 if ((countdown_reset || !do_coundown) &&
448 !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
449 /* We have to enable the irq */
450 int irq = OCTEON_IRQ_WDOG0 + coreid;
451 enable_irq(irq);
452 cpumask_set_cpu(cpu, &irq_enabled_cpus);
453 }
454 }
455}
456
457static void octeon_wdt_calc_parameters(int t)
458{
459 unsigned int periods;
460
461 timeout_sec = max_timeout_sec;
462
463
464 /*
465 * Find the largest interrupt period, that can evenly divide
466 * the requested heartbeat time.
467 */
468 while ((t % timeout_sec) != 0)
469 timeout_sec--;
470
471 periods = t / timeout_sec;
472
473 /*
474 * The last two periods are after the irq is disabled, and
475 * then to the nmi, so we subtract them off.
476 */
477
478 countdown_reset = periods > 2 ? periods - 2 : 0;
479 heartbeat = t;
480 timeout_cnt = ((octeon_get_clock_rate() >> 8) * timeout_sec) >> 8;
481}
482
483static int octeon_wdt_set_heartbeat(int t)
484{
485 int cpu;
486 int coreid;
487 union cvmx_ciu_wdogx ciu_wdog;
488
489 if (t <= 0)
490 return -1;
491
492 octeon_wdt_calc_parameters(t);
493
494 for_each_online_cpu(cpu) {
495 coreid = cpu2core(cpu);
496 cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
497 ciu_wdog.u64 = 0;
498 ciu_wdog.s.len = timeout_cnt;
499 ciu_wdog.s.mode = 3; /* 3 = Interrupt + NMI + Soft-Reset */
500 cvmx_write_csr(CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
501 cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
502 }
503 octeon_wdt_ping(); /* Get the irqs back on. */
504 return 0;
505}
506
507/**
508 * octeon_wdt_write:
509 * @file: file handle to the watchdog
510 * @buf: buffer to write (unused as data does not matter here
511 * @count: count of bytes
512 * @ppos: pointer to the position to write. No seeks allowed
513 *
514 * A write to a watchdog device is defined as a keepalive signal. Any
515 * write of data will do, as we we don't define content meaning.
516 */
517
518static ssize_t octeon_wdt_write(struct file *file, const char __user *buf,
519 size_t count, loff_t *ppos)
520{
521 if (count) {
522 if (!nowayout) {
523 size_t i;
524
525 /* In case it was set long ago */
526 expect_close = 0;
527
528 for (i = 0; i != count; i++) {
529 char c;
530 if (get_user(c, buf + i))
531 return -EFAULT;
532 if (c == 'V')
533 expect_close = 1;
534 }
535 }
536 octeon_wdt_ping();
537 }
538 return count;
539}
540
541/**
542 * octeon_wdt_ioctl:
543 * @file: file handle to the device
544 * @cmd: watchdog command
545 * @arg: argument pointer
546 *
547 * The watchdog API defines a common set of functions for all
548 * watchdogs according to their available features. We only
549 * actually usefully support querying capabilities and setting
550 * the timeout.
551 */
552
553static long octeon_wdt_ioctl(struct file *file, unsigned int cmd,
554 unsigned long arg)
555{
556 void __user *argp = (void __user *)arg;
557 int __user *p = argp;
558 int new_heartbeat;
559
560 static struct watchdog_info ident = {
561 .options = WDIOF_SETTIMEOUT|
562 WDIOF_MAGICCLOSE|
563 WDIOF_KEEPALIVEPING,
564 .firmware_version = 1,
565 .identity = "OCTEON",
566 };
567
568 switch (cmd) {
569 case WDIOC_GETSUPPORT:
570 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
571 case WDIOC_GETSTATUS:
572 case WDIOC_GETBOOTSTATUS:
573 return put_user(0, p);
574 case WDIOC_KEEPALIVE:
575 octeon_wdt_ping();
576 return 0;
577 case WDIOC_SETTIMEOUT:
578 if (get_user(new_heartbeat, p))
579 return -EFAULT;
580 if (octeon_wdt_set_heartbeat(new_heartbeat))
581 return -EINVAL;
582 /* Fall through. */
583 case WDIOC_GETTIMEOUT:
584 return put_user(heartbeat, p);
585 default:
586 return -ENOTTY;
587 }
588}
589
590/**
591 * octeon_wdt_open:
592 * @inode: inode of device
593 * @file: file handle to device
594 *
595 * The watchdog device has been opened. The watchdog device is single
596 * open and on opening we do a ping to reset the counters.
597 */
598
599static int octeon_wdt_open(struct inode *inode, struct file *file)
600{
601 if (test_and_set_bit(0, &octeon_wdt_is_open))
602 return -EBUSY;
603 /*
604 * Activate
605 */
606 octeon_wdt_ping();
607 do_coundown = 1;
608 return nonseekable_open(inode, file);
609}
610
611/**
612 * octeon_wdt_release:
613 * @inode: inode to board
614 * @file: file handle to board
615 *
616 * The watchdog has a configurable API. There is a religious dispute
617 * between people who want their watchdog to be able to shut down and
618 * those who want to be sure if the watchdog manager dies the machine
619 * reboots. In the former case we disable the counters, in the latter
620 * case you have to open it again very soon.
621 */
622
623static int octeon_wdt_release(struct inode *inode, struct file *file)
624{
625 if (expect_close) {
626 do_coundown = 0;
627 octeon_wdt_ping();
628 } else {
629 pr_crit("octeon_wdt: WDT device closed unexpectedly. WDT will not stop!\n");
630 }
631 clear_bit(0, &octeon_wdt_is_open);
632 expect_close = 0;
633 return 0;
634}
635
636static const struct file_operations octeon_wdt_fops = {
637 .owner = THIS_MODULE,
638 .llseek = no_llseek,
639 .write = octeon_wdt_write,
640 .unlocked_ioctl = octeon_wdt_ioctl,
641 .open = octeon_wdt_open,
642 .release = octeon_wdt_release,
643};
644
645static struct miscdevice octeon_wdt_miscdev = {
646 .minor = WATCHDOG_MINOR,
647 .name = "watchdog",
648 .fops = &octeon_wdt_fops,
649};
650
651static struct notifier_block octeon_wdt_cpu_notifier = {
652 .notifier_call = octeon_wdt_cpu_callback,
653};
654
655
656/**
657 * Module/ driver initialization.
658 *
659 * Returns Zero on success
660 */
661static int __init octeon_wdt_init(void)
662{
663 int i;
664 int ret;
665 int cpu;
666 u64 *ptr;
667
668 /*
669 * Watchdog time expiration length = The 16 bits of LEN
670 * represent the most significant bits of a 24 bit decrementer
671 * that decrements every 256 cycles.
672 *
673 * Try for a timeout of 5 sec, if that fails a smaller number
674 * of even seconds,
675 */
676 max_timeout_sec = 6;
677 do {
678 max_timeout_sec--;
679 timeout_cnt = ((octeon_get_clock_rate() >> 8) * max_timeout_sec) >> 8;
680 } while (timeout_cnt > 65535);
681
682 BUG_ON(timeout_cnt == 0);
683
684 octeon_wdt_calc_parameters(heartbeat);
685
686 pr_info("octeon_wdt: Initial granularity %d Sec.\n", timeout_sec);
687
688 ret = misc_register(&octeon_wdt_miscdev);
689 if (ret) {
690 pr_err("octeon_wdt: cannot register miscdev on minor=%d (err=%d)\n",
691 WATCHDOG_MINOR, ret);
692 goto out;
693 }
694
695 /* Build the NMI handler ... */
696 octeon_wdt_build_stage1();
697
698 /* ... and install it. */
699 ptr = (u64 *) nmi_stage1_insns;
700 for (i = 0; i < 16; i++) {
701 cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
702 cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, ptr[i]);
703 }
704 cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000);
705
706 cpumask_clear(&irq_enabled_cpus);
707
708 for_each_online_cpu(cpu)
709 octeon_wdt_setup_interrupt(cpu);
710
711 register_hotcpu_notifier(&octeon_wdt_cpu_notifier);
712out:
713 return ret;
714}
715
716/**
717 * Module / driver shutdown
718 */
719static void __exit octeon_wdt_cleanup(void)
720{
721 int cpu;
722
723 misc_deregister(&octeon_wdt_miscdev);
724
725 unregister_hotcpu_notifier(&octeon_wdt_cpu_notifier);
726
727 for_each_online_cpu(cpu) {
728 int core = cpu2core(cpu);
729 /* Disable the watchdog */
730 cvmx_write_csr(CVMX_CIU_WDOGX(core), 0);
731 /* Free the interrupt handler */
732 free_irq(OCTEON_IRQ_WDOG0 + core, octeon_wdt_poke_irq);
733 }
734 /*
735 * Disable the boot-bus memory, the code it points to is soon
736 * to go missing.
737 */
738 cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0);
739}
740
741MODULE_LICENSE("GPL");
742MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
743MODULE_DESCRIPTION("Cavium Networks Octeon Watchdog driver.");
744module_init(octeon_wdt_init);
745module_exit(octeon_wdt_cleanup);
diff --git a/drivers/watchdog/octeon-wdt-nmi.S b/drivers/watchdog/octeon-wdt-nmi.S
new file mode 100644
index 000000000000..8a900a5e3233
--- /dev/null
+++ b/drivers/watchdog/octeon-wdt-nmi.S
@@ -0,0 +1,64 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2007 Cavium Networks
7 */
8#include <asm/asm.h>
9#include <asm/regdef.h>
10
11#define SAVE_REG(r) sd $r, -32768+6912-(32-r)*8($0)
12
13 NESTED(octeon_wdt_nmi_stage2, 0, sp)
14 .set push
15 .set noreorder
16 .set noat
17 /* Save all registers to the top CVMSEG. This shouldn't
18 * corrupt any state used by the kernel. Also all registers
19 * should have the value right before the NMI. */
20 SAVE_REG(0)
21 SAVE_REG(1)
22 SAVE_REG(2)
23 SAVE_REG(3)
24 SAVE_REG(4)
25 SAVE_REG(5)
26 SAVE_REG(6)
27 SAVE_REG(7)
28 SAVE_REG(8)
29 SAVE_REG(9)
30 SAVE_REG(10)
31 SAVE_REG(11)
32 SAVE_REG(12)
33 SAVE_REG(13)
34 SAVE_REG(14)
35 SAVE_REG(15)
36 SAVE_REG(16)
37 SAVE_REG(17)
38 SAVE_REG(18)
39 SAVE_REG(19)
40 SAVE_REG(20)
41 SAVE_REG(21)
42 SAVE_REG(22)
43 SAVE_REG(23)
44 SAVE_REG(24)
45 SAVE_REG(25)
46 SAVE_REG(26)
47 SAVE_REG(27)
48 SAVE_REG(28)
49 SAVE_REG(29)
50 SAVE_REG(30)
51 SAVE_REG(31)
52 /* Set the stack to begin right below the registers */
53 li sp, -32768+6912-32*8
54 /* Load the address of the third stage handler */
55 dla a0, octeon_wdt_nmi_stage3
56 /* Call the third stage handler */
57 jal a0
58 /* a0 is the address of the saved registers */
59 move a0, sp
60 /* Loop forvever if we get here. */
611: b 1b
62 nop
63 .set pop
64 END(octeon_wdt_nmi_stage2)