aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/smsc911x.c156
-rw-r--r--include/linux/smsc911x.h1
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;
71module_param(debug, int, 0); 71module_param(debug, int, 0);
72MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); 72MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
73 73
74struct smsc911x_data;
75
76struct 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
74struct smsc911x_data { 85struct 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
123static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) 140static 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
153static 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
136static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) 169static 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
198static 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
165static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, 217static 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 */
260static inline void
261smsc911x_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();
289out:
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 */
208static inline void 294static inline void
209smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, 295smsc911x_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 */
326static inline void
327smsc911x_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();
355out:
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 */
241static int smsc911x_mac_complete(struct smsc911x_data *pdata) 361static 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 */
2081static 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 */
2089static 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
1960static int __devinit smsc911x_drv_probe(struct platform_device *pdev) 2096static 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};