]>
Commit | Line | Data |
---|---|---|
6c840dcf GKH |
1 | From 380fefb2ddabd4cd5f14dbe090481f0544e65078 Mon Sep 17 00:00:00 2001 |
2 | From: Baruch Siach <baruch@tkos.co.il> | |
3 | Date: Mon, 17 May 2010 17:45:48 -0700 | |
4 | Subject: dm9000: fix "BUG: spinlock recursion" | |
5 | ||
6 | From: Baruch Siach <baruch@tkos.co.il> | |
7 | ||
8 | commit 380fefb2ddabd4cd5f14dbe090481f0544e65078 upstream. | |
9 | ||
10 | dm9000_set_rx_csum and dm9000_hash_table are called from atomic context (in | |
11 | dm9000_init_dm9000), and from non-atomic context (via ethtool_ops and | |
12 | net_device_ops respectively). This causes a spinlock recursion BUG. Fix this by | |
13 | renaming these functions to *_unlocked for the atomic context, and make the | |
14 | original functions locking wrappers for use in the non-atomic context. | |
15 | ||
16 | Signed-off-by: Baruch Siach <baruch@tkos.co.il> | |
17 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
18 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
19 | ||
20 | --- | |
21 | drivers/net/dm9000.c | 38 +++++++++++++++++++++++++++----------- | |
22 | 1 file changed, 27 insertions(+), 11 deletions(-) | |
23 | ||
24 | --- a/drivers/net/dm9000.c | |
25 | +++ b/drivers/net/dm9000.c | |
26 | @@ -471,17 +471,13 @@ static uint32_t dm9000_get_rx_csum(struc | |
27 | return dm->rx_csum; | |
28 | } | |
29 | ||
30 | -static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) | |
31 | +static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data) | |
32 | { | |
33 | board_info_t *dm = to_dm9000_board(dev); | |
34 | - unsigned long flags; | |
35 | ||
36 | if (dm->can_csum) { | |
37 | dm->rx_csum = data; | |
38 | - | |
39 | - spin_lock_irqsave(&dm->lock, flags); | |
40 | iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); | |
41 | - spin_unlock_irqrestore(&dm->lock, flags); | |
42 | ||
43 | return 0; | |
44 | } | |
45 | @@ -489,6 +485,19 @@ static int dm9000_set_rx_csum(struct net | |
46 | return -EOPNOTSUPP; | |
47 | } | |
48 | ||
49 | +static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) | |
50 | +{ | |
51 | + board_info_t *dm = to_dm9000_board(dev); | |
52 | + unsigned long flags; | |
53 | + int ret; | |
54 | + | |
55 | + spin_lock_irqsave(&dm->lock, flags); | |
56 | + ret = dm9000_set_rx_csum_unlocked(dev, data); | |
57 | + spin_unlock_irqrestore(&dm->lock, flags); | |
58 | + | |
59 | + return ret; | |
60 | +} | |
61 | + | |
62 | static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) | |
63 | { | |
64 | board_info_t *dm = to_dm9000_board(dev); | |
65 | @@ -667,7 +676,7 @@ static unsigned char dm9000_type_to_char | |
66 | * Set DM9000 multicast address | |
67 | */ | |
68 | static void | |
69 | -dm9000_hash_table(struct net_device *dev) | |
70 | +dm9000_hash_table_unlocked(struct net_device *dev) | |
71 | { | |
72 | board_info_t *db = netdev_priv(dev); | |
73 | struct dev_mc_list *mcptr = dev->mc_list; | |
74 | @@ -676,12 +685,9 @@ dm9000_hash_table(struct net_device *dev | |
75 | u32 hash_val; | |
76 | u16 hash_table[4]; | |
77 | u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; | |
78 | - unsigned long flags; | |
79 | ||
80 | dm9000_dbg(db, 1, "entering %s\n", __func__); | |
81 | ||
82 | - spin_lock_irqsave(&db->lock, flags); | |
83 | - | |
84 | for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) | |
85 | iow(db, oft, dev->dev_addr[i]); | |
86 | ||
87 | @@ -711,6 +717,16 @@ dm9000_hash_table(struct net_device *dev | |
88 | } | |
89 | ||
90 | iow(db, DM9000_RCR, rcr); | |
91 | +} | |
92 | + | |
93 | +static void | |
94 | +dm9000_hash_table(struct net_device *dev) | |
95 | +{ | |
96 | + board_info_t *db = netdev_priv(dev); | |
97 | + unsigned long flags; | |
98 | + | |
99 | + spin_lock_irqsave(&db->lock, flags); | |
100 | + dm9000_hash_table_unlocked(dev); | |
101 | spin_unlock_irqrestore(&db->lock, flags); | |
102 | } | |
103 | ||
104 | @@ -729,7 +745,7 @@ dm9000_init_dm9000(struct net_device *de | |
105 | db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ | |
106 | ||
107 | /* Checksum mode */ | |
108 | - dm9000_set_rx_csum(dev, db->rx_csum); | |
109 | + dm9000_set_rx_csum_unlocked(dev, db->rx_csum); | |
110 | ||
111 | /* GPIO0 on pre-activate PHY */ | |
112 | iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ | |
113 | @@ -749,7 +765,7 @@ dm9000_init_dm9000(struct net_device *de | |
114 | iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */ | |
115 | ||
116 | /* Set address filter table */ | |
117 | - dm9000_hash_table(dev); | |
118 | + dm9000_hash_table_unlocked(dev); | |
119 | ||
120 | imr = IMR_PAR | IMR_PTM | IMR_PRM; | |
121 | if (db->type != TYPE_DM9000E) |