diff options
Diffstat (limited to 'drivers/net/usb/sr9800.c')
-rw-r--r-- | drivers/net/usb/sr9800.c | 874 |
1 files changed, 874 insertions, 0 deletions
diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c new file mode 100644 index 000000000000..b94a0fbb8b3b --- /dev/null +++ b/drivers/net/usb/sr9800.c | |||
@@ -0,0 +1,874 @@ | |||
1 | /* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices | ||
2 | * | ||
3 | * Author : Liu Junliang <liujunliang_ljl@163.com> | ||
4 | * | ||
5 | * Based on asix_common.c, asix_devices.c | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public License | ||
8 | * version 2. This program is licensed "as is" without any warranty of any | ||
9 | * kind, whether express or implied.* | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kmod.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/etherdevice.h> | ||
17 | #include <linux/ethtool.h> | ||
18 | #include <linux/workqueue.h> | ||
19 | #include <linux/mii.h> | ||
20 | #include <linux/usb.h> | ||
21 | #include <linux/crc32.h> | ||
22 | #include <linux/usb/usbnet.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/if_vlan.h> | ||
25 | |||
26 | #include "sr9800.h" | ||
27 | |||
28 | static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
29 | u16 size, void *data) | ||
30 | { | ||
31 | int err; | ||
32 | |||
33 | err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index, | ||
34 | data, size); | ||
35 | if ((err != size) && (err >= 0)) | ||
36 | err = -EINVAL; | ||
37 | |||
38 | return err; | ||
39 | } | ||
40 | |||
41 | static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
42 | u16 size, void *data) | ||
43 | { | ||
44 | int err; | ||
45 | |||
46 | err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index, | ||
47 | data, size); | ||
48 | if ((err != size) && (err >= 0)) | ||
49 | err = -EINVAL; | ||
50 | |||
51 | return err; | ||
52 | } | ||
53 | |||
54 | static void | ||
55 | sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
56 | u16 size, void *data) | ||
57 | { | ||
58 | usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data, | ||
59 | size); | ||
60 | } | ||
61 | |||
62 | static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
63 | { | ||
64 | int offset = 0; | ||
65 | |||
66 | /* This check is no longer done by usbnet */ | ||
67 | if (skb->len < dev->net->hard_header_len) | ||
68 | return 0; | ||
69 | |||
70 | while (offset + sizeof(u32) < skb->len) { | ||
71 | struct sk_buff *sr_skb; | ||
72 | u16 size; | ||
73 | u32 header = get_unaligned_le32(skb->data + offset); | ||
74 | |||
75 | offset += sizeof(u32); | ||
76 | /* get the packet length */ | ||
77 | size = (u16) (header & 0x7ff); | ||
78 | if (size != ((~header >> 16) & 0x07ff)) { | ||
79 | netdev_err(dev->net, "%s : Bad Header Length\n", | ||
80 | __func__); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || | ||
85 | (size + offset > skb->len)) { | ||
86 | netdev_err(dev->net, "%s : Bad RX Length %d\n", | ||
87 | __func__, size); | ||
88 | return 0; | ||
89 | } | ||
90 | sr_skb = netdev_alloc_skb_ip_align(dev->net, size); | ||
91 | if (!sr_skb) | ||
92 | return 0; | ||
93 | |||
94 | skb_put(sr_skb, size); | ||
95 | memcpy(sr_skb->data, skb->data + offset, size); | ||
96 | usbnet_skb_return(dev, sr_skb); | ||
97 | |||
98 | offset += (size + 1) & 0xfffe; | ||
99 | } | ||
100 | |||
101 | if (skb->len != offset) { | ||
102 | netdev_err(dev->net, "%s : Bad SKB Length %d\n", __func__, | ||
103 | skb->len); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
111 | gfp_t flags) | ||
112 | { | ||
113 | int headroom = skb_headroom(skb); | ||
114 | int tailroom = skb_tailroom(skb); | ||
115 | u32 padbytes = 0xffff0000; | ||
116 | u32 packet_len; | ||
117 | int padlen; | ||
118 | |||
119 | padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4; | ||
120 | |||
121 | if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) { | ||
122 | if ((headroom < 4) || (tailroom < padlen)) { | ||
123 | skb->data = memmove(skb->head + 4, skb->data, | ||
124 | skb->len); | ||
125 | skb_set_tail_pointer(skb, skb->len); | ||
126 | } | ||
127 | } else { | ||
128 | struct sk_buff *skb2; | ||
129 | skb2 = skb_copy_expand(skb, 4, padlen, flags); | ||
130 | dev_kfree_skb_any(skb); | ||
131 | skb = skb2; | ||
132 | if (!skb) | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | skb_push(skb, 4); | ||
137 | packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); | ||
138 | cpu_to_le32s(&packet_len); | ||
139 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | ||
140 | |||
141 | if (padlen) { | ||
142 | cpu_to_le32s(&padbytes); | ||
143 | memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | ||
144 | skb_put(skb, sizeof(padbytes)); | ||
145 | } | ||
146 | |||
147 | return skb; | ||
148 | } | ||
149 | |||
150 | static void sr_status(struct usbnet *dev, struct urb *urb) | ||
151 | { | ||
152 | struct sr9800_int_data *event; | ||
153 | int link; | ||
154 | |||
155 | if (urb->actual_length < 8) | ||
156 | return; | ||
157 | |||
158 | event = urb->transfer_buffer; | ||
159 | link = event->link & 0x01; | ||
160 | if (netif_carrier_ok(dev->net) != link) { | ||
161 | usbnet_link_change(dev, link, 1); | ||
162 | netdev_dbg(dev->net, "Link Status is: %d\n", link); | ||
163 | } | ||
164 | |||
165 | return; | ||
166 | } | ||
167 | |||
168 | static inline int sr_set_sw_mii(struct usbnet *dev) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | ||
173 | if (ret < 0) | ||
174 | netdev_err(dev->net, "Failed to enable software MII access\n"); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | static inline int sr_set_hw_mii(struct usbnet *dev) | ||
179 | { | ||
180 | int ret; | ||
181 | |||
182 | ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | ||
183 | if (ret < 0) | ||
184 | netdev_err(dev->net, "Failed to enable hardware MII access\n"); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static inline int sr_get_phy_addr(struct usbnet *dev) | ||
189 | { | ||
190 | u8 buf[2]; | ||
191 | int ret; | ||
192 | |||
193 | ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf); | ||
194 | if (ret < 0) { | ||
195 | netdev_err(dev->net, "%s : Error reading PHYID register:%02x\n", | ||
196 | __func__, ret); | ||
197 | goto out; | ||
198 | } | ||
199 | netdev_dbg(dev->net, "%s : returning 0x%04x\n", __func__, | ||
200 | *((__le16 *)buf)); | ||
201 | |||
202 | ret = buf[1]; | ||
203 | |||
204 | out: | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | static int sr_sw_reset(struct usbnet *dev, u8 flags) | ||
209 | { | ||
210 | int ret; | ||
211 | |||
212 | ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL); | ||
213 | if (ret < 0) | ||
214 | netdev_err(dev->net, "Failed to send software reset:%02x\n", | ||
215 | ret); | ||
216 | |||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static u16 sr_read_rx_ctl(struct usbnet *dev) | ||
221 | { | ||
222 | __le16 v; | ||
223 | int ret; | ||
224 | |||
225 | ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v); | ||
226 | if (ret < 0) { | ||
227 | netdev_err(dev->net, "Error reading RX_CTL register:%02x\n", | ||
228 | ret); | ||
229 | goto out; | ||
230 | } | ||
231 | |||
232 | ret = le16_to_cpu(v); | ||
233 | out: | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | static int sr_write_rx_ctl(struct usbnet *dev, u16 mode) | ||
238 | { | ||
239 | int ret; | ||
240 | |||
241 | netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); | ||
242 | ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | ||
243 | if (ret < 0) | ||
244 | netdev_err(dev->net, | ||
245 | "Failed to write RX_CTL mode to 0x%04x:%02x\n", | ||
246 | mode, ret); | ||
247 | |||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | static u16 sr_read_medium_status(struct usbnet *dev) | ||
252 | { | ||
253 | __le16 v; | ||
254 | int ret; | ||
255 | |||
256 | ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | ||
257 | if (ret < 0) { | ||
258 | netdev_err(dev->net, | ||
259 | "Error reading Medium Status register:%02x\n", ret); | ||
260 | return ret; /* TODO: callers not checking for error ret */ | ||
261 | } | ||
262 | |||
263 | return le16_to_cpu(v); | ||
264 | } | ||
265 | |||
266 | static int sr_write_medium_mode(struct usbnet *dev, u16 mode) | ||
267 | { | ||
268 | int ret; | ||
269 | |||
270 | netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); | ||
271 | ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
272 | if (ret < 0) | ||
273 | netdev_err(dev->net, | ||
274 | "Failed to write Medium Mode mode to 0x%04x:%02x\n", | ||
275 | mode, ret); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep) | ||
280 | { | ||
281 | int ret; | ||
282 | |||
283 | netdev_dbg(dev->net, "%s : value = 0x%04x\n", __func__, value); | ||
284 | ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL); | ||
285 | if (ret < 0) | ||
286 | netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n", | ||
287 | value, ret); | ||
288 | if (sleep) | ||
289 | msleep(sleep); | ||
290 | |||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | /* SR9800 have a 16-bit RX_CTL value */ | ||
295 | static void sr_set_multicast(struct net_device *net) | ||
296 | { | ||
297 | struct usbnet *dev = netdev_priv(net); | ||
298 | struct sr_data *data = (struct sr_data *)&dev->data; | ||
299 | u16 rx_ctl = SR_DEFAULT_RX_CTL; | ||
300 | |||
301 | if (net->flags & IFF_PROMISC) { | ||
302 | rx_ctl |= SR_RX_CTL_PRO; | ||
303 | } else if (net->flags & IFF_ALLMULTI || | ||
304 | netdev_mc_count(net) > SR_MAX_MCAST) { | ||
305 | rx_ctl |= SR_RX_CTL_AMALL; | ||
306 | } else if (netdev_mc_empty(net)) { | ||
307 | /* just broadcast and directed */ | ||
308 | } else { | ||
309 | /* We use the 20 byte dev->data | ||
310 | * for our 8 byte filter buffer | ||
311 | * to avoid allocating memory that | ||
312 | * is tricky to free later | ||
313 | */ | ||
314 | struct netdev_hw_addr *ha; | ||
315 | u32 crc_bits; | ||
316 | |||
317 | memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE); | ||
318 | |||
319 | /* Build the multicast hash filter. */ | ||
320 | netdev_for_each_mc_addr(ha, net) { | ||
321 | crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | ||
322 | data->multi_filter[crc_bits >> 3] |= | ||
323 | 1 << (crc_bits & 7); | ||
324 | } | ||
325 | |||
326 | sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
327 | SR_MCAST_FILTER_SIZE, data->multi_filter); | ||
328 | |||
329 | rx_ctl |= SR_RX_CTL_AM; | ||
330 | } | ||
331 | |||
332 | sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
333 | } | ||
334 | |||
335 | static int sr_mdio_read(struct net_device *net, int phy_id, int loc) | ||
336 | { | ||
337 | struct usbnet *dev = netdev_priv(net); | ||
338 | __le16 res; | ||
339 | |||
340 | mutex_lock(&dev->phy_mutex); | ||
341 | sr_set_sw_mii(dev); | ||
342 | sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res); | ||
343 | sr_set_hw_mii(dev); | ||
344 | mutex_unlock(&dev->phy_mutex); | ||
345 | |||
346 | netdev_dbg(dev->net, | ||
347 | "%s : phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", __func__, | ||
348 | phy_id, loc, le16_to_cpu(res)); | ||
349 | |||
350 | return le16_to_cpu(res); | ||
351 | } | ||
352 | |||
353 | static void | ||
354 | sr_mdio_write(struct net_device *net, int phy_id, int loc, int val) | ||
355 | { | ||
356 | struct usbnet *dev = netdev_priv(net); | ||
357 | __le16 res = cpu_to_le16(val); | ||
358 | |||
359 | netdev_dbg(dev->net, | ||
360 | "%s : phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", __func__, | ||
361 | phy_id, loc, val); | ||
362 | mutex_lock(&dev->phy_mutex); | ||
363 | sr_set_sw_mii(dev); | ||
364 | sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); | ||
365 | sr_set_hw_mii(dev); | ||
366 | mutex_unlock(&dev->phy_mutex); | ||
367 | } | ||
368 | |||
369 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | ||
370 | static u32 sr_get_phyid(struct usbnet *dev) | ||
371 | { | ||
372 | int phy_reg; | ||
373 | u32 phy_id; | ||
374 | int i; | ||
375 | |||
376 | /* Poll for the rare case the FW or phy isn't ready yet. */ | ||
377 | for (i = 0; i < 100; i++) { | ||
378 | phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); | ||
379 | if (phy_reg != 0 && phy_reg != 0xFFFF) | ||
380 | break; | ||
381 | mdelay(1); | ||
382 | } | ||
383 | |||
384 | if (phy_reg <= 0 || phy_reg == 0xFFFF) | ||
385 | return 0; | ||
386 | |||
387 | phy_id = (phy_reg & 0xffff) << 16; | ||
388 | |||
389 | phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); | ||
390 | if (phy_reg < 0) | ||
391 | return 0; | ||
392 | |||
393 | phy_id |= (phy_reg & 0xffff); | ||
394 | |||
395 | return phy_id; | ||
396 | } | ||
397 | |||
398 | static void | ||
399 | sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
400 | { | ||
401 | struct usbnet *dev = netdev_priv(net); | ||
402 | u8 opt; | ||
403 | |||
404 | if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | ||
405 | wolinfo->supported = 0; | ||
406 | wolinfo->wolopts = 0; | ||
407 | return; | ||
408 | } | ||
409 | wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | ||
410 | wolinfo->wolopts = 0; | ||
411 | if (opt & SR_MONITOR_LINK) | ||
412 | wolinfo->wolopts |= WAKE_PHY; | ||
413 | if (opt & SR_MONITOR_MAGIC) | ||
414 | wolinfo->wolopts |= WAKE_MAGIC; | ||
415 | } | ||
416 | |||
417 | static int | ||
418 | sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
419 | { | ||
420 | struct usbnet *dev = netdev_priv(net); | ||
421 | u8 opt = 0; | ||
422 | |||
423 | if (wolinfo->wolopts & WAKE_PHY) | ||
424 | opt |= SR_MONITOR_LINK; | ||
425 | if (wolinfo->wolopts & WAKE_MAGIC) | ||
426 | opt |= SR_MONITOR_MAGIC; | ||
427 | |||
428 | if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE, | ||
429 | opt, 0, 0, NULL) < 0) | ||
430 | return -EINVAL; | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int sr_get_eeprom_len(struct net_device *net) | ||
436 | { | ||
437 | struct usbnet *dev = netdev_priv(net); | ||
438 | struct sr_data *data = (struct sr_data *)&dev->data; | ||
439 | |||
440 | return data->eeprom_len; | ||
441 | } | ||
442 | |||
443 | static int sr_get_eeprom(struct net_device *net, | ||
444 | struct ethtool_eeprom *eeprom, u8 *data) | ||
445 | { | ||
446 | struct usbnet *dev = netdev_priv(net); | ||
447 | __le16 *ebuf = (__le16 *)data; | ||
448 | int ret; | ||
449 | int i; | ||
450 | |||
451 | /* Crude hack to ensure that we don't overwrite memory | ||
452 | * if an odd length is supplied | ||
453 | */ | ||
454 | if (eeprom->len % 2) | ||
455 | return -EINVAL; | ||
456 | |||
457 | eeprom->magic = SR_EEPROM_MAGIC; | ||
458 | |||
459 | /* sr9800 returns 2 bytes from eeprom on read */ | ||
460 | for (i = 0; i < eeprom->len / 2; i++) { | ||
461 | ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i, | ||
462 | 0, 2, &ebuf[i]); | ||
463 | if (ret < 0) | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static void sr_get_drvinfo(struct net_device *net, | ||
470 | struct ethtool_drvinfo *info) | ||
471 | { | ||
472 | struct usbnet *dev = netdev_priv(net); | ||
473 | struct sr_data *data = (struct sr_data *)&dev->data; | ||
474 | |||
475 | /* Inherit standard device info */ | ||
476 | usbnet_get_drvinfo(net, info); | ||
477 | strncpy(info->driver, DRIVER_NAME, sizeof(info->driver)); | ||
478 | strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); | ||
479 | info->eedump_len = data->eeprom_len; | ||
480 | } | ||
481 | |||
482 | static u32 sr_get_link(struct net_device *net) | ||
483 | { | ||
484 | struct usbnet *dev = netdev_priv(net); | ||
485 | |||
486 | return mii_link_ok(&dev->mii); | ||
487 | } | ||
488 | |||
489 | static int sr_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | ||
490 | { | ||
491 | struct usbnet *dev = netdev_priv(net); | ||
492 | |||
493 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | ||
494 | } | ||
495 | |||
496 | static int sr_set_mac_address(struct net_device *net, void *p) | ||
497 | { | ||
498 | struct usbnet *dev = netdev_priv(net); | ||
499 | struct sr_data *data = (struct sr_data *)&dev->data; | ||
500 | struct sockaddr *addr = p; | ||
501 | |||
502 | if (netif_running(net)) | ||
503 | return -EBUSY; | ||
504 | if (!is_valid_ether_addr(addr->sa_data)) | ||
505 | return -EADDRNOTAVAIL; | ||
506 | |||
507 | memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | ||
508 | |||
509 | /* We use the 20 byte dev->data | ||
510 | * for our 6 byte mac buffer | ||
511 | * to avoid allocating memory that | ||
512 | * is tricky to free later | ||
513 | */ | ||
514 | memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); | ||
515 | sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
516 | data->mac_addr); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static const struct ethtool_ops sr9800_ethtool_ops = { | ||
522 | .get_drvinfo = sr_get_drvinfo, | ||
523 | .get_link = sr_get_link, | ||
524 | .get_msglevel = usbnet_get_msglevel, | ||
525 | .set_msglevel = usbnet_set_msglevel, | ||
526 | .get_wol = sr_get_wol, | ||
527 | .set_wol = sr_set_wol, | ||
528 | .get_eeprom_len = sr_get_eeprom_len, | ||
529 | .get_eeprom = sr_get_eeprom, | ||
530 | .get_settings = usbnet_get_settings, | ||
531 | .set_settings = usbnet_set_settings, | ||
532 | .nway_reset = usbnet_nway_reset, | ||
533 | }; | ||
534 | |||
535 | static int sr9800_link_reset(struct usbnet *dev) | ||
536 | { | ||
537 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | ||
538 | u16 mode; | ||
539 | |||
540 | mii_check_media(&dev->mii, 1, 1); | ||
541 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
542 | mode = SR9800_MEDIUM_DEFAULT; | ||
543 | |||
544 | if (ethtool_cmd_speed(&ecmd) != SPEED_100) | ||
545 | mode &= ~SR_MEDIUM_PS; | ||
546 | |||
547 | if (ecmd.duplex != DUPLEX_FULL) | ||
548 | mode &= ~SR_MEDIUM_FD; | ||
549 | |||
550 | netdev_dbg(dev->net, "%s : speed: %u duplex: %d mode: 0x%04x\n", | ||
551 | __func__, ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | ||
552 | |||
553 | sr_write_medium_mode(dev, mode); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | |||
559 | static int sr9800_set_default_mode(struct usbnet *dev) | ||
560 | { | ||
561 | u16 rx_ctl; | ||
562 | int ret; | ||
563 | |||
564 | sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
565 | sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
566 | ADVERTISE_ALL | ADVERTISE_CSMA); | ||
567 | mii_nway_restart(&dev->mii); | ||
568 | |||
569 | ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT); | ||
570 | if (ret < 0) | ||
571 | goto out; | ||
572 | |||
573 | ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012, | ||
574 | SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT, | ||
575 | SR9800_IPG2_DEFAULT, 0, NULL); | ||
576 | if (ret < 0) { | ||
577 | netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); | ||
578 | goto out; | ||
579 | } | ||
580 | |||
581 | /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | ||
582 | ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL); | ||
583 | if (ret < 0) | ||
584 | goto out; | ||
585 | |||
586 | rx_ctl = sr_read_rx_ctl(dev); | ||
587 | netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", | ||
588 | rx_ctl); | ||
589 | |||
590 | rx_ctl = sr_read_medium_status(dev); | ||
591 | netdev_dbg(dev->net, "Medium Status:0x%04x after all initializations\n", | ||
592 | rx_ctl); | ||
593 | |||
594 | return 0; | ||
595 | out: | ||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | static int sr9800_reset(struct usbnet *dev) | ||
600 | { | ||
601 | struct sr_data *data = (struct sr_data *)&dev->data; | ||
602 | int ret, embd_phy; | ||
603 | u16 rx_ctl; | ||
604 | |||
605 | ret = sr_write_gpio(dev, | ||
606 | SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5); | ||
607 | if (ret < 0) | ||
608 | goto out; | ||
609 | |||
610 | embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); | ||
611 | |||
612 | ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | ||
613 | if (ret < 0) { | ||
614 | netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); | ||
615 | goto out; | ||
616 | } | ||
617 | |||
618 | ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL); | ||
619 | if (ret < 0) | ||
620 | goto out; | ||
621 | |||
622 | msleep(150); | ||
623 | |||
624 | ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); | ||
625 | if (ret < 0) | ||
626 | goto out; | ||
627 | |||
628 | msleep(150); | ||
629 | |||
630 | if (embd_phy) { | ||
631 | ret = sr_sw_reset(dev, SR_SWRESET_IPRL); | ||
632 | if (ret < 0) | ||
633 | goto out; | ||
634 | } else { | ||
635 | ret = sr_sw_reset(dev, SR_SWRESET_PRTE); | ||
636 | if (ret < 0) | ||
637 | goto out; | ||
638 | } | ||
639 | |||
640 | msleep(150); | ||
641 | rx_ctl = sr_read_rx_ctl(dev); | ||
642 | netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); | ||
643 | ret = sr_write_rx_ctl(dev, 0x0000); | ||
644 | if (ret < 0) | ||
645 | goto out; | ||
646 | |||
647 | rx_ctl = sr_read_rx_ctl(dev); | ||
648 | netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | ||
649 | |||
650 | ret = sr_sw_reset(dev, SR_SWRESET_PRL); | ||
651 | if (ret < 0) | ||
652 | goto out; | ||
653 | |||
654 | msleep(150); | ||
655 | |||
656 | ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL); | ||
657 | if (ret < 0) | ||
658 | goto out; | ||
659 | |||
660 | msleep(150); | ||
661 | |||
662 | ret = sr9800_set_default_mode(dev); | ||
663 | if (ret < 0) | ||
664 | goto out; | ||
665 | |||
666 | /* Rewrite MAC address */ | ||
667 | memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | ||
668 | ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
669 | data->mac_addr); | ||
670 | if (ret < 0) | ||
671 | goto out; | ||
672 | |||
673 | return 0; | ||
674 | |||
675 | out: | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | static const struct net_device_ops sr9800_netdev_ops = { | ||
680 | .ndo_open = usbnet_open, | ||
681 | .ndo_stop = usbnet_stop, | ||
682 | .ndo_start_xmit = usbnet_start_xmit, | ||
683 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
684 | .ndo_change_mtu = usbnet_change_mtu, | ||
685 | .ndo_set_mac_address = sr_set_mac_address, | ||
686 | .ndo_validate_addr = eth_validate_addr, | ||
687 | .ndo_do_ioctl = sr_ioctl, | ||
688 | .ndo_set_rx_mode = sr_set_multicast, | ||
689 | }; | ||
690 | |||
691 | static int sr9800_phy_powerup(struct usbnet *dev) | ||
692 | { | ||
693 | int ret; | ||
694 | |||
695 | /* set the embedded Ethernet PHY in power-down state */ | ||
696 | ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL); | ||
697 | if (ret < 0) { | ||
698 | netdev_err(dev->net, "Failed to power down PHY : %d\n", ret); | ||
699 | return ret; | ||
700 | } | ||
701 | msleep(20); | ||
702 | |||
703 | /* set the embedded Ethernet PHY in power-up state */ | ||
704 | ret = sr_sw_reset(dev, SR_SWRESET_IPRL); | ||
705 | if (ret < 0) { | ||
706 | netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); | ||
707 | return ret; | ||
708 | } | ||
709 | msleep(600); | ||
710 | |||
711 | /* set the embedded Ethernet PHY in reset state */ | ||
712 | ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); | ||
713 | if (ret < 0) { | ||
714 | netdev_err(dev->net, "Failed to power up PHY: %d\n", ret); | ||
715 | return ret; | ||
716 | } | ||
717 | msleep(20); | ||
718 | |||
719 | /* set the embedded Ethernet PHY in power-up state */ | ||
720 | ret = sr_sw_reset(dev, SR_SWRESET_IPRL); | ||
721 | if (ret < 0) { | ||
722 | netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); | ||
723 | return ret; | ||
724 | } | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf) | ||
730 | { | ||
731 | struct sr_data *data = (struct sr_data *)&dev->data; | ||
732 | u16 led01_mux, led23_mux; | ||
733 | int ret, embd_phy; | ||
734 | u32 phyid; | ||
735 | u16 rx_ctl; | ||
736 | |||
737 | data->eeprom_len = SR9800_EEPROM_LEN; | ||
738 | |||
739 | usbnet_get_endpoints(dev, intf); | ||
740 | |||
741 | /* LED Setting Rule : | ||
742 | * AABB:CCDD | ||
743 | * AA : MFA0(LED0) | ||
744 | * BB : MFA1(LED1) | ||
745 | * CC : MFA2(LED2), Reserved for SR9800 | ||
746 | * DD : MFA3(LED3), Reserved for SR9800 | ||
747 | */ | ||
748 | led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK; | ||
749 | led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE; | ||
750 | ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL); | ||
751 | if (ret < 0) { | ||
752 | netdev_err(dev->net, "set LINK LED failed : %d\n", ret); | ||
753 | goto out; | ||
754 | } | ||
755 | |||
756 | /* Get the MAC address */ | ||
757 | ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, | ||
758 | dev->net->dev_addr); | ||
759 | if (ret < 0) { | ||
760 | netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); | ||
761 | return ret; | ||
762 | } | ||
763 | netdev_dbg(dev->net, "mac addr : %pM\n", dev->net->dev_addr); | ||
764 | |||
765 | /* Initialize MII structure */ | ||
766 | dev->mii.dev = dev->net; | ||
767 | dev->mii.mdio_read = sr_mdio_read; | ||
768 | dev->mii.mdio_write = sr_mdio_write; | ||
769 | dev->mii.phy_id_mask = 0x1f; | ||
770 | dev->mii.reg_num_mask = 0x1f; | ||
771 | dev->mii.phy_id = sr_get_phy_addr(dev); | ||
772 | |||
773 | dev->net->netdev_ops = &sr9800_netdev_ops; | ||
774 | dev->net->ethtool_ops = &sr9800_ethtool_ops; | ||
775 | |||
776 | embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); | ||
777 | /* Reset the PHY to normal operation mode */ | ||
778 | ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | ||
779 | if (ret < 0) { | ||
780 | netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); | ||
781 | return ret; | ||
782 | } | ||
783 | |||
784 | /* Init PHY routine */ | ||
785 | ret = sr9800_phy_powerup(dev); | ||
786 | if (ret < 0) | ||
787 | goto out; | ||
788 | |||
789 | rx_ctl = sr_read_rx_ctl(dev); | ||
790 | netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); | ||
791 | ret = sr_write_rx_ctl(dev, 0x0000); | ||
792 | if (ret < 0) | ||
793 | goto out; | ||
794 | |||
795 | rx_ctl = sr_read_rx_ctl(dev); | ||
796 | netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | ||
797 | |||
798 | /* Read PHYID register *AFTER* the PHY was reset properly */ | ||
799 | phyid = sr_get_phyid(dev); | ||
800 | netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); | ||
801 | |||
802 | /* medium mode setting */ | ||
803 | ret = sr9800_set_default_mode(dev); | ||
804 | if (ret < 0) | ||
805 | goto out; | ||
806 | |||
807 | if (dev->udev->speed == USB_SPEED_HIGH) { | ||
808 | ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, | ||
809 | SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt, | ||
810 | SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold, | ||
811 | 0, NULL); | ||
812 | if (ret < 0) { | ||
813 | netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); | ||
814 | goto out; | ||
815 | } | ||
816 | dev->rx_urb_size = | ||
817 | SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size; | ||
818 | } else { | ||
819 | ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, | ||
820 | SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt, | ||
821 | SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold, | ||
822 | 0, NULL); | ||
823 | if (ret < 0) { | ||
824 | netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); | ||
825 | goto out; | ||
826 | } | ||
827 | dev->rx_urb_size = | ||
828 | SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size; | ||
829 | } | ||
830 | netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__, | ||
831 | dev->rx_urb_size); | ||
832 | return 0; | ||
833 | |||
834 | out: | ||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | static const struct driver_info sr9800_driver_info = { | ||
839 | .description = "CoreChip SR9800 USB 2.0 Ethernet", | ||
840 | .bind = sr9800_bind, | ||
841 | .status = sr_status, | ||
842 | .link_reset = sr9800_link_reset, | ||
843 | .reset = sr9800_reset, | ||
844 | .flags = DRIVER_FLAG, | ||
845 | .rx_fixup = sr_rx_fixup, | ||
846 | .tx_fixup = sr_tx_fixup, | ||
847 | }; | ||
848 | |||
849 | static const struct usb_device_id products[] = { | ||
850 | { | ||
851 | USB_DEVICE(0x0fe6, 0x9800), /* SR9800 Device */ | ||
852 | .driver_info = (unsigned long) &sr9800_driver_info, | ||
853 | }, | ||
854 | {}, /* END */ | ||
855 | }; | ||
856 | |||
857 | MODULE_DEVICE_TABLE(usb, products); | ||
858 | |||
859 | static struct usb_driver sr_driver = { | ||
860 | .name = DRIVER_NAME, | ||
861 | .id_table = products, | ||
862 | .probe = usbnet_probe, | ||
863 | .suspend = usbnet_suspend, | ||
864 | .resume = usbnet_resume, | ||
865 | .disconnect = usbnet_disconnect, | ||
866 | .supports_autosuspend = 1, | ||
867 | }; | ||
868 | |||
869 | module_usb_driver(sr_driver); | ||
870 | |||
871 | MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com"); | ||
872 | MODULE_VERSION(DRIVER_VERSION); | ||
873 | MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com"); | ||
874 | MODULE_LICENSE("GPL"); | ||