···84848585 Not sure? It's safe to say N.86868787+config IXP2000_WATCHDOG8888+ tristate "IXP2000 Watchdog"8989+ depends on WATCHDOG && ARCH_IXP20009090+ help9191+ Say Y here if to include support for the watchdog timer9292+ in the Intel IXP2000(2400, 2800, 2850) network processors.9393+ This driver can be built as a module by choosing M. The module9494+ will be called ixp2000_wdt.9595+9696+ Say N if you are unsure.9797+8798config IXP4XX_WATCHDOG8899 tristate "IXP4xx Watchdog"89100 depends on WATCHDOG && ARCH_IXP4XX···10897 which doesn't reset any peripherals. There are circumstances10998 where the watchdog will fail to reset the board correctly11099 (e.g., if the boot ROM is in an unreadable state).111111-112112- Say N if you are unsure.113113-114114-config IXP2000_WATCHDOG115115- tristate "IXP2000 Watchdog"116116- depends on WATCHDOG && ARCH_IXP2000117117- help118118- Say Y here if to include support for the watchdog timer119119- in the Intel IXP2000(2400, 2800, 2850) network processors.120120- This driver can be built as a module by choosing M. The module121121- will be called ixp2000_wdt.122100123101 Say N if you are unsure.124102···233233234234 Most people will say N.235235236236+config IBMASR237237+ tristate "IBM Automatic Server Restart"238238+ depends on WATCHDOG && X86239239+ help240240+ This is the driver for the IBM Automatic Server Restart watchdog241241+ timer builtin into some eServer xSeries machines.242242+243243+ To compile this driver as a module, choose M here: the244244+ module will be called ibmasr.245245+236246config WAFER_WDT237247 tristate "ICP Wafer 5823 Single Board Computer Watchdog"238248 depends on WATCHDOG && X86···252242253243 To compile this driver as a module, choose M here: the254244 module will be called wafer5823wdt.245245+246246+config I6300ESB_WDT247247+ tristate "Intel 6300ESB Timer/Watchdog"248248+ depends on WATCHDOG && X86 && PCI249249+ ---help---250250+ Hardware driver for the watchdog timer built into the Intel251251+ 6300ESB controller hub.252252+253253+ To compile this driver as a module, choose M here: the254254+ module will be called i6300esb.255255256256config I8XX_TCO257257 tristate "Intel i8xx TCO Timer/Watchdog"···318298 You can compile this driver directly into the kernel, or use319299 it as a module. The module will be called sbc60xxwdt.320300301301+config SBC8360_WDT302302+ tristate "SBC8360 Watchdog Timer"303303+ depends on WATCHDOG && X86304304+ ---help---305305+306306+ This is the driver for the hardware watchdog on the SBC8360 Single307307+ Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).308308+309309+ To compile this driver as a module, choose M here: the310310+ module will be called sbc8360.ko.311311+312312+ Most people will say N.313313+321314config CPU5_WDT322315 tristate "SMA CPU5 Watchdog"323316 depends on WATCHDOG && X86···369336370337 Most people will say N.371338339339+config W83977F_WDT340340+ tristate "W83977F (PCM-5335) Watchdog Timer"341341+ depends on WATCHDOG && X86342342+ ---help---343343+ This is the driver for the hardware watchdog on the W83977F I/O chip344344+ as used in AAEON's PCM-5335 SBC (and likely others). This345345+ watchdog simply watches your kernel to make sure it doesn't freeze,346346+ and if it does, it reboots your computer after a certain amount of347347+ time.348348+349349+ To compile this driver as a module, choose M here: the350350+ module will be called w83977f_wdt.351351+372352config MACHZ_WDT373353 tristate "ZF MachZ Watchdog"374354 depends on WATCHDOG && X86···401355 tristate "MPC8xx Watchdog Timer"402356 depends on WATCHDOG && 8xx403357358358+config MV64X60_WDT359359+ tristate "MV64X60 (Marvell Discovery) Watchdog Timer"360360+ depends on WATCHDOG && MV64X60361361+404362config BOOKE_WDT405363 tristate "PowerPC Book-E Watchdog Timer"406364 depends on WATCHDOG && (BOOKE || 4xx)407365 ---help---408366 Please see Documentation/watchdog/watchdog-api.txt for409367 more information.368368+369369+# PPC64 Architecture370370+371371+config WATCHDOG_RTAS372372+ tristate "RTAS watchdog"373373+ depends on WATCHDOG && PPC_RTAS374374+ help375375+ This driver adds watchdog support for the RTAS watchdog.376376+377377+ To compile this driver as a module, choose M here. The module378378+ will be called wdrtas.410379411380# MIPS Architecture412381···490429 Say Y here to support the hardware watchdog capability on Sun RIO491430 machines. The watchdog timeout period is normally one minute but492431 can be changed with a boot-time parameter.493493-494494-# ppc64 RTAS watchdog495495-config WATCHDOG_RTAS496496- tristate "RTAS watchdog"497497- depends on WATCHDOG && PPC_RTAS498498- help499499- This driver adds watchdog support for the RTAS watchdog.500500-501501- To compile this driver as a module, choose M here. The module502502- will be called wdrtas.503432504433#505434# ISA-based Watchdog Cards
···11+/*22+ * i6300esb: Watchdog timer driver for Intel 6300ESB chipset33+ *44+ * (c) Copyright 2004 Google Inc.55+ * (c) Copyright 2005 David H�rdeman <david@2gen.com>66+ *77+ * This program is free software; you can redistribute it and/or88+ * modify it under the terms of the GNU General Public License99+ * as published by the Free Software Foundation; either version1010+ * 2 of the License, or (at your option) any later version.1111+ *1212+ * based on i810-tco.c which is in turn based on softdog.c1313+ *1414+ * The timer is implemented in the following I/O controller hubs:1515+ * (See the intel documentation on http://developer.intel.com.)1616+ * 6300ESB chip : document number 300641-0031717+ *1818+ * 2004YYZZ Ross Biro1919+ * Initial version 0.012020+ * 2004YYZZ Ross Biro2121+ * Version 0.022222+ * 20050210 David H�rdeman <david@2gen.com>2323+ * Ported driver to kernel 2.62424+ */2525+2626+/*2727+ * Includes, defines, variables, module parameters, ...2828+ */2929+3030+#include <linux/module.h>3131+#include <linux/types.h>3232+#include <linux/kernel.h>3333+#include <linux/fs.h>3434+#include <linux/mm.h>3535+#include <linux/miscdevice.h>3636+#include <linux/watchdog.h>3737+#include <linux/reboot.h>3838+#include <linux/init.h>3939+#include <linux/pci.h>4040+#include <linux/ioport.h>4141+4242+#include <asm/uaccess.h>4343+#include <asm/io.h>4444+4545+/* Module and version information */4646+#define ESB_VERSION "0.03"4747+#define ESB_MODULE_NAME "i6300ESB timer"4848+#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION4949+#define PFX ESB_MODULE_NAME ": "5050+5151+/* PCI configuration registers */5252+#define ESB_CONFIG_REG 0x60 /* Config register */5353+#define ESB_LOCK_REG 0x68 /* WDT lock register */5454+5555+/* Memory mapped registers */5656+#define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */5757+#define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */5858+#define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */5959+#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */6060+6161+/* Lock register bits */6262+#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */6363+#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */6464+#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */6565+6666+/* Config register bits */6767+#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */6868+#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */6969+#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */7070+7171+/* Reload register bits */7272+#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */7373+7474+/* Magic constants */7575+#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */7676+#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */7777+7878+/* internal variables */7979+static void __iomem *BASEADDR;8080+static spinlock_t esb_lock; /* Guards the hardware */8181+static unsigned long timer_alive;8282+static struct pci_dev *esb_pci;8383+static unsigned short triggered; /* The status of the watchdog upon boot */8484+static char esb_expect_close;8585+8686+/* module parameters */8787+#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */8888+static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */8989+module_param(heartbeat, int, 0);9090+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");9191+9292+static int nowayout = WATCHDOG_NOWAYOUT;9393+module_param(nowayout, int, 0);9494+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");9595+9696+/*9797+ * Some i6300ESB specific functions9898+ */9999+100100+/*101101+ * Prepare for reloading the timer by unlocking the proper registers.102102+ * This is performed by first writing 0x80 followed by 0x86 to the103103+ * reload register. After this the appropriate registers can be written104104+ * to once before they need to be unlocked again.105105+ */106106+static inline void esb_unlock_registers(void) {107107+ writeb(ESB_UNLOCK1, ESB_RELOAD_REG);108108+ writeb(ESB_UNLOCK2, ESB_RELOAD_REG);109109+}110110+111111+static void esb_timer_start(void)112112+{113113+ u8 val;114114+115115+ /* Enable or Enable + Lock? */116116+ val = 0x02 | (nowayout ? 0x01 : 0x00);117117+118118+ pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);119119+}120120+121121+static int esb_timer_stop(void)122122+{123123+ u8 val;124124+125125+ spin_lock(&esb_lock);126126+ /* First, reset timers as suggested by the docs */127127+ esb_unlock_registers();128128+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);129129+ /* Then disable the WDT */130130+ pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0);131131+ pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val);132132+ spin_unlock(&esb_lock);133133+134134+ /* Returns 0 if the timer was disabled, non-zero otherwise */135135+ return (val & 0x01);136136+}137137+138138+static void esb_timer_keepalive(void)139139+{140140+ spin_lock(&esb_lock);141141+ esb_unlock_registers();142142+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);143143+ /* FIXME: Do we need to flush anything here? */144144+ spin_unlock(&esb_lock);145145+}146146+147147+static int esb_timer_set_heartbeat(int time)148148+{149149+ u32 val;150150+151151+ if (time < 0x1 || time > (2 * 0x03ff))152152+ return -EINVAL;153153+154154+ spin_lock(&esb_lock);155155+156156+ /* We shift by 9, so if we are passed a value of 1 sec,157157+ * val will be 1 << 9 = 512, then write that to two158158+ * timers => 2 * 512 = 1024 (which is decremented at 1KHz)159159+ */160160+ val = time << 9;161161+162162+ /* Write timer 1 */163163+ esb_unlock_registers();164164+ writel(val, ESB_TIMER1_REG);165165+166166+ /* Write timer 2 */167167+ esb_unlock_registers();168168+ writel(val, ESB_TIMER2_REG);169169+170170+ /* Reload */171171+ esb_unlock_registers();172172+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);173173+174174+ /* FIXME: Do we need to flush everything out? */175175+176176+ /* Done */177177+ heartbeat = time;178178+ spin_unlock(&esb_lock);179179+ return 0;180180+}181181+182182+static int esb_timer_read (void)183183+{184184+ u32 count;185185+186186+ /* This isn't documented, and doesn't take into187187+ * acount which stage is running, but it looks188188+ * like a 20 bit count down, so we might as well report it.189189+ */190190+ pci_read_config_dword(esb_pci, 0x64, &count);191191+ return (int)count;192192+}193193+194194+/*195195+ * /dev/watchdog handling196196+ */197197+198198+static int esb_open (struct inode *inode, struct file *file)199199+{200200+ /* /dev/watchdog can only be opened once */201201+ if (test_and_set_bit(0, &timer_alive))202202+ return -EBUSY;203203+204204+ /* Reload and activate timer */205205+ esb_timer_keepalive ();206206+ esb_timer_start ();207207+208208+ return nonseekable_open(inode, file);209209+}210210+211211+static int esb_release (struct inode *inode, struct file *file)212212+{213213+ /* Shut off the timer. */214214+ if (esb_expect_close == 42) {215215+ esb_timer_stop ();216216+ } else {217217+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");218218+ esb_timer_keepalive ();219219+ }220220+ clear_bit(0, &timer_alive);221221+ esb_expect_close = 0;222222+ return 0;223223+}224224+225225+static ssize_t esb_write (struct file *file, const char __user *data,226226+ size_t len, loff_t * ppos)227227+{228228+ /* See if we got the magic character 'V' and reload the timer */229229+ if (len) {230230+ if (!nowayout) {231231+ size_t i;232232+233233+ /* note: just in case someone wrote the magic character234234+ * five months ago... */235235+ esb_expect_close = 0;236236+237237+ /* scan to see whether or not we got the magic character */238238+ for (i = 0; i != len; i++) {239239+ char c;240240+ if(get_user(c, data+i))241241+ return -EFAULT;242242+ if (c == 'V')243243+ esb_expect_close = 42;244244+ }245245+ }246246+247247+ /* someone wrote to us, we should reload the timer */248248+ esb_timer_keepalive ();249249+ }250250+ return len;251251+}252252+253253+static int esb_ioctl (struct inode *inode, struct file *file,254254+ unsigned int cmd, unsigned long arg)255255+{256256+ int new_options, retval = -EINVAL;257257+ int new_heartbeat;258258+ void __user *argp = (void __user *)arg;259259+ int __user *p = argp;260260+ static struct watchdog_info ident = {261261+ .options = WDIOF_SETTIMEOUT |262262+ WDIOF_KEEPALIVEPING |263263+ WDIOF_MAGICCLOSE,264264+ .firmware_version = 0,265265+ .identity = ESB_MODULE_NAME,266266+ };267267+268268+ switch (cmd) {269269+ case WDIOC_GETSUPPORT:270270+ return copy_to_user(argp, &ident,271271+ sizeof (ident)) ? -EFAULT : 0;272272+273273+ case WDIOC_GETSTATUS:274274+ return put_user (esb_timer_read(), p);275275+276276+ case WDIOC_GETBOOTSTATUS:277277+ return put_user (triggered, p);278278+279279+ case WDIOC_KEEPALIVE:280280+ esb_timer_keepalive ();281281+ return 0;282282+283283+ case WDIOC_SETOPTIONS:284284+ {285285+ if (get_user (new_options, p))286286+ return -EFAULT;287287+288288+ if (new_options & WDIOS_DISABLECARD) {289289+ esb_timer_stop ();290290+ retval = 0;291291+ }292292+293293+ if (new_options & WDIOS_ENABLECARD) {294294+ esb_timer_keepalive ();295295+ esb_timer_start ();296296+ retval = 0;297297+ }298298+299299+ return retval;300300+ }301301+302302+ case WDIOC_SETTIMEOUT:303303+ {304304+ if (get_user(new_heartbeat, p))305305+ return -EFAULT;306306+307307+ if (esb_timer_set_heartbeat(new_heartbeat))308308+ return -EINVAL;309309+310310+ esb_timer_keepalive ();311311+ /* Fall */312312+ }313313+314314+ case WDIOC_GETTIMEOUT:315315+ return put_user(heartbeat, p);316316+317317+ default:318318+ return -ENOIOCTLCMD;319319+ }320320+}321321+322322+/*323323+ * Notify system324324+ */325325+326326+static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused)327327+{328328+ if (code==SYS_DOWN || code==SYS_HALT) {329329+ /* Turn the WDT off */330330+ esb_timer_stop ();331331+ }332332+333333+ return NOTIFY_DONE;334334+}335335+336336+/*337337+ * Kernel Interfaces338338+ */339339+340340+static struct file_operations esb_fops = {341341+ .owner = THIS_MODULE,342342+ .llseek = no_llseek,343343+ .write = esb_write,344344+ .ioctl = esb_ioctl,345345+ .open = esb_open,346346+ .release = esb_release,347347+};348348+349349+static struct miscdevice esb_miscdev = {350350+ .minor = WATCHDOG_MINOR,351351+ .name = "watchdog",352352+ .fops = &esb_fops,353353+};354354+355355+static struct notifier_block esb_notifier = {356356+ .notifier_call = esb_notify_sys,357357+};358358+359359+/*360360+ * Data for PCI driver interface361361+ *362362+ * This data only exists for exporting the supported363363+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually364364+ * register a pci_driver, because someone else might one day365365+ * want to register another driver on the same PCI id.366366+ */367367+static struct pci_device_id esb_pci_tbl[] = {368368+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },369369+ { 0, }, /* End of list */370370+};371371+MODULE_DEVICE_TABLE (pci, esb_pci_tbl);372372+373373+/*374374+ * Init & exit routines375375+ */376376+377377+static unsigned char __init esb_getdevice (void)378378+{379379+ u8 val1;380380+ unsigned short val2;381381+382382+ struct pci_dev *dev = NULL;383383+ /*384384+ * Find the PCI device385385+ */386386+387387+ for_each_pci_dev(dev) {388388+ if (pci_match_id(esb_pci_tbl, dev)) {389389+ esb_pci = dev;390390+ break;391391+ }392392+ }393393+394394+ if (esb_pci) {395395+ if (pci_enable_device(esb_pci)) {396396+ printk (KERN_ERR PFX "failed to enable device\n");397397+ goto err_devput;398398+ }399399+400400+ if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {401401+ printk (KERN_ERR PFX "failed to request region\n");402402+ goto err_disable;403403+ }404404+405405+ BASEADDR = ioremap(pci_resource_start(esb_pci, 0),406406+ pci_resource_len(esb_pci, 0));407407+ if (BASEADDR == NULL) {408408+ /* Something's wrong here, BASEADDR has to be set */409409+ printk (KERN_ERR PFX "failed to get BASEADDR\n");410410+ goto err_release;411411+ }412412+413413+ /*414414+ * The watchdog has two timers, it can be setup so that the415415+ * expiry of timer1 results in an interrupt and the expiry of416416+ * timer2 results in a reboot. We set it to not generate417417+ * any interrupts as there is not much we can do with it418418+ * right now.419419+ *420420+ * We also enable reboots and set the timer frequency to421421+ * the PCI clock divided by 2^15 (approx 1KHz).422422+ */423423+ pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003);424424+425425+ /* Check that the WDT isn't already locked */426426+ pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);427427+ if (val1 & ESB_WDT_LOCK)428428+ printk (KERN_WARNING PFX "nowayout already set\n");429429+430430+ /* Set the timer to watchdog mode and disable it for now */431431+ pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);432432+433433+ /* Check if the watchdog was previously triggered */434434+ esb_unlock_registers();435435+ val2 = readw(ESB_RELOAD_REG);436436+ triggered = (val2 & (0x01 << 9) >> 9);437437+438438+ /* Reset trigger flag and timers */439439+ esb_unlock_registers();440440+ writew((0x11 << 8), ESB_RELOAD_REG);441441+442442+ /* Done */443443+ return 1;444444+445445+err_release:446446+ pci_release_region(esb_pci, 0);447447+err_disable:448448+ pci_disable_device(esb_pci);449449+err_devput:450450+ pci_dev_put(esb_pci);451451+ }452452+ return 0;453453+}454454+455455+static int __init watchdog_init (void)456456+{457457+ int ret;458458+459459+ spin_lock_init(&esb_lock);460460+461461+ /* Check whether or not the hardware watchdog is there */462462+ if (!esb_getdevice () || esb_pci == NULL)463463+ return -ENODEV;464464+465465+ /* Check that the heartbeat value is within it's range ; if not reset to the default */466466+ if (esb_timer_set_heartbeat (heartbeat)) {467467+ esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT);468468+ printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n",469469+ heartbeat);470470+ }471471+472472+ ret = register_reboot_notifier(&esb_notifier);473473+ if (ret != 0) {474474+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",475475+ ret);476476+ goto err_unmap;477477+ }478478+479479+ ret = misc_register(&esb_miscdev);480480+ if (ret != 0) {481481+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",482482+ WATCHDOG_MINOR, ret);483483+ goto err_notifier;484484+ }485485+486486+ esb_timer_stop ();487487+488488+ printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",489489+ BASEADDR, heartbeat, nowayout);490490+491491+ return 0;492492+493493+err_notifier:494494+ unregister_reboot_notifier(&esb_notifier);495495+err_unmap:496496+ iounmap(BASEADDR);497497+/* err_release: */498498+ pci_release_region(esb_pci, 0);499499+/* err_disable: */500500+ pci_disable_device(esb_pci);501501+/* err_devput: */502502+ pci_dev_put(esb_pci);503503+ return ret;504504+}505505+506506+static void __exit watchdog_cleanup (void)507507+{508508+ /* Stop the timer before we leave */509509+ if (!nowayout)510510+ esb_timer_stop ();511511+512512+ /* Deregister */513513+ misc_deregister(&esb_miscdev);514514+ unregister_reboot_notifier(&esb_notifier);515515+ iounmap(BASEADDR);516516+ pci_release_region(esb_pci, 0);517517+ pci_disable_device(esb_pci);518518+ pci_dev_put(esb_pci);519519+}520520+521521+module_init(watchdog_init);522522+module_exit(watchdog_cleanup);523523+524524+MODULE_AUTHOR("Ross Biro and David H�rdeman");525525+MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");526526+MODULE_LICENSE("GPL");527527+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+405
drivers/char/watchdog/ibmasr.c
···11+/*22+ * IBM Automatic Server Restart driver.33+ *44+ * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru>55+ *66+ * Based on driver written by Pete Reynolds.77+ * Copyright (c) IBM Corporation, 1998-2004.88+ *99+ * This software may be used and distributed according to the terms1010+ * of the GNU Public License, incorporated herein by reference.1111+ */1212+1313+#include <linux/config.h>1414+#include <linux/fs.h>1515+#include <linux/kernel.h>1616+#include <linux/slab.h>1717+#include <linux/module.h>1818+#include <linux/pci.h>1919+#include <linux/timer.h>2020+#include <linux/miscdevice.h>2121+#include <linux/watchdog.h>2222+#include <linux/dmi.h>2323+2424+#include <asm/io.h>2525+#include <asm/uaccess.h>2626+2727+2828+enum {2929+ ASMTYPE_UNKNOWN,3030+ ASMTYPE_TOPAZ,3131+ ASMTYPE_JASPER,3232+ ASMTYPE_PEARL,3333+ ASMTYPE_JUNIPER,3434+ ASMTYPE_SPRUCE,3535+};3636+3737+#define PFX "ibmasr: "3838+3939+#define TOPAZ_ASR_REG_OFFSET 44040+#define TOPAZ_ASR_TOGGLE 0x404141+#define TOPAZ_ASR_DISABLE 0x804242+4343+/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */4444+#define PEARL_BASE 0xe044545+#define PEARL_WRITE 0xe064646+#define PEARL_READ 0xe074747+4848+#define PEARL_ASR_DISABLE_MASK 0x80 /* bit 7: disable = 1, enable = 0 */4949+#define PEARL_ASR_TOGGLE_MASK 0x40 /* bit 6: 0, then 1, then 0 */5050+5151+/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */5252+#define JASPER_ASR_REG_OFFSET 0x385353+5454+#define JASPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1, enable = 0 */5555+#define JASPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */5656+5757+#define JUNIPER_BASE_ADDRESS 0x54b /* Base address of Juniper ASR */5858+#define JUNIPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1 enable = 0 */5959+#define JUNIPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */6060+6161+#define SPRUCE_BASE_ADDRESS 0x118e /* Base address of Spruce ASR */6262+#define SPRUCE_ASR_DISABLE_MASK 0x01 /* bit 1: disable = 1 enable = 0 */6363+#define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */6464+6565+6666+static int nowayout = WATCHDOG_NOWAYOUT;6767+6868+static unsigned long asr_is_open;6969+static char asr_expect_close;7070+7171+static unsigned int asr_type, asr_base, asr_length;7272+static unsigned int asr_read_addr, asr_write_addr;7373+static unsigned char asr_toggle_mask, asr_disable_mask;7474+7575+static void asr_toggle(void)7676+{7777+ unsigned char reg = inb(asr_read_addr);7878+7979+ outb(reg & ~asr_toggle_mask, asr_write_addr);8080+ reg = inb(asr_read_addr);8181+8282+ outb(reg | asr_toggle_mask, asr_write_addr);8383+ reg = inb(asr_read_addr);8484+8585+ outb(reg & ~asr_toggle_mask, asr_write_addr);8686+ reg = inb(asr_read_addr);8787+}8888+8989+static void asr_enable(void)9090+{9191+ unsigned char reg;9292+9393+ if (asr_type == ASMTYPE_TOPAZ) {9494+ /* asr_write_addr == asr_read_addr */9595+ reg = inb(asr_read_addr);9696+ outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE),9797+ asr_read_addr);9898+ } else {9999+ /*100100+ * First make sure the hardware timer is reset by toggling101101+ * ASR hardware timer line.102102+ */103103+ asr_toggle();104104+105105+ reg = inb(asr_read_addr);106106+ outb(reg & ~asr_disable_mask, asr_write_addr);107107+ }108108+ reg = inb(asr_read_addr);109109+}110110+111111+static void asr_disable(void)112112+{113113+ unsigned char reg = inb(asr_read_addr);114114+115115+ if (asr_type == ASMTYPE_TOPAZ)116116+ /* asr_write_addr == asr_read_addr */117117+ outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE,118118+ asr_read_addr);119119+ else {120120+ outb(reg | asr_toggle_mask, asr_write_addr);121121+ reg = inb(asr_read_addr);122122+123123+ outb(reg | asr_disable_mask, asr_write_addr);124124+ }125125+ reg = inb(asr_read_addr);126126+}127127+128128+static int __init asr_get_base_address(void)129129+{130130+ unsigned char low, high;131131+ const char *type = "";132132+133133+ asr_length = 1;134134+135135+ switch (asr_type) {136136+ case ASMTYPE_TOPAZ:137137+ /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */138138+ outb(0x07, 0x2e);139139+ outb(0x07, 0x2f);140140+141141+ /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */142142+ outb(0x60, 0x2e);143143+ high = inb(0x2f);144144+145145+ /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */146146+ outb(0x61, 0x2e);147147+ low = inb(0x2f);148148+149149+ asr_base = (high << 16) | low;150150+ asr_read_addr = asr_write_addr =151151+ asr_base + TOPAZ_ASR_REG_OFFSET;152152+ asr_length = 5;153153+154154+ break;155155+156156+ case ASMTYPE_JASPER:157157+ type = "Jaspers ";158158+159159+ /* FIXME: need to use pci_config_lock here, but it's not exported */160160+161161+/* spin_lock_irqsave(&pci_config_lock, flags);*/162162+163163+ /* Select the SuperIO chip in the PCI I/O port register */164164+ outl(0x8000f858, 0xcf8);165165+166166+ /*167167+ * Read the base address for the SuperIO chip.168168+ * Only the lower 16 bits are valid, but the address is word169169+ * aligned so the last bit must be masked off.170170+ */171171+ asr_base = inl(0xcfc) & 0xfffe;172172+173173+/* spin_unlock_irqrestore(&pci_config_lock, flags);*/174174+175175+ asr_read_addr = asr_write_addr =176176+ asr_base + JASPER_ASR_REG_OFFSET;177177+ asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;178178+ asr_disable_mask = JASPER_ASR_DISABLE_MASK;179179+ asr_length = JASPER_ASR_REG_OFFSET + 1;180180+181181+ break;182182+183183+ case ASMTYPE_PEARL:184184+ type = "Pearls ";185185+ asr_base = PEARL_BASE;186186+ asr_read_addr = PEARL_READ;187187+ asr_write_addr = PEARL_WRITE;188188+ asr_toggle_mask = PEARL_ASR_TOGGLE_MASK;189189+ asr_disable_mask = PEARL_ASR_DISABLE_MASK;190190+ asr_length = 4;191191+ break;192192+193193+ case ASMTYPE_JUNIPER:194194+ type = "Junipers ";195195+ asr_base = JUNIPER_BASE_ADDRESS;196196+ asr_read_addr = asr_write_addr = asr_base;197197+ asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK;198198+ asr_disable_mask = JUNIPER_ASR_DISABLE_MASK;199199+ break;200200+201201+ case ASMTYPE_SPRUCE:202202+ type = "Spruce's ";203203+ asr_base = SPRUCE_BASE_ADDRESS;204204+ asr_read_addr = asr_write_addr = asr_base;205205+ asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK;206206+ asr_disable_mask = SPRUCE_ASR_DISABLE_MASK;207207+ break;208208+ }209209+210210+ if (!request_region(asr_base, asr_length, "ibmasr")) {211211+ printk(KERN_ERR PFX "address %#x already in use\n",212212+ asr_base);213213+ return -EBUSY;214214+ }215215+216216+ printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);217217+218218+ return 0;219219+}220220+221221+222222+static ssize_t asr_write(struct file *file, const char __user *buf,223223+ size_t count, loff_t *ppos)224224+{225225+ if (count) {226226+ if (!nowayout) {227227+ size_t i;228228+229229+ /* In case it was set long ago */230230+ asr_expect_close = 0;231231+232232+ for (i = 0; i != count; i++) {233233+ char c;234234+ if (get_user(c, buf + i))235235+ return -EFAULT;236236+ if (c == 'V')237237+ asr_expect_close = 42;238238+ }239239+ }240240+ asr_toggle();241241+ }242242+ return count;243243+}244244+245245+static int asr_ioctl(struct inode *inode, struct file *file,246246+ unsigned int cmd, unsigned long arg)247247+{248248+ static const struct watchdog_info ident = {249249+ .options = WDIOF_KEEPALIVEPING | 250250+ WDIOF_MAGICCLOSE,251251+ .identity = "IBM ASR"252252+ };253253+ void __user *argp = (void __user *)arg;254254+ int __user *p = argp;255255+ int heartbeat;256256+257257+ switch (cmd) {258258+ case WDIOC_GETSUPPORT:259259+ return copy_to_user(argp, &ident, sizeof(ident)) ?260260+ -EFAULT : 0;261261+262262+ case WDIOC_GETSTATUS:263263+ case WDIOC_GETBOOTSTATUS:264264+ return put_user(0, p);265265+266266+ case WDIOC_KEEPALIVE:267267+ asr_toggle();268268+ return 0;269269+270270+ /*271271+ * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT272272+ * and WDIOC_GETTIMEOUT always returns 256.273273+ */274274+ case WDIOC_GETTIMEOUT:275275+ heartbeat = 256;276276+ return put_user(heartbeat, p);277277+278278+ case WDIOC_SETOPTIONS: {279279+ int new_options, retval = -EINVAL;280280+281281+ if (get_user(new_options, p))282282+ return -EFAULT;283283+284284+ if (new_options & WDIOS_DISABLECARD) {285285+ asr_disable();286286+ retval = 0;287287+ }288288+289289+ if (new_options & WDIOS_ENABLECARD) {290290+ asr_enable();291291+ asr_toggle();292292+ retval = 0;293293+ }294294+295295+ return retval;296296+ }297297+ }298298+299299+ return -ENOIOCTLCMD;300300+}301301+302302+static int asr_open(struct inode *inode, struct file *file)303303+{304304+ if(test_and_set_bit(0, &asr_is_open))305305+ return -EBUSY;306306+307307+ asr_toggle();308308+ asr_enable();309309+310310+ return nonseekable_open(inode, file);311311+}312312+313313+static int asr_release(struct inode *inode, struct file *file)314314+{315315+ if (asr_expect_close == 42)316316+ asr_disable();317317+ else {318318+ printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");319319+ asr_toggle();320320+ }321321+ clear_bit(0, &asr_is_open);322322+ asr_expect_close = 0;323323+ return 0;324324+}325325+326326+static struct file_operations asr_fops = {327327+ .owner = THIS_MODULE,328328+ .llseek = no_llseek,329329+ .write = asr_write,330330+ .ioctl = asr_ioctl,331331+ .open = asr_open,332332+ .release = asr_release,333333+};334334+335335+static struct miscdevice asr_miscdev = {336336+ .minor = WATCHDOG_MINOR,337337+ .name = "watchdog",338338+ .fops = &asr_fops,339339+};340340+341341+342342+struct ibmasr_id {343343+ const char *desc;344344+ int type;345345+};346346+347347+static struct ibmasr_id __initdata ibmasr_id_table[] = {348348+ { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },349349+ { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },350350+ { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },351351+ { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER },352352+ { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE },353353+ { NULL }354354+};355355+356356+static int __init ibmasr_init(void)357357+{358358+ struct ibmasr_id *id;359359+ int rc;360360+361361+ for (id = ibmasr_id_table; id->desc; id++) {362362+ if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) {363363+ asr_type = id->type;364364+ break;365365+ }366366+ }367367+368368+ if (!asr_type)369369+ return -ENODEV;370370+371371+ rc = misc_register(&asr_miscdev);372372+ if (rc < 0) {373373+ printk(KERN_ERR PFX "failed to register misc device\n");374374+ return rc;375375+ }376376+377377+ rc = asr_get_base_address();378378+ if (rc) {379379+ misc_deregister(&asr_miscdev);380380+ return rc;381381+ }382382+383383+ return 0;384384+}385385+386386+static void __exit ibmasr_exit(void)387387+{388388+ if (!nowayout)389389+ asr_disable();390390+391391+ misc_deregister(&asr_miscdev);392392+393393+ release_region(asr_base, asr_length);394394+}395395+396396+module_init(ibmasr_init);397397+module_exit(ibmasr_exit);398398+399399+module_param(nowayout, int, 0);400400+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");401401+402402+MODULE_DESCRIPTION("IBM Automatic Server Restart driver");403403+MODULE_AUTHOR("Andrey Panin");404404+MODULE_LICENSE("GPL");405405+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+252
drivers/char/watchdog/mv64x60_wdt.c
···11+/*22+ * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface33+ *44+ * Author: James Chapman <jchapman@katalix.com>55+ *66+ * Platform-specific setup code should configure the dog to generate77+ * interrupt or reset as required. This code only enables/disables88+ * and services the watchdog.99+ *1010+ * Derived from mpc8xx_wdt.c, with the following copyright.1111+ * 1212+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under1313+ * the terms of the GNU General Public License version 2. This program1414+ * is licensed "as is" without any warranty of any kind, whether express1515+ * or implied.1616+ */1717+1818+#include <linux/config.h>1919+#include <linux/fs.h>2020+#include <linux/init.h>2121+#include <linux/kernel.h>2222+#include <linux/miscdevice.h>2323+#include <linux/module.h>2424+#include <linux/watchdog.h>2525+#include <asm/mv64x60.h>2626+#include <asm/uaccess.h>2727+#include <asm/io.h>2828+2929+/* MV64x60 WDC (config) register access definitions */3030+#define MV64x60_WDC_CTL1_MASK (3 << 24)3131+#define MV64x60_WDC_CTL1(val) ((val & 3) << 24)3232+#define MV64x60_WDC_CTL2_MASK (3 << 26)3333+#define MV64x60_WDC_CTL2(val) ((val & 3) << 26)3434+3535+/* Flags bits */3636+#define MV64x60_WDOG_FLAG_OPENED 03737+#define MV64x60_WDOG_FLAG_ENABLED 13838+3939+static unsigned long wdt_flags;4040+static int wdt_status;4141+static void __iomem *mv64x60_regs;4242+static int mv64x60_wdt_timeout;4343+4444+static void mv64x60_wdt_reg_write(u32 val)4545+{4646+ /* Allow write only to CTL1 / CTL2 fields, retaining values in4747+ * other fields.4848+ */4949+ u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);5050+ data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);5151+ data |= val;5252+ writel(data, mv64x60_regs + MV64x60_WDT_WDC);5353+}5454+5555+static void mv64x60_wdt_service(void)5656+{5757+ /* Write 01 followed by 10 to CTL2 */5858+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));5959+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));6060+}6161+6262+static void mv64x60_wdt_handler_disable(void)6363+{6464+ if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {6565+ /* Write 01 followed by 10 to CTL1 */6666+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));6767+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));6868+ printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");6969+ }7070+}7171+7272+static void mv64x60_wdt_handler_enable(void)7373+{7474+ if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {7575+ /* Write 01 followed by 10 to CTL1 */7676+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));7777+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));7878+ printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");7979+ }8080+}8181+8282+static int mv64x60_wdt_open(struct inode *inode, struct file *file)8383+{8484+ if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))8585+ return -EBUSY;8686+8787+ mv64x60_wdt_service();8888+ mv64x60_wdt_handler_enable();8989+9090+ return 0;9191+}9292+9393+static int mv64x60_wdt_release(struct inode *inode, struct file *file)9494+{9595+ mv64x60_wdt_service();9696+9797+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)9898+ mv64x60_wdt_handler_disable();9999+#endif100100+101101+ clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);102102+103103+ return 0;104104+}105105+106106+static ssize_t mv64x60_wdt_write(struct file *file, const char *data,107107+ size_t len, loff_t * ppos)108108+{109109+ if (*ppos != file->f_pos)110110+ return -ESPIPE;111111+112112+ if (len)113113+ mv64x60_wdt_service();114114+115115+ return len;116116+}117117+118118+static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,119119+ unsigned int cmd, unsigned long arg)120120+{121121+ int timeout;122122+ static struct watchdog_info info = {123123+ .options = WDIOF_KEEPALIVEPING,124124+ .firmware_version = 0,125125+ .identity = "MV64x60 watchdog",126126+ };127127+128128+ switch (cmd) {129129+ case WDIOC_GETSUPPORT:130130+ if (copy_to_user((void *)arg, &info, sizeof(info)))131131+ return -EFAULT;132132+ break;133133+134134+ case WDIOC_GETSTATUS:135135+ case WDIOC_GETBOOTSTATUS:136136+ if (put_user(wdt_status, (int *)arg))137137+ return -EFAULT;138138+ wdt_status &= ~WDIOF_KEEPALIVEPING;139139+ break;140140+141141+ case WDIOC_GETTEMP:142142+ return -EOPNOTSUPP;143143+144144+ case WDIOC_SETOPTIONS:145145+ return -EOPNOTSUPP;146146+147147+ case WDIOC_KEEPALIVE:148148+ mv64x60_wdt_service();149149+ wdt_status |= WDIOF_KEEPALIVEPING;150150+ break;151151+152152+ case WDIOC_SETTIMEOUT:153153+ return -EOPNOTSUPP;154154+155155+ case WDIOC_GETTIMEOUT:156156+ timeout = mv64x60_wdt_timeout * HZ;157157+ if (put_user(timeout, (int *)arg))158158+ return -EFAULT;159159+ break;160160+161161+ default:162162+ return -ENOIOCTLCMD;163163+ }164164+165165+ return 0;166166+}167167+168168+static struct file_operations mv64x60_wdt_fops = {169169+ .owner = THIS_MODULE,170170+ .llseek = no_llseek,171171+ .write = mv64x60_wdt_write,172172+ .ioctl = mv64x60_wdt_ioctl,173173+ .open = mv64x60_wdt_open,174174+ .release = mv64x60_wdt_release,175175+};176176+177177+static struct miscdevice mv64x60_wdt_miscdev = {178178+ .minor = WATCHDOG_MINOR,179179+ .name = "watchdog",180180+ .fops = &mv64x60_wdt_fops,181181+};182182+183183+static int __devinit mv64x60_wdt_probe(struct device *dev)184184+{185185+ struct platform_device *pd = to_platform_device(dev);186186+ struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data;187187+ int bus_clk = 133;188188+189189+ mv64x60_wdt_timeout = 10;190190+ if (pdata) {191191+ mv64x60_wdt_timeout = pdata->timeout;192192+ bus_clk = pdata->bus_clk;193193+ }194194+195195+ mv64x60_regs = mv64x60_get_bridge_vbase();196196+197197+ writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,198198+ mv64x60_regs + MV64x60_WDT_WDC);199199+200200+ return misc_register(&mv64x60_wdt_miscdev);201201+}202202+203203+static int __devexit mv64x60_wdt_remove(struct device *dev)204204+{205205+ misc_deregister(&mv64x60_wdt_miscdev);206206+207207+ mv64x60_wdt_service();208208+ mv64x60_wdt_handler_disable();209209+210210+ return 0;211211+}212212+213213+static struct device_driver mv64x60_wdt_driver = {214214+ .name = MV64x60_WDT_NAME,215215+ .bus = &platform_bus_type,216216+ .probe = mv64x60_wdt_probe,217217+ .remove = __devexit_p(mv64x60_wdt_remove),218218+};219219+220220+static struct platform_device *mv64x60_wdt_dev;221221+222222+static int __init mv64x60_wdt_init(void)223223+{224224+ int ret;225225+226226+ printk(KERN_INFO "MV64x60 watchdog driver\n");227227+228228+ mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME,229229+ -1, NULL, 0);230230+ if (IS_ERR(mv64x60_wdt_dev)) {231231+ ret = PTR_ERR(mv64x60_wdt_dev);232232+ goto out;233233+ }234234+235235+ ret = driver_register(&mv64x60_wdt_driver);236236+ out:237237+ return ret;238238+}239239+240240+static void __exit mv64x60_wdt_exit(void)241241+{242242+ driver_unregister(&mv64x60_wdt_driver);243243+ platform_device_unregister(mv64x60_wdt_dev);244244+}245245+246246+module_init(mv64x60_wdt_init);247247+module_exit(mv64x60_wdt_exit);248248+249249+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");250250+MODULE_DESCRIPTION("MV64x60 watchdog driver");251251+MODULE_LICENSE("GPL");252252+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+23-19
drivers/char/watchdog/pcwd_pci.c
···2929 * Includes, defines, variables, module parameters, ...3030 */31313232-#include <linux/config.h>3333-#include <linux/module.h>3434-#include <linux/moduleparam.h>3535-#include <linux/types.h>3636-#include <linux/delay.h>3737-#include <linux/miscdevice.h>3838-#include <linux/watchdog.h>3939-#include <linux/notifier.h>4040-#include <linux/reboot.h>4141-#include <linux/init.h>4242-#include <linux/fs.h>4343-#include <linux/pci.h>4444-#include <linux/ioport.h>4545-#include <linux/spinlock.h>3232+#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */3333+#include <linux/module.h> /* For module specific items */3434+#include <linux/moduleparam.h> /* For new moduleparam's */3535+#include <linux/types.h> /* For standard types (like size_t) */3636+#include <linux/errno.h> /* For the -ENODEV/... values */3737+#include <linux/kernel.h> /* For printk/panic/... */3838+#include <linux/delay.h> /* For mdelay function */3939+#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */4040+#include <linux/watchdog.h> /* For the watchdog specific items */4141+#include <linux/notifier.h> /* For notifier support */4242+#include <linux/reboot.h> /* For reboot_notifier stuff */4343+#include <linux/init.h> /* For __init/__exit/... */4444+#include <linux/fs.h> /* For file operations */4545+#include <linux/pci.h> /* For pci functions */4646+#include <linux/ioport.h> /* For io-port access */4747+#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */46484747-#include <asm/uaccess.h>4848-#include <asm/io.h>4949+#include <asm/uaccess.h> /* For copy_to_user/put_user/... */5050+#include <asm/io.h> /* For inb/outb/... */49515052/* Module and version information */5153#define WATCHDOG_VERSION "1.01"5252-#define WATCHDOG_DATE "15 Mar 2005"5454+#define WATCHDOG_DATE "02 Sep 2005"5355#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"5456#define WATCHDOG_NAME "pcwd_pci"5557#define PFX WATCHDOG_NAME ": "···337335 return -EFAULT;338336339337 if (new_options & WDIOS_DISABLECARD) {340340- pcipcwd_stop();338338+ if (pcipcwd_stop())339339+ return -EIO;341340 retval = 0;342341 }343342344343 if (new_options & WDIOS_ENABLECARD) {345345- pcipcwd_start();344344+ if (pcipcwd_start())345345+ return -EIO;346346 retval = 0;347347 }348348
+1-1
drivers/char/watchdog/s3c2410_wdt.c
···464464static unsigned long wtcon_save;465465static unsigned long wtdat_save;466466467467-static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level)467467+static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level)468468{469469 if (level == SUSPEND_POWER_DOWN) {470470 /* Save watchdog state, and turn it off. */
+414
drivers/char/watchdog/sbc8360.c
···11+/*22+ * SBC8360 Watchdog driver33+ *44+ * (c) Copyright 2005 Webcon, Inc.55+ *66+ * Based on ib700wdt.c, which is based on advantechwdt.c which is based77+ * on acquirewdt.c which is based on wdt.c.88+ *99+ * (c) Copyright 2001 Charles Howes <chowes@vsol.net>1010+ *1111+ * Based on advantechwdt.c which is based on acquirewdt.c which1212+ * is based on wdt.c.1313+ *1414+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>1515+ *1616+ * Based on acquirewdt.c which is based on wdt.c.1717+ * Original copyright messages:1818+ *1919+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.2020+ * http://www.redhat.com2121+ *2222+ * This program is free software; you can redistribute it and/or2323+ * modify it under the terms of the GNU General Public License2424+ * as published by the Free Software Foundation; either version2525+ * 2 of the License, or (at your option) any later version.2626+ *2727+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide2828+ * warranty for any of this software. This material is provided2929+ * "AS-IS" and at no charge.3030+ *3131+ * (c) Copyright 1995 Alan Cox <alan@redhat.com>3232+ *3333+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>3434+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT3535+ * Added timeout module option to override default3636+ *3737+ */3838+3939+#include <linux/config.h>4040+#include <linux/module.h>4141+#include <linux/types.h>4242+#include <linux/miscdevice.h>4343+#include <linux/watchdog.h>4444+#include <linux/ioport.h>4545+#include <linux/delay.h>4646+#include <linux/notifier.h>4747+#include <linux/fs.h>4848+#include <linux/reboot.h>4949+#include <linux/init.h>5050+#include <linux/spinlock.h>5151+#include <linux/moduleparam.h>5252+5353+#include <asm/io.h>5454+#include <asm/uaccess.h>5555+#include <asm/system.h>5656+5757+static unsigned long sbc8360_is_open;5858+static spinlock_t sbc8360_lock;5959+static char expect_close;6060+6161+#define PFX "sbc8360: "6262+6363+/*6464+ *6565+ * Watchdog Timer Configuration6666+ *6767+ * The function of the watchdog timer is to reset the system automatically6868+ * and is defined at I/O port 0120H and 0121H. To enable the watchdog timer6969+ * and allow the system to reset, write appropriate values from the table7070+ * below to I/O port 0120H and 0121H. To disable the timer, write a zero7171+ * value to I/O port 0121H for the system to stop the watchdog function.7272+ *7373+ * The following describes how the timer should be programmed (according to7474+ * the vendor documentation)7575+ *7676+ * Enabling Watchdog:7777+ * MOV AX,000AH (enable, phase I)7878+ * MOV DX,0120H7979+ * OUT DX,AX8080+ * MOV AX,000BH (enable, phase II)8181+ * MOV DX,0120H8282+ * OUT DX,AX8383+ * MOV AX,000nH (set multiplier n, from 1-4)8484+ * MOV DX,0120H8585+ * OUT DX,AX8686+ * MOV AX,000mH (set base timer m, from 0-F)8787+ * MOV DX,0121H8888+ * OUT DX,AX8989+ *9090+ * Reset timer:9191+ * MOV AX,000mH (same as set base timer, above)9292+ * MOV DX,0121H9393+ * OUT DX,AX9494+ *9595+ * Disabling Watchdog:9696+ * MOV AX,0000H (a zero value)9797+ * MOV DX,0120H9898+ * OUT DX,AX9999+ *100100+ * Watchdog timeout configuration values:101101+ * N102102+ * M | 1 2 3 4103103+ * --|----------------------------------104104+ * 0 | 0.5s 5s 50s 100s105105+ * 1 | 1s 10s 100s 200s106106+ * 2 | 1.5s 15s 150s 300s107107+ * 3 | 2s 20s 200s 400s108108+ * 4 | 2.5s 25s 250s 500s109109+ * 5 | 3s 30s 300s 600s110110+ * 6 | 3.5s 35s 350s 700s111111+ * 7 | 4s 40s 400s 800s112112+ * 8 | 4.5s 45s 450s 900s113113+ * 9 | 5s 50s 500s 1000s114114+ * A | 5.5s 55s 550s 1100s115115+ * B | 6s 60s 600s 1200s116116+ * C | 6.5s 65s 650s 1300s117117+ * D | 7s 70s 700s 1400s118118+ * E | 7.5s 75s 750s 1500s119119+ * F | 8s 80s 800s 1600s120120+ *121121+ * Another way to say the same things is:122122+ * For N=1, Timeout = (M+1) * 0.5s123123+ * For N=2, Timeout = (M+1) * 5s124124+ * For N=3, Timeout = (M+1) * 50s125125+ * For N=4, Timeout = (M+1) * 100s126126+ *127127+ */128128+129129+static int wd_times[64][2] = {130130+ {0, 1}, /* 0 = 0.5s */131131+ {1, 1}, /* 1 = 1s */132132+ {2, 1}, /* 2 = 1.5s */133133+ {3, 1}, /* 3 = 2s */134134+ {4, 1}, /* 4 = 2.5s */135135+ {5, 1}, /* 5 = 3s */136136+ {6, 1}, /* 6 = 3.5s */137137+ {7, 1}, /* 7 = 4s */138138+ {8, 1}, /* 8 = 4.5s */139139+ {9, 1}, /* 9 = 5s */140140+ {0xA, 1}, /* 10 = 5.5s */141141+ {0xB, 1}, /* 11 = 6s */142142+ {0xC, 1}, /* 12 = 6.5s */143143+ {0xD, 1}, /* 13 = 7s */144144+ {0xE, 1}, /* 14 = 7.5s */145145+ {0xF, 1}, /* 15 = 8s */146146+ {0, 2}, /* 16 = 5s */147147+ {1, 2}, /* 17 = 10s */148148+ {2, 2}, /* 18 = 15s */149149+ {3, 2}, /* 19 = 20s */150150+ {4, 2}, /* 20 = 25s */151151+ {5, 2}, /* 21 = 30s */152152+ {6, 2}, /* 22 = 35s */153153+ {7, 2}, /* 23 = 40s */154154+ {8, 2}, /* 24 = 45s */155155+ {9, 2}, /* 25 = 50s */156156+ {0xA, 2}, /* 26 = 55s */157157+ {0xB, 2}, /* 27 = 60s */158158+ {0xC, 2}, /* 28 = 65s */159159+ {0xD, 2}, /* 29 = 70s */160160+ {0xE, 2}, /* 30 = 75s */161161+ {0xF, 2}, /* 31 = 80s */162162+ {0, 3}, /* 32 = 50s */163163+ {1, 3}, /* 33 = 100s */164164+ {2, 3}, /* 34 = 150s */165165+ {3, 3}, /* 35 = 200s */166166+ {4, 3}, /* 36 = 250s */167167+ {5, 3}, /* 37 = 300s */168168+ {6, 3}, /* 38 = 350s */169169+ {7, 3}, /* 39 = 400s */170170+ {8, 3}, /* 40 = 450s */171171+ {9, 3}, /* 41 = 500s */172172+ {0xA, 3}, /* 42 = 550s */173173+ {0xB, 3}, /* 43 = 600s */174174+ {0xC, 3}, /* 44 = 650s */175175+ {0xD, 3}, /* 45 = 700s */176176+ {0xE, 3}, /* 46 = 750s */177177+ {0xF, 3}, /* 47 = 800s */178178+ {0, 4}, /* 48 = 100s */179179+ {1, 4}, /* 49 = 200s */180180+ {2, 4}, /* 50 = 300s */181181+ {3, 4}, /* 51 = 400s */182182+ {4, 4}, /* 52 = 500s */183183+ {5, 4}, /* 53 = 600s */184184+ {6, 4}, /* 54 = 700s */185185+ {7, 4}, /* 55 = 800s */186186+ {8, 4}, /* 56 = 900s */187187+ {9, 4}, /* 57 = 1000s */188188+ {0xA, 4}, /* 58 = 1100s */189189+ {0xB, 4}, /* 59 = 1200s */190190+ {0xC, 4}, /* 60 = 1300s */191191+ {0xD, 4}, /* 61 = 1400s */192192+ {0xE, 4}, /* 62 = 1500s */193193+ {0xF, 4} /* 63 = 1600s */194194+};195195+196196+#define SBC8360_ENABLE 0x120197197+#define SBC8360_BASETIME 0x121198198+199199+static int timeout = 27;200200+static int wd_margin = 0xB;201201+static int wd_multiplier = 2;202202+static int nowayout = WATCHDOG_NOWAYOUT;203203+204204+module_param(timeout, int, 27);205205+MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");206206+module_param(nowayout, int, 0);207207+MODULE_PARM_DESC(nowayout,208208+ "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");209209+210210+/*211211+ * Kernel methods.212212+ */213213+214214+/* Activate and pre-configure watchdog */215215+static void sbc8360_activate(void)216216+{217217+ /* Enable the watchdog */218218+ outb(0x0A, SBC8360_ENABLE);219219+ msleep_interruptible(100);220220+ outb(0x0B, SBC8360_ENABLE);221221+ msleep_interruptible(100);222222+ /* Set timeout multiplier */223223+ outb(wd_multiplier, SBC8360_ENABLE);224224+ msleep_interruptible(100);225225+ /* Nothing happens until first sbc8360_ping() */226226+}227227+228228+/* Kernel pings watchdog */229229+static void sbc8360_ping(void)230230+{231231+ /* Write the base timer register */232232+ outb(wd_margin, SBC8360_BASETIME);233233+}234234+235235+/* Userspace pings kernel driver, or requests clean close */236236+static ssize_t sbc8360_write(struct file *file, const char __user * buf,237237+ size_t count, loff_t * ppos)238238+{239239+ if (count) {240240+ if (!nowayout) {241241+ size_t i;242242+243243+ /* In case it was set long ago */244244+ expect_close = 0;245245+246246+ for (i = 0; i != count; i++) {247247+ char c;248248+ if (get_user(c, buf + i))249249+ return -EFAULT;250250+ if (c == 'V')251251+ expect_close = 42;252252+ }253253+ }254254+ sbc8360_ping();255255+ }256256+ return count;257257+}258258+259259+static int sbc8360_open(struct inode *inode, struct file *file)260260+{261261+ spin_lock(&sbc8360_lock);262262+ if (test_and_set_bit(0, &sbc8360_is_open)) {263263+ spin_unlock(&sbc8360_lock);264264+ return -EBUSY;265265+ }266266+ if (nowayout)267267+ __module_get(THIS_MODULE);268268+269269+ /* Activate and ping once to start the countdown */270270+ spin_unlock(&sbc8360_lock);271271+ sbc8360_activate();272272+ sbc8360_ping();273273+ return nonseekable_open(inode, file);274274+}275275+276276+static int sbc8360_close(struct inode *inode, struct file *file)277277+{278278+ spin_lock(&sbc8360_lock);279279+ if (expect_close == 42)280280+ outb(0, SBC8360_ENABLE);281281+ else282282+ printk(KERN_CRIT PFX283283+ "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n");284284+285285+ clear_bit(0, &sbc8360_is_open);286286+ expect_close = 0;287287+ spin_unlock(&sbc8360_lock);288288+ return 0;289289+}290290+291291+/*292292+ * Notifier for system down293293+ */294294+295295+static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,296296+ void *unused)297297+{298298+ if (code == SYS_DOWN || code == SYS_HALT) {299299+ /* Disable the SBC8360 Watchdog */300300+ outb(0, SBC8360_ENABLE);301301+ }302302+ return NOTIFY_DONE;303303+}304304+305305+/*306306+ * Kernel Interfaces307307+ */308308+309309+static struct file_operations sbc8360_fops = {310310+ .owner = THIS_MODULE,311311+ .llseek = no_llseek,312312+ .write = sbc8360_write,313313+ .open = sbc8360_open,314314+ .release = sbc8360_close,315315+};316316+317317+static struct miscdevice sbc8360_miscdev = {318318+ .minor = WATCHDOG_MINOR,319319+ .name = "watchdog",320320+ .fops = &sbc8360_fops,321321+};322322+323323+/*324324+ * The SBC8360 needs to learn about soft shutdowns in order to325325+ * turn the timebomb registers off.326326+ */327327+328328+static struct notifier_block sbc8360_notifier = {329329+ .notifier_call = sbc8360_notify_sys,330330+};331331+332332+static int __init sbc8360_init(void)333333+{334334+ int res;335335+ unsigned long int mseconds = 60000;336336+337337+ spin_lock_init(&sbc8360_lock);338338+ res = misc_register(&sbc8360_miscdev);339339+ if (res) {340340+ printk(KERN_ERR PFX "failed to register misc device\n");341341+ goto out_nomisc;342342+ }343343+344344+ if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {345345+ printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",346346+ SBC8360_ENABLE);347347+ res = -EIO;348348+ goto out_noenablereg;349349+ }350350+ if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {351351+ printk(KERN_ERR PFX352352+ "BASETIME method I/O %X is not available.\n",353353+ SBC8360_BASETIME);354354+ res = -EIO;355355+ goto out_nobasetimereg;356356+ }357357+358358+ res = register_reboot_notifier(&sbc8360_notifier);359359+ if (res) {360360+ printk(KERN_ERR PFX "Failed to register reboot notifier.\n");361361+ goto out_noreboot;362362+ }363363+364364+ if (timeout < 0 || timeout > 63) {365365+ printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");366366+ res = -EINVAL;367367+ goto out_noreboot;368368+ }369369+370370+ wd_margin = wd_times[timeout][0];371371+ wd_multiplier = wd_times[timeout][1];372372+373373+ if (wd_multiplier == 1)374374+ mseconds = (wd_margin + 1) * 500;375375+ else if (wd_multiplier == 2)376376+ mseconds = (wd_margin + 1) * 5000;377377+ else if (wd_multiplier == 3)378378+ mseconds = (wd_margin + 1) * 50000;379379+ else if (wd_multiplier == 4)380380+ mseconds = (wd_margin + 1) * 100000;381381+382382+ /* My kingdom for the ability to print "0.5 seconds" in the kernel! */383383+ printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);384384+385385+ return 0;386386+387387+ out_noreboot:388388+ release_region(SBC8360_ENABLE, 1);389389+ release_region(SBC8360_BASETIME, 1);390390+ out_noenablereg:391391+ out_nobasetimereg:392392+ misc_deregister(&sbc8360_miscdev);393393+ out_nomisc:394394+ return res;395395+}396396+397397+static void __exit sbc8360_exit(void)398398+{399399+ misc_deregister(&sbc8360_miscdev);400400+ unregister_reboot_notifier(&sbc8360_notifier);401401+ release_region(SBC8360_ENABLE, 1);402402+ release_region(SBC8360_BASETIME, 1);403403+}404404+405405+module_init(sbc8360_init);406406+module_exit(sbc8360_exit);407407+408408+MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");409409+MODULE_DESCRIPTION("SBC8360 watchdog driver");410410+MODULE_LICENSE("GPL");411411+MODULE_VERSION("1.0");412412+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);413413+414414+/* end of sbc8360.c */
+543
drivers/char/watchdog/w83977f_wdt.c
···11+/*22+ * W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip33+ *44+ * (c) Copyright 2005 Jose Goncalves <jose.goncalves@inov.pt>55+ *66+ * Based on w83877f_wdt.c by Scott Jennings,77+ * and wdt977.c by Woody Suwalski88+ *99+ * -----------------------1010+ *1111+ * This program is free software; you can redistribute it and/or1212+ * modify it under the terms of the GNU General Public License1313+ * as published by the Free Software Foundation; either version1414+ * 2 of the License, or (at your option) any later version.1515+ *1616+ */1717+1818+#include <linux/module.h>1919+#include <linux/moduleparam.h>2020+#include <linux/config.h>2121+#include <linux/types.h>2222+#include <linux/kernel.h>2323+#include <linux/fs.h>2424+#include <linux/miscdevice.h>2525+#include <linux/init.h>2626+#include <linux/ioport.h>2727+#include <linux/watchdog.h>2828+#include <linux/notifier.h>2929+#include <linux/reboot.h>3030+3131+#include <asm/io.h>3232+#include <asm/system.h>3333+#include <asm/uaccess.h>3434+3535+#define WATCHDOG_VERSION "1.00"3636+#define WATCHDOG_NAME "W83977F WDT"3737+#define PFX WATCHDOG_NAME ": "3838+#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"3939+4040+#define IO_INDEX_PORT 0x3F04141+#define IO_DATA_PORT (IO_INDEX_PORT+1)4242+4343+#define UNLOCK_DATA 0x874444+#define LOCK_DATA 0xAA4545+#define DEVICE_REGISTER 0x074646+4747+#define DEFAULT_TIMEOUT 45 /* default timeout in seconds */4848+4949+static int timeout = DEFAULT_TIMEOUT;5050+static int timeoutW; /* timeout in watchdog counter units */5151+static unsigned long timer_alive;5252+static int testmode;5353+static char expect_close;5454+static spinlock_t spinlock;5555+5656+module_param(timeout, int, 0);5757+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");5858+module_param(testmode, int, 0);5959+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");6060+6161+static int nowayout = WATCHDOG_NOWAYOUT;6262+module_param(nowayout, int, 0);6363+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");6464+6565+/*6666+ * Start the watchdog6767+ */6868+6969+static int wdt_start(void)7070+{7171+ unsigned long flags;7272+7373+ spin_lock_irqsave(&spinlock, flags);7474+7575+ /* Unlock the SuperIO chip */7676+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);7777+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);7878+7979+ /*8080+ * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.8181+ * F2 has the timeout in watchdog counter units.8282+ * F3 is set to enable watchdog LED blink at timeout.8383+ * F4 is used to just clear the TIMEOUT'ed state (bit 0).8484+ */8585+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);8686+ outb_p(0x08,IO_DATA_PORT);8787+ outb_p(0xF2,IO_INDEX_PORT);8888+ outb_p(timeoutW,IO_DATA_PORT);8989+ outb_p(0xF3,IO_INDEX_PORT);9090+ outb_p(0x08,IO_DATA_PORT);9191+ outb_p(0xF4,IO_INDEX_PORT);9292+ outb_p(0x00,IO_DATA_PORT);9393+9494+ /* Set device Aux2 active */9595+ outb_p(0x30,IO_INDEX_PORT);9696+ outb_p(0x01,IO_DATA_PORT);9797+9898+ /* 9999+ * Select device Aux1 (dev=7) to set GP16 as the watchdog output100100+ * (in reg E6) and GP13 as the watchdog LED output (in reg E3).101101+ * Map GP16 at pin 119.102102+ * In test mode watch the bit 0 on F4 to indicate "triggered" or103103+ * check watchdog LED on SBC.104104+ */105105+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);106106+ outb_p(0x07,IO_DATA_PORT);107107+ if (!testmode)108108+ {109109+ unsigned pin_map;110110+111111+ outb_p(0xE6,IO_INDEX_PORT);112112+ outb_p(0x0A,IO_DATA_PORT);113113+ outb_p(0x2C,IO_INDEX_PORT);114114+ pin_map = inb_p(IO_DATA_PORT);115115+ pin_map |= 0x10;116116+ pin_map &= ~(0x20);117117+ outb_p(0x2C,IO_INDEX_PORT);118118+ outb_p(pin_map,IO_DATA_PORT);119119+ }120120+ outb_p(0xE3,IO_INDEX_PORT);121121+ outb_p(0x08,IO_DATA_PORT);122122+123123+ /* Set device Aux1 active */124124+ outb_p(0x30,IO_INDEX_PORT);125125+ outb_p(0x01,IO_DATA_PORT);126126+127127+ /* Lock the SuperIO chip */128128+ outb_p(LOCK_DATA,IO_INDEX_PORT);129129+130130+ spin_unlock_irqrestore(&spinlock, flags);131131+132132+ printk(KERN_INFO PFX "activated.\n");133133+134134+ return 0;135135+}136136+137137+/*138138+ * Stop the watchdog139139+ */140140+141141+static int wdt_stop(void)142142+{143143+ unsigned long flags;144144+145145+ spin_lock_irqsave(&spinlock, flags);146146+147147+ /* Unlock the SuperIO chip */148148+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);149149+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);150150+151151+ /* 152152+ * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.153153+ * F2 is reset to its default value (watchdog timer disabled).154154+ * F3 is reset to its default state.155155+ * F4 clears the TIMEOUT'ed state (bit 0) - back to default.156156+ */157157+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);158158+ outb_p(0x08,IO_DATA_PORT);159159+ outb_p(0xF2,IO_INDEX_PORT);160160+ outb_p(0xFF,IO_DATA_PORT);161161+ outb_p(0xF3,IO_INDEX_PORT);162162+ outb_p(0x00,IO_DATA_PORT);163163+ outb_p(0xF4,IO_INDEX_PORT);164164+ outb_p(0x00,IO_DATA_PORT);165165+ outb_p(0xF2,IO_INDEX_PORT);166166+ outb_p(0x00,IO_DATA_PORT);167167+168168+ /*169169+ * Select device Aux1 (dev=7) to set GP16 (in reg E6) and 170170+ * Gp13 (in reg E3) as inputs.171171+ */172172+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);173173+ outb_p(0x07,IO_DATA_PORT);174174+ if (!testmode)175175+ {176176+ outb_p(0xE6,IO_INDEX_PORT);177177+ outb_p(0x01,IO_DATA_PORT);178178+ }179179+ outb_p(0xE3,IO_INDEX_PORT);180180+ outb_p(0x01,IO_DATA_PORT);181181+182182+ /* Lock the SuperIO chip */183183+ outb_p(LOCK_DATA,IO_INDEX_PORT);184184+185185+ spin_unlock_irqrestore(&spinlock, flags);186186+187187+ printk(KERN_INFO PFX "shutdown.\n");188188+189189+ return 0;190190+}191191+192192+/*193193+ * Send a keepalive ping to the watchdog194194+ * This is done by simply re-writing the timeout to reg. 0xF2195195+ */196196+197197+static int wdt_keepalive(void)198198+{199199+ unsigned long flags;200200+201201+ spin_lock_irqsave(&spinlock, flags);202202+203203+ /* Unlock the SuperIO chip */204204+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);205205+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);206206+207207+ /* Select device Aux2 (device=8) to kick watchdog reg F2 */208208+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);209209+ outb_p(0x08,IO_DATA_PORT);210210+ outb_p(0xF2,IO_INDEX_PORT);211211+ outb_p(timeoutW,IO_DATA_PORT);212212+213213+ /* Lock the SuperIO chip */214214+ outb_p(LOCK_DATA,IO_INDEX_PORT);215215+216216+ spin_unlock_irqrestore(&spinlock, flags);217217+218218+ return 0;219219+}220220+221221+/*222222+ * Set the watchdog timeout value223223+ */224224+225225+static int wdt_set_timeout(int t)226226+{227227+ int tmrval;228228+229229+ /*230230+ * Convert seconds to watchdog counter time units, rounding up.231231+ * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup 232232+ * value. This information is supplied in the PCM-5335 manual and was233233+ * checked by me on a real board. This is a bit strange because W83977f234234+ * datasheet says counter unit is in minutes!235235+ */236236+ if (t < 15)237237+ return -EINVAL;238238+239239+ tmrval = ((t + 15) + 29) / 30;240240+241241+ if (tmrval > 255)242242+ return -EINVAL;243243+244244+ /*245245+ * timeout is the timeout in seconds, 246246+ * timeoutW is the timeout in watchdog counter units.247247+ */248248+ timeoutW = tmrval;249249+ timeout = (timeoutW * 30) - 15;250250+ return 0;251251+}252252+253253+/*254254+ * Get the watchdog status255255+ */256256+257257+static int wdt_get_status(int *status)258258+{259259+ int new_status;260260+ unsigned long flags;261261+262262+ spin_lock_irqsave(&spinlock, flags);263263+264264+ /* Unlock the SuperIO chip */265265+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);266266+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);267267+268268+ /* Select device Aux2 (device=8) to read watchdog reg F4 */269269+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);270270+ outb_p(0x08,IO_DATA_PORT);271271+ outb_p(0xF4,IO_INDEX_PORT);272272+ new_status = inb_p(IO_DATA_PORT);273273+274274+ /* Lock the SuperIO chip */275275+ outb_p(LOCK_DATA,IO_INDEX_PORT);276276+277277+ spin_unlock_irqrestore(&spinlock, flags);278278+279279+ *status = 0;280280+ if (new_status & 1)281281+ *status |= WDIOF_CARDRESET;282282+283283+ return 0;284284+}285285+286286+287287+/*288288+ * /dev/watchdog handling289289+ */290290+291291+static int wdt_open(struct inode *inode, struct file *file)292292+{293293+ /* If the watchdog is alive we don't need to start it again */294294+ if( test_and_set_bit(0, &timer_alive) )295295+ return -EBUSY;296296+297297+ if (nowayout)298298+ __module_get(THIS_MODULE);299299+300300+ wdt_start();301301+ return nonseekable_open(inode, file);302302+}303303+304304+static int wdt_release(struct inode *inode, struct file *file)305305+{306306+ /*307307+ * Shut off the timer.308308+ * Lock it in if it's a module and we set nowayout309309+ */310310+ if (expect_close == 42)311311+ {312312+ wdt_stop();313313+ clear_bit(0, &timer_alive);314314+ } else {315315+ wdt_keepalive();316316+ printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");317317+ }318318+ expect_close = 0;319319+ return 0;320320+}321321+322322+/*323323+ * wdt_write:324324+ * @file: file handle to the watchdog325325+ * @buf: buffer to write (unused as data does not matter here326326+ * @count: count of bytes327327+ * @ppos: pointer to the position to write. No seeks allowed328328+ *329329+ * A write to a watchdog device is defined as a keepalive signal. Any330330+ * write of data will do, as we we don't define content meaning.331331+ */332332+333333+static ssize_t wdt_write(struct file *file, const char __user *buf,334334+ size_t count, loff_t *ppos)335335+{336336+ /* See if we got the magic character 'V' and reload the timer */337337+ if(count)338338+ {339339+ if (!nowayout)340340+ {341341+ size_t ofs;342342+343343+ /* note: just in case someone wrote the magic character long ago */344344+ expect_close = 0;345345+346346+ /* scan to see whether or not we got the magic character */347347+ for(ofs = 0; ofs != count; ofs++)348348+ {349349+ char c;350350+ if (get_user(c, buf + ofs))351351+ return -EFAULT;352352+ if (c == 'V') {353353+ expect_close = 42;354354+ }355355+ }356356+ }357357+358358+ /* someone wrote to us, we should restart timer */359359+ wdt_keepalive();360360+ }361361+ return count;362362+}363363+364364+/*365365+ * wdt_ioctl:366366+ * @inode: inode of the device367367+ * @file: file handle to the device368368+ * @cmd: watchdog command369369+ * @arg: argument pointer370370+ *371371+ * The watchdog API defines a common set of functions for all watchdogs372372+ * according to their available features.373373+ */374374+375375+static struct watchdog_info ident = {376376+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,377377+ .firmware_version = 1,378378+ .identity = WATCHDOG_NAME,379379+};380380+381381+static int wdt_ioctl(struct inode *inode, struct file *file,382382+ unsigned int cmd, unsigned long arg)383383+{384384+ int status;385385+ int new_options, retval = -EINVAL;386386+ int new_timeout;387387+ union {388388+ struct watchdog_info __user *ident;389389+ int __user *i;390390+ } uarg;391391+392392+ uarg.i = (int __user *)arg;393393+394394+ switch(cmd)395395+ {396396+ default:397397+ return -ENOIOCTLCMD;398398+399399+ case WDIOC_GETSUPPORT:400400+ return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;401401+402402+ case WDIOC_GETSTATUS:403403+ wdt_get_status(&status);404404+ return put_user(status, uarg.i);405405+406406+ case WDIOC_GETBOOTSTATUS:407407+ return put_user(0, uarg.i);408408+409409+ case WDIOC_KEEPALIVE:410410+ wdt_keepalive();411411+ return 0;412412+413413+ case WDIOC_SETOPTIONS:414414+ if (get_user (new_options, uarg.i))415415+ return -EFAULT;416416+417417+ if (new_options & WDIOS_DISABLECARD) {418418+ wdt_stop();419419+ retval = 0;420420+ }421421+422422+ if (new_options & WDIOS_ENABLECARD) {423423+ wdt_start();424424+ retval = 0;425425+ }426426+427427+ return retval;428428+429429+ case WDIOC_SETTIMEOUT:430430+ if (get_user(new_timeout, uarg.i))431431+ return -EFAULT;432432+433433+ if (wdt_set_timeout(new_timeout))434434+ return -EINVAL;435435+436436+ wdt_keepalive();437437+ /* Fall */438438+439439+ case WDIOC_GETTIMEOUT:440440+ return put_user(timeout, uarg.i);441441+442442+ }443443+}444444+445445+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,446446+ void *unused)447447+{448448+ if (code==SYS_DOWN || code==SYS_HALT)449449+ wdt_stop();450450+ return NOTIFY_DONE;451451+}452452+453453+static struct file_operations wdt_fops=454454+{455455+ .owner = THIS_MODULE,456456+ .llseek = no_llseek,457457+ .write = wdt_write,458458+ .ioctl = wdt_ioctl,459459+ .open = wdt_open,460460+ .release = wdt_release,461461+};462462+463463+static struct miscdevice wdt_miscdev=464464+{465465+ .minor = WATCHDOG_MINOR,466466+ .name = "watchdog",467467+ .fops = &wdt_fops,468468+};469469+470470+static struct notifier_block wdt_notifier = {471471+ .notifier_call = wdt_notify_sys,472472+};473473+474474+static int __init w83977f_wdt_init(void)475475+{476476+ int rc;477477+478478+ printk(KERN_INFO PFX DRIVER_VERSION);479479+480480+ spin_lock_init(&spinlock);481481+482482+ /*483483+ * Check that the timeout value is within it's range ; 484484+ * if not reset to the default485485+ */486486+ if (wdt_set_timeout(timeout)) {487487+ wdt_set_timeout(DEFAULT_TIMEOUT);488488+ printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n",489489+ DEFAULT_TIMEOUT);490490+ }491491+492492+ if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))493493+ {494494+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",495495+ IO_INDEX_PORT);496496+ rc = -EIO;497497+ goto err_out;498498+ }499499+500500+ rc = misc_register(&wdt_miscdev);501501+ if (rc)502502+ {503503+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",504504+ wdt_miscdev.minor, rc);505505+ goto err_out_region;506506+ }507507+508508+ rc = register_reboot_notifier(&wdt_notifier);509509+ if (rc)510510+ {511511+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",512512+ rc);513513+ goto err_out_miscdev;514514+ }515515+516516+ printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",517517+ timeout, nowayout, testmode);518518+519519+ return 0;520520+521521+err_out_miscdev:522522+ misc_deregister(&wdt_miscdev);523523+err_out_region:524524+ release_region(IO_INDEX_PORT,2);525525+err_out:526526+ return rc;527527+}528528+529529+static void __exit w83977f_wdt_exit(void)530530+{531531+ wdt_stop();532532+ misc_deregister(&wdt_miscdev);533533+ unregister_reboot_notifier(&wdt_notifier);534534+ release_region(IO_INDEX_PORT,2);535535+}536536+537537+module_init(w83977f_wdt_init);538538+module_exit(w83977f_wdt_exit);539539+540540+MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>");541541+MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip");542542+MODULE_LICENSE("GPL");543543+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+8
include/asm-ppc/mv64x60.h
···119119120120#define MV64x60_64BIT_WIN_COUNT 24121121122122+/* Watchdog Platform Device, Driver Data */123123+#define MV64x60_WDT_NAME "wdt"124124+125125+struct mv64x60_wdt_pdata {126126+ int timeout; /* watchdog expiry in seconds, default 10 */127127+ int bus_clk; /* bus clock in MHz, default 133 */128128+};129129+122130/*123131 * Define a structure that's used to pass in config information to the124132 * core routines.