diff options
-rw-r--r-- | drivers/net/smsc911x.c | 156 | ||||
-rw-r--r-- | include/linux/smsc911x.h | 1 |
2 files changed, 150 insertions, 7 deletions
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index b8faab7780da..c6d47d10590c 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c | |||
@@ -71,6 +71,17 @@ static int debug = 3; | |||
71 | module_param(debug, int, 0); | 71 | module_param(debug, int, 0); |
72 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); | 72 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); |
73 | 73 | ||
74 | struct smsc911x_data; | ||
75 | |||
76 | struct smsc911x_ops { | ||
77 | u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg); | ||
78 | void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val); | ||
79 | void (*rx_readfifo)(struct smsc911x_data *pdata, | ||
80 | unsigned int *buf, unsigned int wordcount); | ||
81 | void (*tx_writefifo)(struct smsc911x_data *pdata, | ||
82 | unsigned int *buf, unsigned int wordcount); | ||
83 | }; | ||
84 | |||
74 | struct smsc911x_data { | 85 | struct smsc911x_data { |
75 | void __iomem *ioaddr; | 86 | void __iomem *ioaddr; |
76 | 87 | ||
@@ -118,8 +129,14 @@ struct smsc911x_data { | |||
118 | unsigned int clear_bits_mask; | 129 | unsigned int clear_bits_mask; |
119 | unsigned int hashhi; | 130 | unsigned int hashhi; |
120 | unsigned int hashlo; | 131 | unsigned int hashlo; |
132 | |||
133 | /* register access functions */ | ||
134 | const struct smsc911x_ops *ops; | ||
121 | }; | 135 | }; |
122 | 136 | ||
137 | /* Easy access to information */ | ||
138 | #define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift)) | ||
139 | |||
123 | static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) | 140 | static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) |
124 | { | 141 | { |
125 | if (pdata->config.flags & SMSC911X_USE_32BIT) | 142 | if (pdata->config.flags & SMSC911X_USE_32BIT) |
@@ -133,13 +150,29 @@ static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) | |||
133 | return 0; | 150 | return 0; |
134 | } | 151 | } |
135 | 152 | ||
153 | static inline u32 | ||
154 | __smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg) | ||
155 | { | ||
156 | if (pdata->config.flags & SMSC911X_USE_32BIT) | ||
157 | return readl(pdata->ioaddr + __smsc_shift(pdata, reg)); | ||
158 | |||
159 | if (pdata->config.flags & SMSC911X_USE_16BIT) | ||
160 | return (readw(pdata->ioaddr + | ||
161 | __smsc_shift(pdata, reg)) & 0xFFFF) | | ||
162 | ((readw(pdata->ioaddr + | ||
163 | __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16); | ||
164 | |||
165 | BUG(); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
136 | static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) | 169 | static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) |
137 | { | 170 | { |
138 | u32 data; | 171 | u32 data; |
139 | unsigned long flags; | 172 | unsigned long flags; |
140 | 173 | ||
141 | spin_lock_irqsave(&pdata->dev_lock, flags); | 174 | spin_lock_irqsave(&pdata->dev_lock, flags); |
142 | data = __smsc911x_reg_read(pdata, reg); | 175 | data = pdata->ops->reg_read(pdata, reg); |
143 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | 176 | spin_unlock_irqrestore(&pdata->dev_lock, flags); |
144 | 177 | ||
145 | return data; | 178 | return data; |
@@ -162,13 +195,32 @@ static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, | |||
162 | BUG(); | 195 | BUG(); |
163 | } | 196 | } |
164 | 197 | ||
198 | static inline void | ||
199 | __smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val) | ||
200 | { | ||
201 | if (pdata->config.flags & SMSC911X_USE_32BIT) { | ||
202 | writel(val, pdata->ioaddr + __smsc_shift(pdata, reg)); | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | if (pdata->config.flags & SMSC911X_USE_16BIT) { | ||
207 | writew(val & 0xFFFF, | ||
208 | pdata->ioaddr + __smsc_shift(pdata, reg)); | ||
209 | writew((val >> 16) & 0xFFFF, | ||
210 | pdata->ioaddr + __smsc_shift(pdata, reg + 2)); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | BUG(); | ||
215 | } | ||
216 | |||
165 | static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, | 217 | static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, |
166 | u32 val) | 218 | u32 val) |
167 | { | 219 | { |
168 | unsigned long flags; | 220 | unsigned long flags; |
169 | 221 | ||
170 | spin_lock_irqsave(&pdata->dev_lock, flags); | 222 | spin_lock_irqsave(&pdata->dev_lock, flags); |
171 | __smsc911x_reg_write(pdata, reg, val); | 223 | pdata->ops->reg_write(pdata, reg, val); |
172 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | 224 | spin_unlock_irqrestore(&pdata->dev_lock, flags); |
173 | } | 225 | } |
174 | 226 | ||
@@ -204,6 +256,40 @@ out: | |||
204 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | 256 | spin_unlock_irqrestore(&pdata->dev_lock, flags); |
205 | } | 257 | } |
206 | 258 | ||
259 | /* Writes a packet to the TX_DATA_FIFO - shifted version */ | ||
260 | static inline void | ||
261 | smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, | ||
262 | unsigned int wordcount) | ||
263 | { | ||
264 | unsigned long flags; | ||
265 | |||
266 | spin_lock_irqsave(&pdata->dev_lock, flags); | ||
267 | |||
268 | if (pdata->config.flags & SMSC911X_SWAP_FIFO) { | ||
269 | while (wordcount--) | ||
270 | __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO, | ||
271 | swab32(*buf++)); | ||
272 | goto out; | ||
273 | } | ||
274 | |||
275 | if (pdata->config.flags & SMSC911X_USE_32BIT) { | ||
276 | writesl(pdata->ioaddr + __smsc_shift(pdata, | ||
277 | TX_DATA_FIFO), buf, wordcount); | ||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | if (pdata->config.flags & SMSC911X_USE_16BIT) { | ||
282 | while (wordcount--) | ||
283 | __smsc911x_reg_write_shift(pdata, | ||
284 | TX_DATA_FIFO, *buf++); | ||
285 | goto out; | ||
286 | } | ||
287 | |||
288 | BUG(); | ||
289 | out: | ||
290 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | ||
291 | } | ||
292 | |||
207 | /* Reads a packet out of the RX_DATA_FIFO */ | 293 | /* Reads a packet out of the RX_DATA_FIFO */ |
208 | static inline void | 294 | static inline void |
209 | smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, | 295 | smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, |
@@ -236,6 +322,40 @@ out: | |||
236 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | 322 | spin_unlock_irqrestore(&pdata->dev_lock, flags); |
237 | } | 323 | } |
238 | 324 | ||
325 | /* Reads a packet out of the RX_DATA_FIFO - shifted version */ | ||
326 | static inline void | ||
327 | smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, | ||
328 | unsigned int wordcount) | ||
329 | { | ||
330 | unsigned long flags; | ||
331 | |||
332 | spin_lock_irqsave(&pdata->dev_lock, flags); | ||
333 | |||
334 | if (pdata->config.flags & SMSC911X_SWAP_FIFO) { | ||
335 | while (wordcount--) | ||
336 | *buf++ = swab32(__smsc911x_reg_read_shift(pdata, | ||
337 | RX_DATA_FIFO)); | ||
338 | goto out; | ||
339 | } | ||
340 | |||
341 | if (pdata->config.flags & SMSC911X_USE_32BIT) { | ||
342 | readsl(pdata->ioaddr + __smsc_shift(pdata, | ||
343 | RX_DATA_FIFO), buf, wordcount); | ||
344 | goto out; | ||
345 | } | ||
346 | |||
347 | if (pdata->config.flags & SMSC911X_USE_16BIT) { | ||
348 | while (wordcount--) | ||
349 | *buf++ = __smsc911x_reg_read_shift(pdata, | ||
350 | RX_DATA_FIFO); | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | BUG(); | ||
355 | out: | ||
356 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | ||
357 | } | ||
358 | |||
239 | /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read | 359 | /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read |
240 | * and smsc911x_mac_write, so assumes mac_lock is held */ | 360 | * and smsc911x_mac_write, so assumes mac_lock is held */ |
241 | static int smsc911x_mac_complete(struct smsc911x_data *pdata) | 361 | static int smsc911x_mac_complete(struct smsc911x_data *pdata) |
@@ -500,7 +620,7 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) | |||
500 | wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); | 620 | wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); |
501 | wrsz >>= 2; | 621 | wrsz >>= 2; |
502 | 622 | ||
503 | smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); | 623 | pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); |
504 | 624 | ||
505 | /* Wait till transmit is done */ | 625 | /* Wait till transmit is done */ |
506 | i = 60; | 626 | i = 60; |
@@ -544,7 +664,7 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) | |||
544 | rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); | 664 | rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); |
545 | rdsz >>= 2; | 665 | rdsz >>= 2; |
546 | 666 | ||
547 | smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); | 667 | pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz); |
548 | 668 | ||
549 | if (pktlength != (MIN_PACKET_SIZE + 4)) { | 669 | if (pktlength != (MIN_PACKET_SIZE + 4)) { |
550 | SMSC_WARN(pdata, hw, "Unexpected packet size " | 670 | SMSC_WARN(pdata, hw, "Unexpected packet size " |
@@ -1046,8 +1166,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) | |||
1046 | /* Align IP on 16B boundary */ | 1166 | /* Align IP on 16B boundary */ |
1047 | skb_reserve(skb, NET_IP_ALIGN); | 1167 | skb_reserve(skb, NET_IP_ALIGN); |
1048 | skb_put(skb, pktlength - 4); | 1168 | skb_put(skb, pktlength - 4); |
1049 | smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, | 1169 | pdata->ops->rx_readfifo(pdata, |
1050 | pktwords); | 1170 | (unsigned int *)skb->head, pktwords); |
1051 | skb->protocol = eth_type_trans(skb, dev); | 1171 | skb->protocol = eth_type_trans(skb, dev); |
1052 | skb_checksum_none_assert(skb); | 1172 | skb_checksum_none_assert(skb); |
1053 | netif_receive_skb(skb); | 1173 | netif_receive_skb(skb); |
@@ -1351,7 +1471,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1351 | wrsz += (u32)((ulong)skb->data & 0x3); | 1471 | wrsz += (u32)((ulong)skb->data & 0x3); |
1352 | wrsz >>= 2; | 1472 | wrsz >>= 2; |
1353 | 1473 | ||
1354 | smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); | 1474 | pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); |
1355 | freespace -= (skb->len + 32); | 1475 | freespace -= (skb->len + 32); |
1356 | dev_kfree_skb(skb); | 1476 | dev_kfree_skb(skb); |
1357 | 1477 | ||
@@ -1957,6 +2077,22 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) | |||
1957 | return 0; | 2077 | return 0; |
1958 | } | 2078 | } |
1959 | 2079 | ||
2080 | /* standard register acces */ | ||
2081 | static const struct smsc911x_ops standard_smsc911x_ops = { | ||
2082 | .reg_read = __smsc911x_reg_read, | ||
2083 | .reg_write = __smsc911x_reg_write, | ||
2084 | .rx_readfifo = smsc911x_rx_readfifo, | ||
2085 | .tx_writefifo = smsc911x_tx_writefifo, | ||
2086 | }; | ||
2087 | |||
2088 | /* shifted register access */ | ||
2089 | static const struct smsc911x_ops shifted_smsc911x_ops = { | ||
2090 | .reg_read = __smsc911x_reg_read_shift, | ||
2091 | .reg_write = __smsc911x_reg_write_shift, | ||
2092 | .rx_readfifo = smsc911x_rx_readfifo_shift, | ||
2093 | .tx_writefifo = smsc911x_tx_writefifo_shift, | ||
2094 | }; | ||
2095 | |||
1960 | static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | 2096 | static int __devinit smsc911x_drv_probe(struct platform_device *pdev) |
1961 | { | 2097 | { |
1962 | struct net_device *dev; | 2098 | struct net_device *dev; |
@@ -2026,6 +2162,12 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
2026 | goto out_free_netdev_2; | 2162 | goto out_free_netdev_2; |
2027 | } | 2163 | } |
2028 | 2164 | ||
2165 | /* assume standard, non-shifted, access to HW registers */ | ||
2166 | pdata->ops = &standard_smsc911x_ops; | ||
2167 | /* apply the right access if shifting is needed */ | ||
2168 | if (config->shift) | ||
2169 | pdata->ops = &shifted_smsc911x_ops; | ||
2170 | |||
2029 | retval = smsc911x_init(dev); | 2171 | retval = smsc911x_init(dev); |
2030 | if (retval < 0) | 2172 | if (retval < 0) |
2031 | goto out_unmap_io_3; | 2173 | goto out_unmap_io_3; |
diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h index 7144e8aa1e41..4dde70e74822 100644 --- a/include/linux/smsc911x.h +++ b/include/linux/smsc911x.h | |||
@@ -29,6 +29,7 @@ struct smsc911x_platform_config { | |||
29 | unsigned int irq_polarity; | 29 | unsigned int irq_polarity; |
30 | unsigned int irq_type; | 30 | unsigned int irq_type; |
31 | unsigned int flags; | 31 | unsigned int flags; |
32 | unsigned int shift; | ||
32 | phy_interface_t phy_interface; | 33 | phy_interface_t phy_interface; |
33 | unsigned char mac[6]; | 34 | unsigned char mac[6]; |
34 | }; | 35 | }; |