summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-03-22 21:28:39 -0700
committerDavid S. Miller <davem@davemloft.net>2009-03-22 21:28:39 -0700
commite3162d381fc359ebe5c98a3e216888a7cb200051 (patch)
treed3affce735bf848e98150541fe2c487319a29bd0
parent6580f57d485f70851218813fa053d971915f61fb (diff)
downloadlinux-3.10-e3162d381fc359ebe5c98a3e216888a7cb200051.tar.gz
linux-3.10-e3162d381fc359ebe5c98a3e216888a7cb200051.tar.bz2
linux-3.10-e3162d381fc359ebe5c98a3e216888a7cb200051.zip
dm9000: locking bugfix
This fixes a locking bug in the dm9000 driver. It calls request_irq() without setting IRQF_DISABLED ... which is correct for handlers that support IRQ sharing, since that behavior is not guaranteed for shared IRQs. However, its IRQ handler then wrongly assumes that IRQs are blocked. So the fix just uses the right spinlock primitives in the IRQ handler. NOTE: this is a classic example of the type of bug which lockdep currently masks by forcibly setting IRQF_DISABLED on IRQ handlers that did not request that flag. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dm9000.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index bcf92917bbf..254ec62b5f5 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -930,13 +930,15 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
struct net_device *dev = dev_id;
board_info_t *db = netdev_priv(dev);
int int_status;
+ unsigned long flags;
u8 reg_save;
dm9000_dbg(db, 3, "entering %s\n", __func__);
/* A real interrupt coming */
- spin_lock(&db->lock);
+ /* holders of db->lock must always block IRQs */
+ spin_lock_irqsave(&db->lock, flags);
/* Save previous register address */
reg_save = readb(db->io_addr);
@@ -972,7 +974,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
/* Restore previous register address */
writeb(reg_save, db->io_addr);
- spin_unlock(&db->lock);
+ spin_unlock_irqrestore(&db->lock, flags);
return IRQ_HANDLED;
}