Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=01c785dcb4e9fd6c4c370fd9915fc10585ed64bd
Commit:     01c785dcb4e9fd6c4c370fd9915fc10585ed64bd
Parent:     b47711bfbcd4eb77ca61ef0162487b20e023ae55
Author:     Alan Cox <[EMAIL PROTECTED]>
AuthorDate: Wed Jan 9 21:36:01 2008 -0800
Committer:  Wim Van Sebroeck <[EMAIL PROTECTED]>
CommitDate: Fri Jan 25 20:23:28 2008 +0000

    [WATCHDOG] wdt: fix locking
    
    The audit of _p usage shows various drivers assume inb_p is somehow atomic.
     Of course it isn't and the delay can be split from the I/O cycle causing a
    timing violation on chips that matter (eg this one)
    
    With the proposed use of udelay() for some _p delays this will cease to be
    a mostly theoretical bug (as the delay stall is unsplittable) and wants
    fixing.
    
    Lots of other drivers need fixing this way too.
    
    Signed-off-by: Alan Cox <[EMAIL PROTECTED]>
    Signed-off-by: Wim Van Sebroeck <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
---
 drivers/watchdog/wdt.c |   30 +++++++++++++++++++++++++++---
 1 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 53d0bb4..756fb15 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once 
started (default=" _
 static int io=0x240;
 static int irq=11;
 
+static DEFINE_SPINLOCK(wdt_lock);
+
 module_param(io, int, 0);
 MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
 module_param(irq, int, 0);
@@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val)
 
 static int wdt_start(void)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&wdt_lock, flags);
        inb_p(WDT_DC);                  /* Disable watchdog */
        wdt_ctr_mode(0,3);              /* Program CTR0 for Mode 3: Square Wave 
Generator */
        wdt_ctr_mode(1,2);              /* Program CTR1 for Mode 2: Rate 
Generator */
@@ -117,6 +121,7 @@ static int wdt_start(void)
        wdt_ctr_load(1,wd_heartbeat);   /* Heartbeat */
        wdt_ctr_load(2,65535);          /* Length of reset pulse */
        outb_p(0, WDT_DC);              /* Enable watchdog */
+       spin_unlock_irqrestore(&wdt_lock, flags);
        return 0;
 }
 
@@ -128,9 +133,12 @@ static int wdt_start(void)
 
 static int wdt_stop (void)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&wdt_lock, flags);
        /* Turn the card off */
        inb_p(WDT_DC);                  /* Disable watchdog */
        wdt_ctr_load(2,0);              /* 0 length reset pulses now */
+       spin_unlock_irqrestore(&wdt_lock, flags);
        return 0;
 }
 
@@ -143,11 +151,14 @@ static int wdt_stop (void)
 
 static int wdt_ping(void)
 {
+       unsigned long flags;
+       spin_lock_irqsave(&wdt_lock, flags);
        /* Write a watchdog value */
        inb_p(WDT_DC);                  /* Disable watchdog */
        wdt_ctr_mode(1,2);              /* Re-Program CTR1 for Mode 2: Rate 
Generator */
        wdt_ctr_load(1,wd_heartbeat);   /* Heartbeat */
        outb_p(0, WDT_DC);              /* Enable watchdog */
+       spin_unlock_irqrestore(&wdt_lock, flags);
        return 0;
 }
 
@@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t)
 
 static int wdt_get_status(int *status)
 {
-       unsigned char new_status=inb_p(WDT_SR);
+       unsigned char new_status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdt_lock, flags);
+       new_status = inb_p(WDT_SR);
+       spin_unlock_irqrestore(&wdt_lock, flags);
 
        *status=0;
        if (new_status & WDC_SR_ISOI0)
@@ -214,8 +230,12 @@ static int wdt_get_status(int *status)
 
 static int wdt_get_temperature(int *temperature)
 {
-       unsigned short c=inb_p(WDT_RT);
+       unsigned short c;
+       unsigned long flags;
 
+       spin_lock_irqsave(&wdt_lock, flags);
+       c = inb_p(WDT_RT);
+       spin_unlock_irqrestore(&wdt_lock, flags);
        *temperature = (c * 11 / 15) + 7;
        return 0;
 }
@@ -237,7 +257,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
         *      Read the status register see what is up and
         *      then printk it.
         */
-       unsigned char status=inb_p(WDT_SR);
+       unsigned char status;
+
+       spin_lock(&wdt_lock);
+       status = inb_p(WDT_SR);
 
        printk(KERN_CRIT "WDT status %d\n", status);
 
@@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
                printk(KERN_CRIT "Reset in 5ms.\n");
 #endif
        }
+       spin_unlock(&wdt_lock);
        return IRQ_HANDLED;
 }
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to