aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-03-23 00:28:39 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-23 00:28:39 -0400
commite3162d381fc359ebe5c98a3e216888a7cb200051 (patch)
treed3affce735bf848e98150541fe2c487319a29bd0
parent6580f57d485f70851218813fa053d971915f61fb (diff)
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 bcf92917bbf3..254ec62b5f58 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)
930 struct net_device *dev = dev_id; 930 struct net_device *dev = dev_id;
931 board_info_t *db = netdev_priv(dev); 931 board_info_t *db = netdev_priv(dev);
932 int int_status; 932 int int_status;
933 unsigned long flags;
933 u8 reg_save; 934 u8 reg_save;
934 935
935 dm9000_dbg(db, 3, "entering %s\n", __func__); 936 dm9000_dbg(db, 3, "entering %s\n", __func__);
936 937
937 /* A real interrupt coming */ 938 /* A real interrupt coming */
938 939
939 spin_lock(&db->lock); 940 /* holders of db->lock must always block IRQs */
941 spin_lock_irqsave(&db->lock, flags);
940 942
941 /* Save previous register address */ 943 /* Save previous register address */
942 reg_save = readb(db->io_addr); 944 reg_save = readb(db->io_addr);
@@ -972,7 +974,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
972 /* Restore previous register address */ 974 /* Restore previous register address */
973 writeb(reg_save, db->io_addr); 975 writeb(reg_save, db->io_addr);
974 976
975 spin_unlock(&db->lock); 977 spin_unlock_irqrestore(&db->lock, flags);
976 978
977 return IRQ_HANDLED; 979 return IRQ_HANDLED;
978} 980}