diff options
| author | Mathieu J. Poirier <mathieu.poirier@linaro.org> | 2011-04-13 20:13:00 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-04-13 20:13:00 -0400 |
| commit | c326de88b8ac7ed1cd1027017ba6079dbe91be49 (patch) | |
| tree | 9458898250dc12048b46b7a54581211422a8c39e | |
| parent | c3e945006ab2295e9a3f4327aa74a502ad123fe6 (diff) | |
net: allow shifted access in smsc911x V2
This is a revised patch that permits a shifted access to the
LAN9221 registers. More specifically:
It adds a shift parameter in the platform_data.
It introduces an ops in smsc911x_data.
A choice of access function to use at run-time.
Four new shifted access function.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -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 b8faab7780d..c6d47d10590 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 7144e8aa1e4..4dde70e7482 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 | }; |
