Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Mathieu J. Poirier and committed by
David S. Miller
c326de88 c3e94500

+150 -7
+149 -7
drivers/net/smsc911x.c
··· 71 71 module_param(debug, int, 0); 72 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 85 struct smsc911x_data { 75 86 void __iomem *ioaddr; 76 87 ··· 129 118 unsigned int clear_bits_mask; 130 119 unsigned int hashhi; 131 120 unsigned int hashlo; 121 + 122 + /* register access functions */ 123 + const struct smsc911x_ops *ops; 132 124 }; 125 + 126 + /* Easy access to information */ 127 + #define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift)) 133 128 134 129 static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) 135 130 { ··· 150 133 return 0; 151 134 } 152 135 136 + static inline u32 137 + __smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg) 138 + { 139 + if (pdata->config.flags & SMSC911X_USE_32BIT) 140 + return readl(pdata->ioaddr + __smsc_shift(pdata, reg)); 141 + 142 + if (pdata->config.flags & SMSC911X_USE_16BIT) 143 + return (readw(pdata->ioaddr + 144 + __smsc_shift(pdata, reg)) & 0xFFFF) | 145 + ((readw(pdata->ioaddr + 146 + __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16); 147 + 148 + BUG(); 149 + return 0; 150 + } 151 + 153 152 static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) 154 153 { 155 154 u32 data; 156 155 unsigned long flags; 157 156 158 157 spin_lock_irqsave(&pdata->dev_lock, flags); 159 - data = __smsc911x_reg_read(pdata, reg); 158 + data = pdata->ops->reg_read(pdata, reg); 160 159 spin_unlock_irqrestore(&pdata->dev_lock, flags); 161 160 162 161 return data; ··· 195 162 BUG(); 196 163 } 197 164 165 + static inline void 166 + __smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val) 167 + { 168 + if (pdata->config.flags & SMSC911X_USE_32BIT) { 169 + writel(val, pdata->ioaddr + __smsc_shift(pdata, reg)); 170 + return; 171 + } 172 + 173 + if (pdata->config.flags & SMSC911X_USE_16BIT) { 174 + writew(val & 0xFFFF, 175 + pdata->ioaddr + __smsc_shift(pdata, reg)); 176 + writew((val >> 16) & 0xFFFF, 177 + pdata->ioaddr + __smsc_shift(pdata, reg + 2)); 178 + return; 179 + } 180 + 181 + BUG(); 182 + } 183 + 198 184 static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, 199 185 u32 val) 200 186 { 201 187 unsigned long flags; 202 188 203 189 spin_lock_irqsave(&pdata->dev_lock, flags); 204 - __smsc911x_reg_write(pdata, reg, val); 190 + pdata->ops->reg_write(pdata, reg, val); 205 191 spin_unlock_irqrestore(&pdata->dev_lock, flags); 206 192 } 207 193 ··· 256 204 spin_unlock_irqrestore(&pdata->dev_lock, flags); 257 205 } 258 206 207 + /* Writes a packet to the TX_DATA_FIFO - shifted version */ 208 + static inline void 209 + smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, 210 + unsigned int wordcount) 211 + { 212 + unsigned long flags; 213 + 214 + spin_lock_irqsave(&pdata->dev_lock, flags); 215 + 216 + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { 217 + while (wordcount--) 218 + __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO, 219 + swab32(*buf++)); 220 + goto out; 221 + } 222 + 223 + if (pdata->config.flags & SMSC911X_USE_32BIT) { 224 + writesl(pdata->ioaddr + __smsc_shift(pdata, 225 + TX_DATA_FIFO), buf, wordcount); 226 + goto out; 227 + } 228 + 229 + if (pdata->config.flags & SMSC911X_USE_16BIT) { 230 + while (wordcount--) 231 + __smsc911x_reg_write_shift(pdata, 232 + TX_DATA_FIFO, *buf++); 233 + goto out; 234 + } 235 + 236 + BUG(); 237 + out: 238 + spin_unlock_irqrestore(&pdata->dev_lock, flags); 239 + } 240 + 259 241 /* Reads a packet out of the RX_DATA_FIFO */ 260 242 static inline void 261 243 smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, ··· 314 228 if (pdata->config.flags & SMSC911X_USE_16BIT) { 315 229 while (wordcount--) 316 230 *buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO); 231 + goto out; 232 + } 233 + 234 + BUG(); 235 + out: 236 + spin_unlock_irqrestore(&pdata->dev_lock, flags); 237 + } 238 + 239 + /* Reads a packet out of the RX_DATA_FIFO - shifted version */ 240 + static inline void 241 + smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, 242 + unsigned int wordcount) 243 + { 244 + unsigned long flags; 245 + 246 + spin_lock_irqsave(&pdata->dev_lock, flags); 247 + 248 + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { 249 + while (wordcount--) 250 + *buf++ = swab32(__smsc911x_reg_read_shift(pdata, 251 + RX_DATA_FIFO)); 252 + goto out; 253 + } 254 + 255 + if (pdata->config.flags & SMSC911X_USE_32BIT) { 256 + readsl(pdata->ioaddr + __smsc_shift(pdata, 257 + RX_DATA_FIFO), buf, wordcount); 258 + goto out; 259 + } 260 + 261 + if (pdata->config.flags & SMSC911X_USE_16BIT) { 262 + while (wordcount--) 263 + *buf++ = __smsc911x_reg_read_shift(pdata, 264 + RX_DATA_FIFO); 317 265 goto out; 318 266 } 319 267 ··· 620 500 wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); 621 501 wrsz >>= 2; 622 502 623 - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); 503 + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); 624 504 625 505 /* Wait till transmit is done */ 626 506 i = 60; ··· 664 544 rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); 665 545 rdsz >>= 2; 666 546 667 - smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); 547 + pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz); 668 548 669 549 if (pktlength != (MIN_PACKET_SIZE + 4)) { 670 550 SMSC_WARN(pdata, hw, "Unexpected packet size " ··· 1166 1046 /* Align IP on 16B boundary */ 1167 1047 skb_reserve(skb, NET_IP_ALIGN); 1168 1048 skb_put(skb, pktlength - 4); 1169 - smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, 1170 - pktwords); 1049 + pdata->ops->rx_readfifo(pdata, 1050 + (unsigned int *)skb->head, pktwords); 1171 1051 skb->protocol = eth_type_trans(skb, dev); 1172 1052 skb_checksum_none_assert(skb); 1173 1053 netif_receive_skb(skb); ··· 1471 1351 wrsz += (u32)((ulong)skb->data & 0x3); 1472 1352 wrsz >>= 2; 1473 1353 1474 - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); 1354 + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); 1475 1355 freespace -= (skb->len + 32); 1476 1356 dev_kfree_skb(skb); 1477 1357 ··· 2077 1957 return 0; 2078 1958 } 2079 1959 1960 + /* standard register acces */ 1961 + static const struct smsc911x_ops standard_smsc911x_ops = { 1962 + .reg_read = __smsc911x_reg_read, 1963 + .reg_write = __smsc911x_reg_write, 1964 + .rx_readfifo = smsc911x_rx_readfifo, 1965 + .tx_writefifo = smsc911x_tx_writefifo, 1966 + }; 1967 + 1968 + /* shifted register access */ 1969 + static const struct smsc911x_ops shifted_smsc911x_ops = { 1970 + .reg_read = __smsc911x_reg_read_shift, 1971 + .reg_write = __smsc911x_reg_write_shift, 1972 + .rx_readfifo = smsc911x_rx_readfifo_shift, 1973 + .tx_writefifo = smsc911x_tx_writefifo_shift, 1974 + }; 1975 + 2080 1976 static int __devinit smsc911x_drv_probe(struct platform_device *pdev) 2081 1977 { 2082 1978 struct net_device *dev; ··· 2161 2025 retval = -ENOMEM; 2162 2026 goto out_free_netdev_2; 2163 2027 } 2028 + 2029 + /* assume standard, non-shifted, access to HW registers */ 2030 + pdata->ops = &standard_smsc911x_ops; 2031 + /* apply the right access if shifting is needed */ 2032 + if (config->shift) 2033 + pdata->ops = &shifted_smsc911x_ops; 2164 2034 2165 2035 retval = smsc911x_init(dev); 2166 2036 if (retval < 0)
+1
include/linux/smsc911x.h
··· 29 29 unsigned int irq_polarity; 30 30 unsigned int irq_type; 31 31 unsigned int flags; 32 + unsigned int shift; 32 33 phy_interface_t phy_interface; 33 34 unsigned char mac[6]; 34 35 };