qlge: bugfix: Move netif_napi_del() to common call point.
[safe/jmp/linux-2.6] / drivers / watchdog / mpc8xxx_wdt.c
index fa82ec9..38c588e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * mpc83xx_wdt.c - MPC83xx/MPC86xx watchdog userspace interface
+ * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
  *
  * Authors: Dave Updegraff <dave@cray.org>
  *         Kumar Gala <galak@kernel.crashing.org>
@@ -29,7 +29,7 @@
 #include <linux/uaccess.h>
 #include <sysdev/fsl_soc.h>
 
-struct mpc83xx_wdt {
+struct mpc8xxx_wdt {
        __be32 res0;
        __be32 swcrr; /* System watchdog control register */
 #define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
@@ -42,12 +42,13 @@ struct mpc83xx_wdt {
        u8 res2[0xF0];
 };
 
-struct mpc83xx_wdt_type {
+struct mpc8xxx_wdt_type {
        int prescaler;
        bool hw_enabled;
 };
 
-static struct mpc83xx_wdt __iomem *wd_base;
+static struct mpc8xxx_wdt __iomem *wd_base;
+static int mpc8xxx_wdt_init_late(void);
 
 static u16 timeout = 0xffff;
 module_param(timeout, ushort, 0);
@@ -74,7 +75,7 @@ static unsigned int timeout_sec;
 static unsigned long wdt_is_open;
 static DEFINE_SPINLOCK(wdt_spinlock);
 
-static void mpc83xx_wdt_keepalive(void)
+static void mpc8xxx_wdt_keepalive(void)
 {
        /* Ping the WDT */
        spin_lock(&wdt_spinlock);
@@ -83,31 +84,31 @@ static void mpc83xx_wdt_keepalive(void)
        spin_unlock(&wdt_spinlock);
 }
 
-static void mpc83xx_wdt_timer_ping(unsigned long arg);
-static DEFINE_TIMER(wdt_timer, mpc83xx_wdt_timer_ping, 0, 0);
+static void mpc8xxx_wdt_timer_ping(unsigned long arg);
+static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, 0);
 
-static void mpc83xx_wdt_timer_ping(unsigned long arg)
+static void mpc8xxx_wdt_timer_ping(unsigned long arg)
 {
-       mpc83xx_wdt_keepalive();
+       mpc8xxx_wdt_keepalive();
        /* We're pinging it twice faster than needed, just to be sure. */
        mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
 }
 
-static void mpc83xx_wdt_pr_warn(const char *msg)
+static void mpc8xxx_wdt_pr_warn(const char *msg)
 {
-       pr_crit("mpc83xx_wdt: %s, expect the %s soon!\n", msg,
+       pr_crit("mpc8xxx_wdt: %s, expect the %s soon!\n", msg,
                reset ? "reset" : "machine check exception");
 }
 
-static ssize_t mpc83xx_wdt_write(struct file *file, const char __user *buf,
+static ssize_t mpc8xxx_wdt_write(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        if (count)
-               mpc83xx_wdt_keepalive();
+               mpc8xxx_wdt_keepalive();
        return count;
 }
 
-static int mpc83xx_wdt_open(struct inode *inode, struct file *file)
+static int mpc8xxx_wdt_open(struct inode *inode, struct file *file)
 {
        u32 tmp = SWCRR_SWEN;
        if (test_and_set_bit(0, &wdt_is_open))
@@ -132,17 +133,17 @@ static int mpc83xx_wdt_open(struct inode *inode, struct file *file)
        return nonseekable_open(inode, file);
 }
 
-static int mpc83xx_wdt_release(struct inode *inode, struct file *file)
+static int mpc8xxx_wdt_release(struct inode *inode, struct file *file)
 {
        if (!nowayout)
-               mpc83xx_wdt_timer_ping(0);
+               mpc8xxx_wdt_timer_ping(0);
        else
-               mpc83xx_wdt_pr_warn("watchdog closed");
+               mpc8xxx_wdt_pr_warn("watchdog closed");
        clear_bit(0, &wdt_is_open);
        return 0;
 }
 
-static long mpc83xx_wdt_ioctl(struct file *file, unsigned int cmd,
+static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd,
                                                        unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
@@ -150,7 +151,7 @@ static long mpc83xx_wdt_ioctl(struct file *file, unsigned int cmd,
        static struct watchdog_info ident = {
                .options = WDIOF_KEEPALIVEPING,
                .firmware_version = 1,
-               .identity = "MPC83xx",
+               .identity = "MPC8xxx",
        };
 
        switch (cmd) {
@@ -160,7 +161,7 @@ static long mpc83xx_wdt_ioctl(struct file *file, unsigned int cmd,
        case WDIOC_GETBOOTSTATUS:
                return put_user(0, p);
        case WDIOC_KEEPALIVE:
-               mpc83xx_wdt_keepalive();
+               mpc8xxx_wdt_keepalive();
                return 0;
        case WDIOC_GETTIMEOUT:
                return put_user(timeout_sec, p);
@@ -169,27 +170,27 @@ static long mpc83xx_wdt_ioctl(struct file *file, unsigned int cmd,
        }
 }
 
-static const struct file_operations mpc83xx_wdt_fops = {
+static const struct file_operations mpc8xxx_wdt_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
-       .write          = mpc83xx_wdt_write,
-       .unlocked_ioctl = mpc83xx_wdt_ioctl,
-       .open           = mpc83xx_wdt_open,
-       .release        = mpc83xx_wdt_release,
+       .write          = mpc8xxx_wdt_write,
+       .unlocked_ioctl = mpc8xxx_wdt_ioctl,
+       .open           = mpc8xxx_wdt_open,
+       .release        = mpc8xxx_wdt_release,
 };
 
-static struct miscdevice mpc83xx_wdt_miscdev = {
+static struct miscdevice mpc8xxx_wdt_miscdev = {
        .minor  = WATCHDOG_MINOR,
        .name   = "watchdog",
-       .fops   = &mpc83xx_wdt_fops,
+       .fops   = &mpc8xxx_wdt_fops,
 };
 
-static int __devinit mpc83xx_wdt_probe(struct of_device *ofdev,
+static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev,
                                       const struct of_device_id *match)
 {
        int ret;
        struct device_node *np = ofdev->node;
-       struct mpc83xx_wdt_type *wdt_type = match->data;
+       struct mpc8xxx_wdt_type *wdt_type = match->data;
        u32 freq = fsl_get_sys_freq();
        bool enabled;
 
@@ -202,93 +203,123 @@ static int __devinit mpc83xx_wdt_probe(struct of_device *ofdev,
 
        enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN;
        if (!enabled && wdt_type->hw_enabled) {
-               pr_info("mpc83xx_wdt: could not be enabled in software\n");
+               pr_info("mpc8xxx_wdt: could not be enabled in software\n");
                ret = -ENOSYS;
                goto err_unmap;
        }
 
-       ret = misc_register(&mpc83xx_wdt_miscdev);
-       if (ret) {
-               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
-               goto err_unmap;
-       }
-
        /* Calculate the timeout in seconds */
        if (prescale)
                timeout_sec = (timeout * wdt_type->prescaler) / freq;
        else
                timeout_sec = timeout / freq;
 
-       pr_info("WDT driver for MPC83xx initialized. mode:%s timeout=%d "
+#ifdef MODULE
+       ret = mpc8xxx_wdt_init_late();
+       if (ret)
+               goto err_unmap;
+#endif
+
+       pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d "
                "(%d seconds)\n", reset ? "reset" : "interrupt", timeout,
                timeout_sec);
 
        /*
         * If the watchdog was previously enabled or we're running on
-        * MPC86xx, we should ping the wdt from the kernel until the
+        * MPC8xxx, we should ping the wdt from the kernel until the
         * userspace handles it.
         */
        if (enabled)
-               mpc83xx_wdt_timer_ping(0);
+               mpc8xxx_wdt_timer_ping(0);
        return 0;
 err_unmap:
        iounmap(wd_base);
+       wd_base = NULL;
        return ret;
 }
 
-static int __devexit mpc83xx_wdt_remove(struct of_device *ofdev)
+static int __devexit mpc8xxx_wdt_remove(struct of_device *ofdev)
 {
-       mpc83xx_wdt_pr_warn("watchdog removed");
+       mpc8xxx_wdt_pr_warn("watchdog removed");
        del_timer_sync(&wdt_timer);
-       misc_deregister(&mpc83xx_wdt_miscdev);
+       misc_deregister(&mpc8xxx_wdt_miscdev);
        iounmap(wd_base);
 
        return 0;
 }
 
-static const struct of_device_id mpc83xx_wdt_match[] = {
+static const struct of_device_id mpc8xxx_wdt_match[] = {
        {
                .compatible = "mpc83xx_wdt",
-               .data = &(struct mpc83xx_wdt_type) {
+               .data = &(struct mpc8xxx_wdt_type) {
                        .prescaler = 0x10000,
                },
        },
        {
                .compatible = "fsl,mpc8610-wdt",
-               .data = &(struct mpc83xx_wdt_type) {
+               .data = &(struct mpc8xxx_wdt_type) {
                        .prescaler = 0x10000,
                        .hw_enabled = true,
                },
        },
+       {
+               .compatible = "fsl,mpc823-wdt",
+               .data = &(struct mpc8xxx_wdt_type) {
+                       .prescaler = 0x800,
+               },
+       },
        {},
 };
-MODULE_DEVICE_TABLE(of, mpc83xx_wdt_match);
+MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match);
 
-static struct of_platform_driver mpc83xx_wdt_driver = {
-       .match_table    = mpc83xx_wdt_match,
-       .probe          = mpc83xx_wdt_probe,
-       .remove         = __devexit_p(mpc83xx_wdt_remove),
+static struct of_platform_driver mpc8xxx_wdt_driver = {
+       .match_table    = mpc8xxx_wdt_match,
+       .probe          = mpc8xxx_wdt_probe,
+       .remove         = __devexit_p(mpc8xxx_wdt_remove),
        .driver         = {
-               .name   = "mpc83xx_wdt",
+               .name   = "mpc8xxx_wdt",
                .owner  = THIS_MODULE,
        },
 };
 
-static int __init mpc83xx_wdt_init(void)
+/*
+ * We do wdt initialization in two steps: arch_initcall probes the wdt
+ * very early to start pinging the watchdog (misc devices are not yet
+ * available), and later module_init() just registers the misc device.
+ */
+static int mpc8xxx_wdt_init_late(void)
 {
-       return of_register_platform_driver(&mpc83xx_wdt_driver);
+       int ret;
+
+       if (!wd_base)
+               return -ENODEV;
+
+       ret = misc_register(&mpc8xxx_wdt_miscdev);
+       if (ret) {
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                       WATCHDOG_MINOR, ret);
+               return ret;
+       }
+       return 0;
 }
+#ifndef MODULE
+module_init(mpc8xxx_wdt_init_late);
+#endif
 
-static void __exit mpc83xx_wdt_exit(void)
+static int __init mpc8xxx_wdt_init(void)
 {
-       of_unregister_platform_driver(&mpc83xx_wdt_driver);
+       return of_register_platform_driver(&mpc8xxx_wdt_driver);
 }
+arch_initcall(mpc8xxx_wdt_init);
 
-subsys_initcall(mpc83xx_wdt_init);
-module_exit(mpc83xx_wdt_exit);
+static void __exit mpc8xxx_wdt_exit(void)
+{
+       of_unregister_platform_driver(&mpc8xxx_wdt_driver);
+}
+module_exit(mpc8xxx_wdt_exit);
 
 MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
-MODULE_DESCRIPTION("Driver for watchdog timer in MPC83xx/MPC86xx uProcessors");
+MODULE_DESCRIPTION("Driver for watchdog timer in MPC8xx/MPC83xx/MPC86xx "
+                  "uProcessors");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);