X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fwatchdog%2Falim7101_wdt.c;h=bf25d0a55a9954f9683a28c301a918cff349c5e1;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=00baec945048156fe4eddaef1c51ff3bdc6235cb;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c index 00baec945..bf25d0a55 100644 --- a/drivers/char/watchdog/alim7101_wdt.c +++ b/drivers/char/watchdog/alim7101_wdt.c @@ -12,6 +12,11 @@ * because this particular WDT has a very short timeout (1.6 * seconds) and it would be insane to count on any userspace * daemon always getting scheduled within that time frame. + * + * Additions: + * Aug 23, 2004 - Added use_gpio module parameter for use on revision a1d PMUs + * found on very old cobalt hardware. + * -- Mike Waychison */ #include @@ -38,6 +43,8 @@ #define WDT_DISABLE 0x8C #define ALI_7101_WDT 0x92 +#define ALI_7101_GPIO 0x7D +#define ALI_7101_GPIO_O 0x7E #define ALI_WDT_ARM 0x01 /* @@ -57,6 +64,10 @@ static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ t module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); +static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */ +module_param(use_gpio, int, 0); +MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)"); + static void wdt_timer_ping(unsigned long); static struct timer_list timer; static unsigned long next_heartbeat; @@ -64,14 +75,10 @@ static unsigned long wdt_is_open; static char wdt_expect_close; static struct pci_dev *alim7101_pmu; -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - +static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")"); /* * Whack the dog @@ -90,6 +97,13 @@ static void wdt_timer_ping(unsigned long data) pci_read_config_byte(alim7101_pmu, 0x92, &tmp); pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp + | 0x20); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp + & ~0x20); + } } else { printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } @@ -106,11 +120,21 @@ static void wdt_change(int writeval) { char tmp; - pci_read_config_byte(alim7101_pmu, 0x92, &tmp); - if (writeval == WDT_ENABLE) + pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp); + if (writeval == WDT_ENABLE) { pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); - else + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20); + } + + } else { pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); + if (use_gpio) { + pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); + pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20); + } + } } static void wdt_startup(void) @@ -148,12 +172,8 @@ static void wdt_keepalive(void) * /dev/watchdog handling */ -static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) { - /* We can't seek */ - if(ppos != &file->f_pos) - return -ESPIPE; - /* See if we got the magic character 'V' and reload the timer */ if(count) { if (!nowayout) { @@ -185,7 +205,7 @@ static int fop_open(struct inode * inode, struct file * file) return -EBUSY; /* Good, fire up the show */ wdt_startup(); - return 0; + return nonseekable_open(inode, file); } static int fop_close(struct inode * inode, struct file * file) @@ -203,6 +223,8 @@ static int fop_close(struct inode * inode, struct file * file) static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + void __user *argp = (void __user *)arg; + int __user *p = argp; static struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, @@ -213,10 +235,10 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u switch(cmd) { case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - return put_user(0, (int *)arg); + return put_user(0, p); case WDIOC_KEEPALIVE: wdt_keepalive(); return 0; @@ -224,7 +246,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u { int new_options, retval = -EINVAL; - if(get_user(new_options, (int *)arg)) + if(get_user(new_options, p)) return -EFAULT; if(new_options & WDIOS_DISABLECARD) { @@ -243,7 +265,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u { int new_timeout; - if(get_user(new_timeout, (int *)arg)) + if(get_user(new_timeout, p)) return -EFAULT; if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ @@ -254,13 +276,13 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u /* Fall through */ } case WDIOC_GETTIMEOUT: - return put_user(timeout, (int *)arg); + return put_user(timeout, p); default: - return -ENOIOCTLCMD; + return -ENOTTY; } } -static struct file_operations wdt_fops = { +static const struct file_operations wdt_fops = { .owner= THIS_MODULE, .llseek= no_llseek, .write= fop_write, @@ -312,6 +334,7 @@ static void __exit alim7101_wdt_unload(void) /* Deregister */ misc_deregister(&wdt_miscdev); unregister_reboot_notifier(&wdt_notifier); + pci_dev_put(alim7101_pmu); } static int __init alim7101_wdt_init(void) @@ -321,7 +344,8 @@ static int __init alim7101_wdt_init(void) char tmp; printk(KERN_INFO PFX "Steve Hill .\n"); - alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL); + alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + NULL); if (!alim7101_pmu) { printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n"); return -EBUSY; @@ -330,15 +354,23 @@ static int __init alim7101_wdt_init(void) /* Set the WDT in the PMU to 1 second */ pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02); - ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + NULL); if (!ali1543_south) { printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n"); - return -EBUSY; + goto err_out; } pci_read_config_byte(ali1543_south, 0x5e, &tmp); - if ((tmp & 0x1e) != 0x12) { + pci_dev_put(ali1543_south); + if ((tmp & 0x1e) == 0x00) { + if (!use_gpio) { + printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); + goto err_out; + } + nowayout = 1; + } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); - return -EBUSY; + goto err_out; } if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ @@ -366,6 +398,10 @@ static int __init alim7101_wdt_init(void) goto err_out_miscdev; } + if (nowayout) { + __module_get(THIS_MODULE); + } + printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n", timeout, nowayout); return 0; @@ -373,12 +409,23 @@ static int __init alim7101_wdt_init(void) err_out_miscdev: misc_deregister(&wdt_miscdev); err_out: + pci_dev_put(alim7101_pmu); return rc; } module_init(alim7101_wdt_init); module_exit(alim7101_wdt_unload); +static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; + +MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl); + MODULE_AUTHOR("Steve Hill"); MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver"); MODULE_LICENSE("GPL");