aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/smsc911x.c
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2010-07-19 16:36:21 -0400
committerDavid S. Miller <davem@davemloft.net>2010-07-19 16:36:21 -0400
commit492c5d943d6a04b124ba3a719dc746dc36b14cfb (patch)
treeffaf0cac0c39af113bba21b9cb459accd64c5de8 /drivers/net/smsc911x.c
parent90e1795b9b18ce47e95cd26028a9cfd0f4cc35ba (diff)
smsc911x: Add spinlocks around registers access
On SMP systems, the SMSC911x registers may be accessed by multiple CPUs and this seems to put the chip in an inconsistent state. The patch adds spinlocks to the smsc911x_reg_read, smsc911x_reg_write, smsc911x_rx_readfifo and smsc911x_tx_writefifo functions. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/smsc911x.c')
-rw-r--r--drivers/net/smsc911x.c92
1 files changed, 52 insertions, 40 deletions
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 56dc2ff75ee3..0909ae934ad0 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -84,8 +84,7 @@ struct smsc911x_data {
84 */ 84 */
85 spinlock_t mac_lock; 85 spinlock_t mac_lock;
86 86
87 /* spinlock to ensure 16-bit accesses are serialised. 87 /* spinlock to ensure register accesses are serialised */
88 * unused with a 32-bit bus */
89 spinlock_t dev_lock; 88 spinlock_t dev_lock;
90 89
91 struct phy_device *phy_dev; 90 struct phy_device *phy_dev;
@@ -118,37 +117,33 @@ struct smsc911x_data {
118 unsigned int hashlo; 117 unsigned int hashlo;
119}; 118};
120 119
121/* The 16-bit access functions are significantly slower, due to the locking 120static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
122 * necessary. If your bus hardware can be configured to do this for you
123 * (in response to a single 32-bit operation from software), you should use
124 * the 32-bit access functions instead. */
125
126static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
127{ 121{
128 if (pdata->config.flags & SMSC911X_USE_32BIT) 122 if (pdata->config.flags & SMSC911X_USE_32BIT)
129 return readl(pdata->ioaddr + reg); 123 return readl(pdata->ioaddr + reg);
130 124
131 if (pdata->config.flags & SMSC911X_USE_16BIT) { 125 if (pdata->config.flags & SMSC911X_USE_16BIT)
132 u32 data; 126 return ((readw(pdata->ioaddr + reg) & 0xFFFF) |
133 unsigned long flags;
134
135 /* these two 16-bit reads must be performed consecutively, so
136 * must not be interrupted by our own ISR (which would start
137 * another read operation) */
138 spin_lock_irqsave(&pdata->dev_lock, flags);
139 data = ((readw(pdata->ioaddr + reg) & 0xFFFF) |
140 ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); 127 ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
141 spin_unlock_irqrestore(&pdata->dev_lock, flags);
142
143 return data;
144 }
145 128
146 BUG(); 129 BUG();
147 return 0; 130 return 0;
148} 131}
149 132
150static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, 133static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
151 u32 val) 134{
135 u32 data;
136 unsigned long flags;
137
138 spin_lock_irqsave(&pdata->dev_lock, flags);
139 data = __smsc911x_reg_read(pdata, reg);
140 spin_unlock_irqrestore(&pdata->dev_lock, flags);
141
142 return data;
143}
144
145static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
146 u32 val)
152{ 147{
153 if (pdata->config.flags & SMSC911X_USE_32BIT) { 148 if (pdata->config.flags & SMSC911X_USE_32BIT) {
154 writel(val, pdata->ioaddr + reg); 149 writel(val, pdata->ioaddr + reg);
@@ -156,44 +151,54 @@ static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
156 } 151 }
157 152
158 if (pdata->config.flags & SMSC911X_USE_16BIT) { 153 if (pdata->config.flags & SMSC911X_USE_16BIT) {
159 unsigned long flags;
160
161 /* these two 16-bit writes must be performed consecutively, so
162 * must not be interrupted by our own ISR (which would start
163 * another read operation) */
164 spin_lock_irqsave(&pdata->dev_lock, flags);
165 writew(val & 0xFFFF, pdata->ioaddr + reg); 154 writew(val & 0xFFFF, pdata->ioaddr + reg);
166 writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); 155 writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2);
167 spin_unlock_irqrestore(&pdata->dev_lock, flags);
168 return; 156 return;
169 } 157 }
170 158
171 BUG(); 159 BUG();
172} 160}
173 161
162static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
163 u32 val)
164{
165 unsigned long flags;
166
167 spin_lock_irqsave(&pdata->dev_lock, flags);
168 __smsc911x_reg_write(pdata, reg, val);
169 spin_unlock_irqrestore(&pdata->dev_lock, flags);
170}
171
174/* Writes a packet to the TX_DATA_FIFO */ 172/* Writes a packet to the TX_DATA_FIFO */
175static inline void 173static inline void
176smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, 174smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
177 unsigned int wordcount) 175 unsigned int wordcount)
178{ 176{
177 unsigned long flags;
178
179 spin_lock_irqsave(&pdata->dev_lock, flags);
180
179 if (pdata->config.flags & SMSC911X_SWAP_FIFO) { 181 if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
180 while (wordcount--) 182 while (wordcount--)
181 smsc911x_reg_write(pdata, TX_DATA_FIFO, swab32(*buf++)); 183 __smsc911x_reg_write(pdata, TX_DATA_FIFO,
182 return; 184 swab32(*buf++));
185 goto out;
183 } 186 }
184 187
185 if (pdata->config.flags & SMSC911X_USE_32BIT) { 188 if (pdata->config.flags & SMSC911X_USE_32BIT) {
186 writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); 189 writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
187 return; 190 goto out;
188 } 191 }
189 192
190 if (pdata->config.flags & SMSC911X_USE_16BIT) { 193 if (pdata->config.flags & SMSC911X_USE_16BIT) {
191 while (wordcount--) 194 while (wordcount--)
192 smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++); 195 __smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
193 return; 196 goto out;
194 } 197 }
195 198
196 BUG(); 199 BUG();
200out:
201 spin_unlock_irqrestore(&pdata->dev_lock, flags);
197} 202}
198 203
199/* Reads a packet out of the RX_DATA_FIFO */ 204/* Reads a packet out of the RX_DATA_FIFO */
@@ -201,24 +206,31 @@ static inline void
201smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, 206smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
202 unsigned int wordcount) 207 unsigned int wordcount)
203{ 208{
209 unsigned long flags;
210
211 spin_lock_irqsave(&pdata->dev_lock, flags);
212
204 if (pdata->config.flags & SMSC911X_SWAP_FIFO) { 213 if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
205 while (wordcount--) 214 while (wordcount--)
206 *buf++ = swab32(smsc911x_reg_read(pdata, RX_DATA_FIFO)); 215 *buf++ = swab32(__smsc911x_reg_read(pdata,
207 return; 216 RX_DATA_FIFO));
217 goto out;
208 } 218 }
209 219
210 if (pdata->config.flags & SMSC911X_USE_32BIT) { 220 if (pdata->config.flags & SMSC911X_USE_32BIT) {
211 readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); 221 readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
212 return; 222 goto out;
213 } 223 }
214 224
215 if (pdata->config.flags & SMSC911X_USE_16BIT) { 225 if (pdata->config.flags & SMSC911X_USE_16BIT) {
216 while (wordcount--) 226 while (wordcount--)
217 *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO); 227 *buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO);
218 return; 228 goto out;
219 } 229 }
220 230
221 BUG(); 231 BUG();
232out:
233 spin_unlock_irqrestore(&pdata->dev_lock, flags);
222} 234}
223 235
224/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read 236/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read