aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-19 11:02:04 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-19 11:02:04 -0500
commit9ef38eaf4289a99beb3bc13d1ded220a68cc8877 (patch)
tree7c9a3cb302aa28efe1f1d5b794c4fe010f13e388 /drivers
parentcf91b824bb2bdea8a47bf6bb94cf3a438683e5eb (diff)
parent7f4da4745c34287938ce76b92b23409adeecb5b8 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: [WATCHDOG] HP ProLiant WatchDog driver [WATCHDOG] blackfin Watchdog driver: relocate all strings used in __init functions to __initdata [WATCHDOG] Convert mtx1 wdt to be a platform device and use generic GPIO API [WATCHDOG] Add support for SB1 hardware watchdog
Diffstat (limited to 'drivers')
-rw-r--r--drivers/watchdog/Kconfig25
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/bfin_wdt.c7
-rw-r--r--drivers/watchdog/hpwdt.c926
-rw-r--r--drivers/watchdog/mtx-1_wdt.c35
-rw-r--r--drivers/watchdog/sb_wdog.c353
6 files changed, 1340 insertions, 8 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index afcdc69e37d6..254d115cafab 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -402,6 +402,18 @@ config IT8712F_WDT
402 To compile this driver as a module, choose M here: the 402 To compile this driver as a module, choose M here: the
403 module will be called it8712f_wdt. 403 module will be called it8712f_wdt.
404 404
405config HP_WATCHDOG
406 tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
407 depends on X86
408 help
409 A software monitoring watchdog and NMI sourcing driver. This driver
410 will detect lockups and provide stack trace. Also, when an NMI
411 occurs this driver will make the necessary BIOS calls to log
412 the cause of the NMI. This is a driver that will only load on a
413 HP ProLiant system with a minimum of iLO2 support.
414 To compile this driver as a module, choose M here: the
415 module will be called hpwdt.
416
405config SC1200_WDT 417config SC1200_WDT
406 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" 418 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
407 depends on X86 419 depends on X86
@@ -633,6 +645,19 @@ config WDT_RM9K_GPI
633 To compile this driver as a module, choose M here: the 645 To compile this driver as a module, choose M here: the
634 module will be called rm9k_wdt. 646 module will be called rm9k_wdt.
635 647
648config SIBYTE_WDOG
649 tristate "Sibyte SoC hardware watchdog"
650 depends on CPU_SB1
651 help
652 Watchdog driver for the built in watchdog hardware in Sibyte
653 SoC processors. There are apparently two watchdog timers
654 on such processors; this driver supports only the first one,
655 because currently Linux only supports exporting one watchdog
656 to userspace.
657
658 To compile this driver as a loadable module, choose M here.
659 The module will be called sb_wdog.
660
636config AR7_WDT 661config AR7_WDT
637 tristate "TI AR7 Watchdog Timer" 662 tristate "TI AR7 Watchdog Timer"
638 depends on AR7 663 depends on AR7
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index ebc21146d40c..f3fb170fe5c6 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
67obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o 67obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
68obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o 68obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
69obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o 69obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
70obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
70obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o 71obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
71obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o 72obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
72obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o 73obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
@@ -92,6 +93,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
92obj-$(CONFIG_INDYDOG) += indydog.o 93obj-$(CONFIG_INDYDOG) += indydog.o
93obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o 94obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
94obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o 95obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
96obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
95obj-$(CONFIG_AR7_WDT) += ar7_wdt.o 97obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
96obj-$(CONFIG_TXX9_WDT) += txx9wdt.o 98obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
97 99
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 472be10f0686..1237113dc14a 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -29,6 +29,7 @@
29 29
30#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) 30#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
31#define stampit() stamp("here i am") 31#define stampit() stamp("here i am")
32#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
32 33
33#define WATCHDOG_NAME "bfin-wdt" 34#define WATCHDOG_NAME "bfin-wdt"
34#define PFX WATCHDOG_NAME ": " 35#define PFX WATCHDOG_NAME ": "
@@ -445,19 +446,19 @@ static int __init bfin_wdt_init(void)
445 446
446 ret = register_reboot_notifier(&bfin_wdt_notifier); 447 ret = register_reboot_notifier(&bfin_wdt_notifier);
447 if (ret) { 448 if (ret) {
448 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); 449 pr_init(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
449 return ret; 450 return ret;
450 } 451 }
451 452
452 ret = misc_register(&bfin_wdt_miscdev); 453 ret = misc_register(&bfin_wdt_miscdev);
453 if (ret) { 454 if (ret) {
454 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 455 pr_init(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
455 WATCHDOG_MINOR, ret); 456 WATCHDOG_MINOR, ret);
456 unregister_reboot_notifier(&bfin_wdt_notifier); 457 unregister_reboot_notifier(&bfin_wdt_notifier);
457 return ret; 458 return ret;
458 } 459 }
459 460
460 printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n", 461 pr_init(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
461 timeout, nowayout); 462 timeout, nowayout);
462 463
463 return 0; 464 return 0;
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
new file mode 100644
index 000000000000..a2e174b09fe7
--- /dev/null
+++ b/drivers/watchdog/hpwdt.c
@@ -0,0 +1,926 @@
1/*
2 * HP WatchDog Driver
3 * based on
4 *
5 * SoftDog 0.05: A Software Watchdog Device
6 *
7 * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
8 * Thomas Mingarelli <thomas.mingarelli@hp.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation
13 *
14 */
15
16#include <linux/device.h>
17#include <linux/fs.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/io.h>
21#include <linux/irq.h>
22#include <linux/kernel.h>
23#include <linux/miscdevice.h>
24#include <linux/mm.h>
25#include <linux/module.h>
26#include <linux/kdebug.h>
27#include <linux/moduleparam.h>
28#include <linux/notifier.h>
29#include <linux/pci.h>
30#include <linux/pci_ids.h>
31#include <linux/reboot.h>
32#include <linux/sched.h>
33#include <linux/timer.h>
34#include <linux/types.h>
35#include <linux/uaccess.h>
36#include <linux/watchdog.h>
37#include <linux/dmi.h>
38#include <linux/efi.h>
39#include <linux/string.h>
40#include <linux/bootmem.h>
41#include <linux/slab.h>
42#include <asm/dmi.h>
43#include <asm/desc.h>
44#include <asm/kdebug.h>
45
46#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */
47#define CRU_BIOS_SIGNATURE_VALUE 0x55524324
48#define PCI_BIOS32_PARAGRAPH_LEN 16
49#define PCI_ROM_BASE1 0x000F0000
50#define ROM_SIZE 0x10000
51
52struct bios32_service_dir {
53 u32 signature;
54 u32 entry_point;
55 u8 revision;
56 u8 length;
57 u8 checksum;
58 u8 reserved[5];
59};
60
61/*
62 * smbios_entry_point - defines SMBIOS entry point structure
63 *
64 * anchor[4] - anchor string (_SM_)
65 * checksum - checksum of the entry point structure
66 * length - length of the entry point structure
67 * major_ver - major version (02h for revision 2.1)
68 * minor_ver - minor version (01h for revision 2.1)
69 * max_struct_size - size of the largest SMBIOS structure
70 * revision - entry point structure revision implemented
71 * formatted_area[5] - reserved
72 * intermediate_anchor[5] - intermediate anchor string (_DMI_)
73 * intermediate_checksum - intermediate checksum
74 * table_length - structure table length
75 * table_address - structure table address
76 * table_num_structs - number of SMBIOS structures present
77 * bcd_revision - BCD revision
78 */
79struct smbios_entry_point {
80 u8 anchor[4];
81 u8 checksum;
82 u8 length;
83 u8 major_ver;
84 u8 minor_ver;
85 u16 max_struct_size;
86 u8 revision;
87 u8 formatted_area[5];
88 u8 intermediate_anchor[5];
89 u8 intermediate_checksum;
90 u16 table_length;
91 u64 table_address;
92 u16 table_num_structs;
93 u8 bcd_revision;
94};
95
96/* type 212 */
97struct smbios_cru64_info {
98 u8 type;
99 u8 byte_length;
100 u16 handle;
101 u32 signature;
102 u64 physical_address;
103 u32 double_length;
104 u32 double_offset;
105};
106#define SMBIOS_CRU64_INFORMATION 212
107
108struct cmn_registers {
109 union {
110 struct {
111 u8 ral;
112 u8 rah;
113 u16 rea2;
114 };
115 u32 reax;
116 } u1;
117 union {
118 struct {
119 u8 rbl;
120 u8 rbh;
121 u8 reb2l;
122 u8 reb2h;
123 };
124 u32 rebx;
125 } u2;
126 union {
127 struct {
128 u8 rcl;
129 u8 rch;
130 u16 rec2;
131 };
132 u32 recx;
133 } u3;
134 union {
135 struct {
136 u8 rdl;
137 u8 rdh;
138 u16 red2;
139 };
140 u32 redx;
141 } u4;
142
143 u32 resi;
144 u32 redi;
145 u16 rds;
146 u16 res;
147 u32 reflags;
148} __attribute__((packed));
149
150#define DEFAULT_MARGIN 30
151static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */
152static unsigned int reload; /* the computed soft_margin */
153static int nowayout = WATCHDOG_NOWAYOUT;
154static char expect_release;
155static unsigned long hpwdt_is_open;
156
157static void __iomem *pci_mem_addr; /* the PCI-memory address */
158static unsigned long __iomem *hpwdt_timer_reg;
159static unsigned long __iomem *hpwdt_timer_con;
160
161static DEFINE_SPINLOCK(rom_lock);
162
163static void *cru_rom_addr;
164
165static struct cmn_registers cmn_regs;
166
167static struct pci_device_id hpwdt_devices[] = {
168 {
169 .vendor = PCI_VENDOR_ID_COMPAQ,
170 .device = 0xB203,
171 .subvendor = PCI_ANY_ID,
172 .subdevice = PCI_ANY_ID,
173 },
174 {0}, /* terminate list */
175};
176MODULE_DEVICE_TABLE(pci, hpwdt_devices);
177
178/*
179 * bios_checksum
180 */
181static int __devinit bios_checksum(const char __iomem *ptr, int len)
182{
183 char sum = 0;
184 int i;
185
186 /*
187 * calculate checksum of size bytes. This should add up
188 * to zero if we have a valid header.
189 */
190 for (i = 0; i < len; i++)
191 sum += ptr[i];
192
193 return ((sum == 0) && (len > 0));
194}
195
196#ifndef CONFIG_X86_64
197/* --32 Bit Bios------------------------------------------------------------ */
198
199#define HPWDT_ARCH 32
200
201asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
202 unsigned long *pRomEntry)
203{
204 asm("pushl %ebp \n\t"
205 "movl %esp, %ebp \n\t"
206 "pusha \n\t"
207 "pushf \n\t"
208 "push %es \n\t"
209 "push %ds \n\t"
210 "pop %es \n\t"
211 "movl 8(%ebp),%eax \n\t"
212 "movl 4(%eax),%ebx \n\t"
213 "movl 8(%eax),%ecx \n\t"
214 "movl 12(%eax),%edx \n\t"
215 "movl 16(%eax),%esi \n\t"
216 "movl 20(%eax),%edi \n\t"
217 "movl (%eax),%eax \n\t"
218 "push %cs \n\t"
219 "call *12(%ebp) \n\t"
220 "pushf \n\t"
221 "pushl %eax \n\t"
222 "movl 8(%ebp),%eax \n\t"
223 "movl %ebx,4(%eax) \n\t"
224 "movl %ecx,8(%eax) \n\t"
225 "movl %edx,12(%eax) \n\t"
226 "movl %esi,16(%eax) \n\t"
227 "movl %edi,20(%eax) \n\t"
228 "movw %ds,24(%eax) \n\t"
229 "movw %es,26(%eax) \n\t"
230 "popl %ebx \n\t"
231 "movl %ebx,(%eax) \n\t"
232 "popl %ebx \n\t"
233 "movl %ebx,28(%eax) \n\t"
234 "pop %es \n\t"
235 "popf \n\t"
236 "popa \n\t"
237 "leave \n\t" "ret");
238}
239
240/*
241 * cru_detect
242 *
243 * Routine Description:
244 * This function uses the 32-bit BIOS Service Directory record to
245 * search for a $CRU record.
246 *
247 * Return Value:
248 * 0 : SUCCESS
249 * <0 : FAILURE
250 */
251static int __devinit cru_detect(unsigned long map_entry,
252 unsigned long map_offset)
253{
254 void *bios32_map;
255 unsigned long *bios32_entrypoint;
256 unsigned long cru_physical_address;
257 unsigned long cru_length;
258 unsigned long physical_bios_base = 0;
259 unsigned long physical_bios_offset = 0;
260 int retval = -ENODEV;
261
262 bios32_map = ioremap(map_entry, (2 * PAGE_SIZE));
263
264 if (bios32_map == NULL)
265 return -ENODEV;
266
267 bios32_entrypoint = bios32_map + map_offset;
268
269 cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE;
270
271 asminline_call(&cmn_regs, bios32_entrypoint);
272
273 if (cmn_regs.u1.ral != 0) {
274 printk(KERN_WARNING
275 "hpwdt: Call succeeded but with an error: 0x%x\n",
276 cmn_regs.u1.ral);
277 } else {
278 physical_bios_base = cmn_regs.u2.rebx;
279 physical_bios_offset = cmn_regs.u4.redx;
280 cru_length = cmn_regs.u3.recx;
281 cru_physical_address =
282 physical_bios_base + physical_bios_offset;
283
284 /* If the values look OK, then map it in. */
285 if ((physical_bios_base + physical_bios_offset)) {
286 cru_rom_addr =
287 ioremap(cru_physical_address, cru_length);
288 if (cru_rom_addr)
289 retval = 0;
290 }
291
292 printk(KERN_DEBUG "hpwdt: CRU Base Address: 0x%lx\n",
293 physical_bios_base);
294 printk(KERN_DEBUG "hpwdt: CRU Offset Address: 0x%lx\n",
295 physical_bios_offset);
296 printk(KERN_DEBUG "hpwdt: CRU Length: 0x%lx\n",
297 cru_length);
298 printk(KERN_DEBUG "hpwdt: CRU Mapped Address: 0x%x\n",
299 (unsigned int)&cru_rom_addr);
300 }
301 iounmap(bios32_map);
302 return retval;
303}
304
305/*
306 * bios32_present
307 *
308 * Routine Description:
309 * This function finds the 32-bit BIOS Service Directory
310 *
311 * Return Value:
312 * 0 : SUCCESS
313 * <0 : FAILURE
314 */
315static int __devinit bios32_present(const char __iomem *p)
316{
317 struct bios32_service_dir *bios_32_ptr;
318 int length;
319 unsigned long map_entry, map_offset;
320
321 bios_32_ptr = (struct bios32_service_dir *) p;
322
323 /*
324 * Search for signature by checking equal to the swizzled value
325 * instead of calling another routine to perform a strcmp.
326 */
327 if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) {
328 length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN;
329 if (bios_checksum(p, length)) {
330 /*
331 * According to the spec, we're looking for the
332 * first 4KB-aligned address below the entrypoint
333 * listed in the header. The Service Directory code
334 * is guaranteed to occupy no more than 2 4KB pages.
335 */
336 map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1);
337 map_offset = bios_32_ptr->entry_point - map_entry;
338
339 return cru_detect(map_entry, map_offset);
340 }
341 }
342 return -ENODEV;
343}
344
345static int __devinit detect_cru_service(void)
346{
347 char __iomem *p, *q;
348 int rc = -1;
349
350 /*
351 * Search from 0x0f0000 through 0x0fffff, inclusive.
352 */
353 p = ioremap(PCI_ROM_BASE1, ROM_SIZE);
354 if (p == NULL)
355 return -ENOMEM;
356
357 for (q = p; q < p + ROM_SIZE; q += 16) {
358 rc = bios32_present(q);
359 if (!rc)
360 break;
361 }
362 iounmap(p);
363 return rc;
364}
365
366#else
367/* --64 Bit Bios------------------------------------------------------------ */
368
369#define HPWDT_ARCH 64
370
371asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
372 unsigned long *pRomEntry)
373{
374 asm("pushq %rbp \n\t"
375 "movq %rsp, %rbp \n\t"
376 "pushq %rax \n\t"
377 "pushq %rbx \n\t"
378 "pushq %rdx \n\t"
379 "pushq %r12 \n\t"
380 "pushq %r9 \n\t"
381 "movq %rsi, %r12 \n\t"
382 "movq %rdi, %r9 \n\t"
383 "movl 4(%r9),%ebx \n\t"
384 "movl 8(%r9),%ecx \n\t"
385 "movl 12(%r9),%edx \n\t"
386 "movl 16(%r9),%esi \n\t"
387 "movl 20(%r9),%edi \n\t"
388 "movl (%r9),%eax \n\t"
389 "call *%r12 \n\t"
390 "pushfq \n\t"
391 "popq %r12 \n\t"
392 "popfq \n\t"
393 "movl %eax, (%r9) \n\t"
394 "movl %ebx, 4(%r9) \n\t"
395 "movl %ecx, 8(%r9) \n\t"
396 "movl %edx, 12(%r9) \n\t"
397 "movl %esi, 16(%r9) \n\t"
398 "movl %edi, 20(%r9) \n\t"
399 "movq %r12, %rax \n\t"
400 "movl %eax, 28(%r9) \n\t"
401 "popq %r9 \n\t"
402 "popq %r12 \n\t"
403 "popq %rdx \n\t"
404 "popq %rbx \n\t"
405 "popq %rax \n\t"
406 "leave \n\t" "ret");
407}
408
409/*
410 * dmi_find_cru
411 *
412 * Routine Description:
413 * This function checks wether or not a SMBIOS/DMI record is
414 * the 64bit CRU info or not
415 *
416 * Return Value:
417 * 0 : SUCCESS - if record found
418 * <0 : FAILURE - if record not found
419 */
420static void __devinit dmi_find_cru(const struct dmi_header *dm)
421{
422 struct smbios_cru64_info *smbios_cru64_ptr;
423 unsigned long cru_physical_address;
424
425 if (dm->type == SMBIOS_CRU64_INFORMATION) {
426 smbios_cru64_ptr = (struct smbios_cru64_info *) dm;
427 if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) {
428 cru_physical_address =
429 smbios_cru64_ptr->physical_address +
430 smbios_cru64_ptr->double_offset;
431 cru_rom_addr = ioremap(cru_physical_address,
432 smbios_cru64_ptr->double_length);
433 }
434 }
435}
436
437/*
438 * dmi_table
439 *
440 * Routine Description:
441 * Decode the SMBIOS/DMI table and check if we have a 64bit CRU record
442 * or not.
443 *
444 * We have to be cautious here. We have seen BIOSes with DMI pointers
445 * pointing to completely the wrong place for example
446 */
447static void __devinit dmi_table(u8 *buf, int len, int num,
448 void (*decode)(const struct dmi_header *))
449{
450 u8 *data = buf;
451 int i = 0;
452
453 /*
454 * Stop when we see all the items the table claimed to have
455 * OR we run off the end of the table (also happens)
456 */
457 while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
458 const struct dmi_header *dm = (const struct dmi_header *)data;
459
460 /*
461 * We want to know the total length (formated area and strings)
462 * before decoding to make sure we won't run off the table in
463 * dmi_decode or dmi_string
464 */
465 data += dm->length;
466 while ((data - buf < len - 1) && (data[0] || data[1]))
467 data++;
468 if (data - buf < len - 1)
469 decode(dm);
470 data += 2;
471 i++;
472 }
473}
474
475/*
476 * smbios_present
477 *
478 * Routine Description:
479 * This function parses the SMBIOS entry point table to retrieve
480 * the 64 bit CRU Service.
481 *
482 * Return Value:
483 * 0 : SUCCESS
484 * <0 : FAILURE
485 */
486static int __devinit smbios_present(const char __iomem *p)
487{
488 struct smbios_entry_point *eps =
489 (struct smbios_entry_point *) p;
490 int length;
491 u8 *buf;
492
493 /* check if we have indeed the SMBIOS table entry point */
494 if ((strncmp((char *)eps->anchor, "_SM_",
495 sizeof(eps->anchor))) == 0) {
496 length = eps->length;
497
498 /* SMBIOS v2.1 implementation might use 0x1e */
499 if ((length == 0x1e) &&
500 (eps->major_ver == 2) &&
501 (eps->minor_ver == 1))
502 length = 0x1f;
503
504 /*
505 * Now we will check:
506 * - SMBIOS checksum must be 0
507 * - intermediate anchor should be _DMI_
508 * - intermediate checksum should be 0
509 */
510 if ((bios_checksum(p, length)) &&
511 (strncmp((char *)eps->intermediate_anchor, "_DMI_",
512 sizeof(eps->intermediate_anchor)) == 0) &&
513 (bios_checksum(p+0x10, 15))) {
514 buf = ioremap(eps->table_address, eps->table_length);
515 if (buf == NULL)
516 return -ENODEV;
517
518
519 /* Scan the DMI table for the 64 bit CRU service */
520 dmi_table(buf, eps->table_length,
521 eps->table_num_structs, dmi_find_cru);
522
523 iounmap(buf);
524 return 0;
525 }
526 }
527
528 return -ENODEV;
529}
530
531static int __devinit smbios_scan_machine(void)
532{
533 char __iomem *p, *q;
534 int rc;
535
536 if (efi_enabled) {
537 if (efi.smbios == EFI_INVALID_TABLE_ADDR)
538 return -ENODEV;
539
540 p = ioremap(efi.smbios, 32);
541 if (p == NULL)
542 return -ENOMEM;
543
544 rc = smbios_present(p);
545 iounmap(p);
546 } else {
547 /*
548 * Search from 0x0f0000 through 0x0fffff, inclusive.
549 */
550 p = ioremap(PCI_ROM_BASE1, ROM_SIZE);
551 if (p == NULL)
552 return -ENOMEM;
553
554 for (q = p; q < p + ROM_SIZE; q += 16) {
555 rc = smbios_present(q);
556 if (!rc) {
557 break;
558 }
559 }
560 iounmap(p);
561 }
562}
563
564static int __devinit detect_cru_service(void)
565{
566 cru_rom_addr = NULL;
567
568 smbios_scan_machine(); /* will become dmi_walk(dmi_find_cru); */
569
570 /* if cru_rom_addr has been set then we found a CRU service */
571 return ((cru_rom_addr != NULL)? 0: -ENODEV);
572}
573
574/* ------------------------------------------------------------------------- */
575
576#endif
577
578/*
579 * NMI Handler
580 */
581static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
582 void *data)
583{
584 static unsigned long rom_pl;
585 static int die_nmi_called;
586
587 if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI)
588 return NOTIFY_OK;
589
590 spin_lock_irqsave(&rom_lock, rom_pl);
591 if (!die_nmi_called)
592 asminline_call(&cmn_regs, cru_rom_addr);
593 die_nmi_called = 1;
594 spin_unlock_irqrestore(&rom_lock, rom_pl);
595 if (cmn_regs.u1.ral == 0) {
596 printk(KERN_WARNING "hpwdt: An NMI occurred, "
597 "but unable to determine source.\n");
598 } else {
599 panic("An NMI occurred, please see the Integrated "
600 "Management Log for details.\n");
601 }
602
603 return NOTIFY_STOP;
604}
605
606/*
607 * Watchdog operations
608 */
609static void hpwdt_start(void)
610{
611 reload = (soft_margin * 1000) / 128;
612 iowrite16(reload, hpwdt_timer_reg);
613 iowrite16(0x85, hpwdt_timer_con);
614}
615
616static void hpwdt_stop(void)
617{
618 unsigned long data;
619
620 data = ioread16(hpwdt_timer_con);
621 data &= 0xFE;
622 iowrite16(data, hpwdt_timer_con);
623}
624
625static void hpwdt_ping(void)
626{
627 iowrite16(reload, hpwdt_timer_reg);
628}
629
630static int hpwdt_change_timer(int new_margin)
631{
632 /* Arbitrary, can't find the card's limits */
633 if (new_margin < 30 || new_margin > 600) {
634 printk(KERN_WARNING
635 "hpwdt: New value passed in is invalid: %d seconds.\n",
636 new_margin);
637 return -EINVAL;
638 }
639
640 soft_margin = new_margin;
641 printk(KERN_DEBUG
642 "hpwdt: New timer passed in is %d seconds.\n",
643 new_margin);
644 reload = (soft_margin * 1000) / 128;
645
646 return 0;
647}
648
649/*
650 * /dev/watchdog handling
651 */
652static int hpwdt_open(struct inode *inode, struct file *file)
653{
654 /* /dev/watchdog can only be opened once */
655 if (test_and_set_bit(0, &hpwdt_is_open))
656 return -EBUSY;
657
658 /* Start the watchdog */
659 hpwdt_start();
660 hpwdt_ping();
661
662 return nonseekable_open(inode, file);
663}
664
665static int hpwdt_release(struct inode *inode, struct file *file)
666{
667 /* Stop the watchdog */
668 if (expect_release == 42) {
669 hpwdt_stop();
670 } else {
671 printk(KERN_CRIT
672 "hpwdt: Unexpected close, not stopping watchdog!\n");
673 hpwdt_ping();
674 }
675
676 expect_release = 0;
677
678 /* /dev/watchdog is being closed, make sure it can be re-opened */
679 clear_bit(0, &hpwdt_is_open);
680
681 return 0;
682}
683
684static ssize_t hpwdt_write(struct file *file, const char __user *data,
685 size_t len, loff_t *ppos)
686{
687 /* See if we got the magic character 'V' and reload the timer */
688 if (len) {
689 if (!nowayout) {
690 size_t i;
691
692 /* note: just in case someone wrote the magic character
693 * five months ago... */
694 expect_release = 0;
695
696 /* scan to see whether or not we got the magic char. */
697 for (i = 0; i != len; i++) {
698 char c;
699 if (get_user(c, data+i))
700 return -EFAULT;
701 if (c == 'V')
702 expect_release = 42;
703 }
704 }
705
706 /* someone wrote to us, we should reload the timer */
707 hpwdt_ping();
708 }
709
710 return len;
711}
712
713static struct watchdog_info ident = {
714 .options = WDIOF_SETTIMEOUT |
715 WDIOF_KEEPALIVEPING |
716 WDIOF_MAGICCLOSE,
717 .identity = "HP iLO2 HW Watchdog Timer",
718};
719
720static long hpwdt_ioctl(struct file *file, unsigned int cmd,
721 unsigned long arg)
722{
723 void __user *argp = (void __user *)arg;
724 int __user *p = argp;
725 int new_margin;
726 int ret = -ENOTTY;
727
728 switch (cmd) {
729 case WDIOC_GETSUPPORT:
730 ret = 0;
731 if (copy_to_user(argp, &ident, sizeof(ident)))
732 ret = -EFAULT;
733 break;
734
735 case WDIOC_GETSTATUS:
736 case WDIOC_GETBOOTSTATUS:
737 ret = put_user(0, p);
738 break;
739
740 case WDIOC_KEEPALIVE:
741 hpwdt_ping();
742 ret = 0;
743 break;
744
745 case WDIOC_SETTIMEOUT:
746 ret = get_user(new_margin, p);
747 if (ret)
748 break;
749
750 ret = hpwdt_change_timer(new_margin);
751 if (ret)
752 break;
753
754 hpwdt_ping();
755 /* Fall */
756 case WDIOC_GETTIMEOUT:
757 ret = put_user(soft_margin, p);
758 break;
759 }
760 return ret;
761}
762
763/*
764 * Kernel interfaces
765 */
766static struct file_operations hpwdt_fops = {
767 .owner = THIS_MODULE,
768 .llseek = no_llseek,
769 .write = hpwdt_write,
770 .unlocked_ioctl = hpwdt_ioctl,
771 .open = hpwdt_open,
772 .release = hpwdt_release,
773};
774
775static struct miscdevice hpwdt_miscdev = {
776 .minor = WATCHDOG_MINOR,
777 .name = "watchdog",
778 .fops = &hpwdt_fops,
779};
780
781static struct notifier_block die_notifier = {
782 .notifier_call = hpwdt_pretimeout,
783 .priority = 0x7FFFFFFF,
784};
785
786/*
787 * Init & Exit
788 */
789
790static int __devinit hpwdt_init_one(struct pci_dev *dev,
791 const struct pci_device_id *ent)
792{
793 int retval;
794
795 /*
796 * First let's find out if we are on an iLO2 server. We will
797 * not run on a legacy ASM box.
798 */
799 if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) {
800 dev_warn(&dev->dev,
801 "This server does not have an iLO2 ASIC.\n");
802 return -ENODEV;
803 }
804
805 if (pci_enable_device(dev)) {
806 dev_warn(&dev->dev,
807 "Not possible to enable PCI Device: 0x%x:0x%x.\n",
808 ent->vendor, ent->device);
809 return -ENODEV;
810 }
811
812 pci_mem_addr = pci_iomap(dev, 1, 0x80);
813 if (!pci_mem_addr) {
814 dev_warn(&dev->dev,
815 "Unable to detect the iLO2 server memory.\n");
816 retval = -ENOMEM;
817 goto error_pci_iomap;
818 }
819 hpwdt_timer_reg = pci_mem_addr + 0x70;
820 hpwdt_timer_con = pci_mem_addr + 0x72;
821
822 /* Make sure that we have a valid soft_margin */
823 if (hpwdt_change_timer(soft_margin))
824 hpwdt_change_timer(DEFAULT_MARGIN);
825
826 /*
827 * We need to map the ROM to get the CRU service.
828 * For 32 bit Operating Systems we need to go through the 32 Bit
829 * BIOS Service Directory
830 * For 64 bit Operating Systems we get that service through SMBIOS.
831 */
832 retval = detect_cru_service();
833 if (retval < 0) {
834 dev_warn(&dev->dev,
835 "Unable to detect the %d Bit CRU Service.\n",
836 HPWDT_ARCH);
837 goto error_get_cru;
838 }
839
840 /*
841 * We know this is the only CRU call we need to make so lets keep as
842 * few instructions as possible once the NMI comes in.
843 */
844 cmn_regs.u1.rah = 0x0D;
845 cmn_regs.u1.ral = 0x02;
846
847 retval = register_die_notifier(&die_notifier);
848 if (retval != 0) {
849 dev_warn(&dev->dev,
850 "Unable to register a die notifier (err=%d).\n",
851 retval);
852 goto error_die_notifier;
853 }
854
855 retval = misc_register(&hpwdt_miscdev);
856 if (retval < 0) {
857 dev_warn(&dev->dev,
858 "Unable to register miscdev on minor=%d (err=%d).\n",
859 WATCHDOG_MINOR, retval);
860 goto error_misc_register;
861 }
862
863 printk(KERN_INFO
864 "hp Watchdog Timer Driver: 1.00"
865 ", timer margin: %d seconds( nowayout=%d).\n",
866 soft_margin, nowayout);
867
868 return 0;
869
870error_misc_register:
871 unregister_die_notifier(&die_notifier);
872error_die_notifier:
873 if (cru_rom_addr)
874 iounmap(cru_rom_addr);
875error_get_cru:
876 pci_iounmap(dev, pci_mem_addr);
877error_pci_iomap:
878 pci_disable_device(dev);
879 return retval;
880}
881
882static void __devexit hpwdt_exit(struct pci_dev *dev)
883{
884 if (!nowayout)
885 hpwdt_stop();
886
887 misc_deregister(&hpwdt_miscdev);
888 unregister_die_notifier(&die_notifier);
889
890 if (cru_rom_addr)
891 iounmap(cru_rom_addr);
892 pci_iounmap(dev, pci_mem_addr);
893 pci_disable_device(dev);
894}
895
896static struct pci_driver hpwdt_driver = {
897 .name = "hpwdt",
898 .id_table = hpwdt_devices,
899 .probe = hpwdt_init_one,
900 .remove = __devexit_p(hpwdt_exit),
901};
902
903static void __exit hpwdt_cleanup(void)
904{
905 pci_unregister_driver(&hpwdt_driver);
906}
907
908static int __init hpwdt_init(void)
909{
910 return pci_register_driver(&hpwdt_driver);
911}
912
913MODULE_AUTHOR("Tom Mingarelli");
914MODULE_DESCRIPTION("hp watchdog driver");
915MODULE_LICENSE("GPL");
916MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
917
918module_param(soft_margin, int, 0);
919MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
920
921module_param(nowayout, int, 0);
922MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
923 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
924
925module_init(hpwdt_init);
926module_exit(hpwdt_cleanup);
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index 98451747d3cd..789831b3fa00 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -45,10 +45,13 @@
45#include <linux/completion.h> 45#include <linux/completion.h>
46#include <linux/jiffies.h> 46#include <linux/jiffies.h>
47#include <linux/watchdog.h> 47#include <linux/watchdog.h>
48#include <linux/platform_device.h>
49
48#include <asm/io.h> 50#include <asm/io.h>
49#include <asm/uaccess.h> 51#include <asm/uaccess.h>
50 52
51#include <asm/mach-au1x00/au1000.h> 53#include <asm/mach-au1x00/au1000.h>
54#include <asm/gpio.h>
52 55
53#define MTX1_WDT_INTERVAL (5 * HZ) 56#define MTX1_WDT_INTERVAL (5 * HZ)
54 57
@@ -61,6 +64,7 @@ static struct {
61 volatile int queue; 64 volatile int queue;
62 int default_ticks; 65 int default_ticks;
63 unsigned long inuse; 66 unsigned long inuse;
67 unsigned gpio;
64} mtx1_wdt_device; 68} mtx1_wdt_device;
65 69
66static void mtx1_wdt_trigger(unsigned long unused) 70static void mtx1_wdt_trigger(unsigned long unused)
@@ -73,7 +77,8 @@ static void mtx1_wdt_trigger(unsigned long unused)
73 * toggle GPIO2_15 77 * toggle GPIO2_15
74 */ 78 */
75 tmp = au_readl(GPIO2_DIR); 79 tmp = au_readl(GPIO2_DIR);
76 tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15)); 80 tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) |
81 ((~tmp) & (1 << mtx1_wdt_device.gpio));
77 au_writel (tmp, GPIO2_DIR); 82 au_writel (tmp, GPIO2_DIR);
78 83
79 if (mtx1_wdt_device.queue && ticks) 84 if (mtx1_wdt_device.queue && ticks)
@@ -93,7 +98,7 @@ static void mtx1_wdt_start(void)
93{ 98{
94 if (!mtx1_wdt_device.queue) { 99 if (!mtx1_wdt_device.queue) {
95 mtx1_wdt_device.queue = 1; 100 mtx1_wdt_device.queue = 1;
96 au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR); 101 gpio_set_value(mtx1_wdt_device.gpio, 1);
97 mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); 102 mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
98 } 103 }
99 mtx1_wdt_device.running++; 104 mtx1_wdt_device.running++;
@@ -103,7 +108,7 @@ static int mtx1_wdt_stop(void)
103{ 108{
104 if (mtx1_wdt_device.queue) { 109 if (mtx1_wdt_device.queue) {
105 mtx1_wdt_device.queue = 0; 110 mtx1_wdt_device.queue = 0;
106 au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR); 111 gpio_set_value(mtx1_wdt_device.gpio, 0);
107 } 112 }
108 113
109 ticks = mtx1_wdt_device.default_ticks; 114 ticks = mtx1_wdt_device.default_ticks;
@@ -197,10 +202,12 @@ static struct miscdevice mtx1_wdt_misc = {
197}; 202};
198 203
199 204
200static int __init mtx1_wdt_init(void) 205static int mtx1_wdt_probe(struct platform_device *pdev)
201{ 206{
202 int ret; 207 int ret;
203 208
209 mtx1_wdt_device.gpio = pdev->resource[0].start;
210
204 if ((ret = misc_register(&mtx1_wdt_misc)) < 0) { 211 if ((ret = misc_register(&mtx1_wdt_misc)) < 0) {
205 printk(KERN_ERR " mtx-1_wdt : failed to register\n"); 212 printk(KERN_ERR " mtx-1_wdt : failed to register\n");
206 return ret; 213 return ret;
@@ -222,13 +229,30 @@ static int __init mtx1_wdt_init(void)
222 return 0; 229 return 0;
223} 230}
224 231
225static void __exit mtx1_wdt_exit(void) 232static int mtx1_wdt_remove(struct platform_device *pdev)
226{ 233{
227 if (mtx1_wdt_device.queue) { 234 if (mtx1_wdt_device.queue) {
228 mtx1_wdt_device.queue = 0; 235 mtx1_wdt_device.queue = 0;
229 wait_for_completion(&mtx1_wdt_device.stop); 236 wait_for_completion(&mtx1_wdt_device.stop);
230 } 237 }
231 misc_deregister(&mtx1_wdt_misc); 238 misc_deregister(&mtx1_wdt_misc);
239 return 0;
240}
241
242static struct platform_driver mtx1_wdt = {
243 .probe = mtx1_wdt_probe,
244 .remove = mtx1_wdt_remove,
245 .driver.name = "mtx1-wdt",
246};
247
248static int __init mtx1_wdt_init(void)
249{
250 return platform_driver_register(&mtx1_wdt);
251}
252
253static void __exit mtx1_wdt_exit(void)
254{
255 platform_driver_unregister(&mtx1_wdt);
232} 256}
233 257
234module_init(mtx1_wdt_init); 258module_init(mtx1_wdt_init);
@@ -237,3 +261,4 @@ module_exit(mtx1_wdt_exit);
237MODULE_AUTHOR("Michael Stickel, Florian Fainelli"); 261MODULE_AUTHOR("Michael Stickel, Florian Fainelli");
238MODULE_DESCRIPTION("Driver for the MTX-1 watchdog"); 262MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
239MODULE_LICENSE("GPL"); 263MODULE_LICENSE("GPL");
264MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
new file mode 100644
index 000000000000..b94431433695
--- /dev/null
+++ b/drivers/watchdog/sb_wdog.c
@@ -0,0 +1,353 @@
1/*
2 * Watchdog driver for SiByte SB1 SoCs
3 *
4 * Copyright (C) 2007 OnStor, Inc. * Andrew Sharp <andy.sharp@onstor.com>
5 *
6 * This driver is intended to make the second of two hardware watchdogs
7 * on the Sibyte 12XX and 11XX SoCs available to the user. There are two
8 * such devices available on the SoC, but it seems that there isn't an
9 * enumeration class for watchdogs in Linux like there is for RTCs.
10 * The second is used rather than the first because it uses IRQ 1,
11 * thereby avoiding all that IRQ 0 problematic nonsense.
12 *
13 * I have not tried this driver on a 1480 processor; it might work
14 * just well enough to really screw things up.
15 *
16 * It is a simple timer, and there is an interrupt that is raised the
17 * first time the timer expires. The second time it expires, the chip
18 * is reset and there is no way to redirect that NMI. Which could
19 * be problematic in some cases where this chip is sitting on the HT
20 * bus and has just taken responsibility for providing a cache block.
21 * Since the reset can't be redirected to the external reset pin, it is
22 * possible that other HT connected processors might hang and not reset.
23 * For Linux, a soft reset would probably be even worse than a hard reset.
24 * There you have it.
25 *
26 * The timer takes 23 bits of a 64 bit register (?) as a count value,
27 * and decrements the count every microsecond, for a max value of
28 * 0x7fffff usec or about 8.3ish seconds.
29 *
30 * This watchdog borrows some user semantics from the softdog driver,
31 * in that if you close the fd, it leaves the watchdog running, unless
32 * you previously wrote a 'V' to the fd, in which case it disables
33 * the watchdog when you close the fd like some other drivers.
34 *
35 * Based on various other watchdog drivers, which are probably all
36 * loosely based on something Alan Cox wrote years ago.
37 *
38 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
39 * http://www.redhat.com
40 *
41 * This program is free software; you can redistribute it and/or
42 * modify it under the terms of the GNU General Public License
43 * version 1 or 2 as published by the Free Software Foundation.
44 *
45 */
46#include <linux/module.h>
47#include <linux/io.h>
48#include <linux/uaccess.h>
49#include <linux/fs.h>
50#include <linux/reboot.h>
51#include <linux/miscdevice.h>
52#include <linux/watchdog.h>
53#include <linux/interrupt.h>
54
55#include <asm/sibyte/sb1250.h>
56#include <asm/sibyte/sb1250_regs.h>
57#include <asm/sibyte/sb1250_int.h>
58#include <asm/sibyte/sb1250_scd.h>
59
60
61/*
62 * set the initial count value of a timer
63 *
64 * wdog is the iomem address of the cfg register
65 */
66void sbwdog_set(char __iomem *wdog, unsigned long t)
67{
68 __raw_writeb(0, wdog - 0x10);
69 __raw_writeq(t & 0x7fffffUL, wdog);
70}
71
72/*
73 * cause the timer to [re]load it's initial count and start counting
74 * all over again
75 *
76 * wdog is the iomem address of the cfg register
77 */
78void sbwdog_pet(char __iomem *wdog)
79{
80 __raw_writeb(__raw_readb(wdog) | 1, wdog);
81}
82
83static unsigned long sbwdog_gate; /* keeps it to one thread only */
84static char __iomem *kern_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_0));
85static char __iomem *user_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_1));
86static unsigned long timeout = 0x7fffffUL; /* useconds: 8.3ish secs. */
87static int expect_close;
88
89static struct watchdog_info ident = {
90 .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
91 .identity = "SiByte Watchdog",
92};
93
94/*
95 * Allow only a single thread to walk the dog
96 */
97static int sbwdog_open(struct inode *inode, struct file *file)
98{
99 nonseekable_open(inode, file);
100 if (test_and_set_bit(0, &sbwdog_gate)) {
101 return -EBUSY;
102 }
103 __module_get(THIS_MODULE);
104
105 /*
106 * Activate the timer
107 */
108 sbwdog_set(user_dog, timeout);
109 __raw_writeb(1, user_dog);
110
111 return 0;
112}
113
114/*
115 * Put the dog back in the kennel.
116 */
117static int sbwdog_release(struct inode *inode, struct file *file)
118{
119 if (expect_close == 42) {
120 __raw_writeb(0, user_dog);
121 module_put(THIS_MODULE);
122 } else {
123 printk(KERN_CRIT "%s: Unexpected close, not stopping watchdog!\n",
124 ident.identity);
125 sbwdog_pet(user_dog);
126 }
127 clear_bit(0, &sbwdog_gate);
128 expect_close = 0;
129
130 return 0;
131}
132
133/*
134 * 42 - the answer
135 */
136static ssize_t sbwdog_write(struct file *file, const char __user *data,
137 size_t len, loff_t *ppos)
138{
139 int i;
140
141 if (len) {
142 /*
143 * restart the timer
144 */
145 expect_close = 0;
146
147 for (i = 0; i != len; i++) {
148 char c;
149
150 if (get_user(c, data + i)) {
151 return -EFAULT;
152 }
153 if (c == 'V') {
154 expect_close = 42;
155 }
156 }
157 sbwdog_pet(user_dog);
158 }
159
160 return len;
161}
162
163static int sbwdog_ioctl(struct inode *inode, struct file *file,
164 unsigned int cmd, unsigned long arg)
165{
166 int ret = -ENOTTY;
167 unsigned long time;
168 void __user *argp = (void __user *)arg;
169 int __user *p = argp;
170
171 switch (cmd) {
172 case WDIOC_GETSUPPORT:
173 ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
174 break;
175
176 case WDIOC_GETSTATUS:
177 case WDIOC_GETBOOTSTATUS:
178 ret = put_user(0, p);
179 break;
180
181 case WDIOC_SETTIMEOUT:
182 ret = get_user(time, p);
183 if (ret) {
184 break;
185 }
186
187 time *= 1000000;
188 if (time > 0x7fffffUL) {
189 ret = -EINVAL;
190 break;
191 }
192 timeout = time;
193 sbwdog_set(user_dog, timeout);
194 sbwdog_pet(user_dog);
195
196 case WDIOC_GETTIMEOUT:
197 /*
198 * get the remaining count from the ... count register
199 * which is 1*8 before the config register
200 */
201 ret = put_user(__raw_readq(user_dog - 8) / 1000000, p);
202 break;
203
204 case WDIOC_KEEPALIVE:
205 sbwdog_pet(user_dog);
206 ret = 0;
207 break;
208 }
209 return ret;
210}
211
212/*
213 * Notifier for system down
214 */
215static int
216sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf)
217{
218 if (code == SYS_DOWN || code == SYS_HALT) {
219 /*
220 * sit and sit
221 */
222 __raw_writeb(0, user_dog);
223 __raw_writeb(0, kern_dog);
224 }
225
226 return NOTIFY_DONE;
227}
228
229static const struct file_operations sbwdog_fops =
230{
231 .owner = THIS_MODULE,
232 .llseek = no_llseek,
233 .write = sbwdog_write,
234 .ioctl = sbwdog_ioctl,
235 .open = sbwdog_open,
236 .release = sbwdog_release,
237};
238
239static struct miscdevice sbwdog_miscdev =
240{
241 .minor = WATCHDOG_MINOR,
242 .name = "watchdog",
243 .fops = &sbwdog_fops,
244};
245
246static struct notifier_block sbwdog_notifier = {
247 .notifier_call = sbwdog_notify_sys,
248};
249
250/*
251 * interrupt handler
252 *
253 * doesn't do a whole lot for user, but oh so cleverly written so kernel
254 * code can use it to re-up the watchdog, thereby saving the kernel from
255 * having to create and maintain a timer, just to tickle another timer,
256 * which is just so wrong.
257 */
258irqreturn_t sbwdog_interrupt(int irq, void *addr)
259{
260 unsigned long wd_init;
261 char *wd_cfg_reg = (char *)addr;
262 u8 cfg;
263
264 cfg = __raw_readb(wd_cfg_reg);
265 wd_init = __raw_readq(wd_cfg_reg - 8) & 0x7fffff;
266
267 /*
268 * if it's the second watchdog timer, it's for those users
269 */
270 if (wd_cfg_reg == user_dog) {
271 printk(KERN_CRIT
272 "%s in danger of initiating system reset in %ld.%01ld seconds\n",
273 ident.identity, wd_init / 1000000, (wd_init / 100000) % 10);
274 } else {
275 cfg |= 1;
276 }
277
278 __raw_writeb(cfg, wd_cfg_reg);
279
280 return IRQ_HANDLED;
281}
282
283static int __init sbwdog_init(void)
284{
285 int ret;
286
287 /*
288 * register a reboot notifier
289 */
290 ret = register_reboot_notifier(&sbwdog_notifier);
291 if (ret) {
292 printk (KERN_ERR "%s: cannot register reboot notifier (err=%d)\n",
293 ident.identity, ret);
294 return ret;
295 }
296
297 /*
298 * get the resources
299 */
300 ret = misc_register(&sbwdog_miscdev);
301 if (ret == 0) {
302 printk(KERN_INFO "%s: timeout is %ld.%ld secs\n", ident.identity,
303 timeout / 1000000, (timeout / 100000) % 10);
304 }
305
306 ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED,
307 ident.identity, (void *)user_dog);
308 if (ret) {
309 printk(KERN_ERR "%s: failed to request irq 1 - %d\n", ident.identity,
310 ret);
311 misc_deregister(&sbwdog_miscdev);
312 }
313
314 return ret;
315}
316
317static void __exit sbwdog_exit(void)
318{
319 misc_deregister(&sbwdog_miscdev);
320}
321
322module_init(sbwdog_init);
323module_exit(sbwdog_exit);
324
325MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
326MODULE_DESCRIPTION("SiByte Watchdog");
327
328module_param(timeout, ulong, 0);
329MODULE_PARM_DESC(timeout,
330 "Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)");
331
332MODULE_LICENSE("GPL");
333MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
334
335/*
336 * example code that can be put in a platform code area to utilize the
337 * first watchdog timer for the kernels own purpose.
338
339 void
340platform_wd_setup(void)
341{
342 int ret;
343
344 ret = request_irq(0, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED,
345 "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0));
346 if (ret) {
347 printk(KERN_CRIT "Watchdog IRQ zero(0) failed to be requested - %d\n",
348 ret);
349 }
350}
351
352
353 */