diff options
author | Christian Riesch <christian.riesch@omicron.at> | 2012-07-13 01:26:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-17 02:26:23 -0400 |
commit | 607740bc1605395c96b09416cdcc5e77c8976eed (patch) | |
tree | 684d41f965a2b5771a1dbef9501fa51a5fa73a23 | |
parent | b4cdae20ef956fb80b231cbbcfcdb446fed763ca (diff) |
asix: Factor out common code
Allow the new driver for the AX88172A to share code with the
existing drivers for ASIX devices.
Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/usb/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/usb/asix.h | 1532 | ||||
-rw-r--r-- | drivers/net/usb/asix_common.c | 1203 | ||||
-rw-r--r-- | drivers/net/usb/asix_devices.c | 660 |
4 files changed, 64 insertions, 3333 deletions
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index 2c8f7b4a5d8..a9490d9a4e9 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile | |||
@@ -8,7 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o | |||
8 | obj-$(CONFIG_USB_RTL8150) += rtl8150.o | 8 | obj-$(CONFIG_USB_RTL8150) += rtl8150.o |
9 | obj-$(CONFIG_USB_HSO) += hso.o | 9 | obj-$(CONFIG_USB_HSO) += hso.o |
10 | obj-$(CONFIG_USB_NET_AX8817X) += asix.o | 10 | obj-$(CONFIG_USB_NET_AX8817X) += asix.o |
11 | asix-y := asix_devices.o | 11 | asix-y := asix_devices.o asix_common.o |
12 | obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o | 12 | obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o |
13 | obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o | 13 | obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o |
14 | obj-$(CONFIG_USB_NET_DM9601) += dm9601.o | 14 | obj-$(CONFIG_USB_NET_DM9601) += dm9601.o |
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index 6564c32d3af..790af241f19 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h | |||
@@ -20,6 +20,9 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #ifndef _ASIX_H | ||
24 | #define _ASIX_H | ||
25 | |||
23 | // #define DEBUG // error path messages, extra info | 26 | // #define DEBUG // error path messages, extra info |
24 | // #define VERBOSE // more; success messages | 27 | // #define VERBOSE // more; success messages |
25 | 28 | ||
@@ -152,20 +155,6 @@ | |||
152 | #define AX88172_EEPROM_LEN 0x40 | 155 | #define AX88172_EEPROM_LEN 0x40 |
153 | #define AX88772_EEPROM_LEN 0xff | 156 | #define AX88772_EEPROM_LEN 0xff |
154 | 157 | ||
155 | #define PHY_MODE_MARVELL 0x0000 | ||
156 | #define MII_MARVELL_LED_CTRL 0x0018 | ||
157 | #define MII_MARVELL_STATUS 0x001b | ||
158 | #define MII_MARVELL_CTRL 0x0014 | ||
159 | |||
160 | #define MARVELL_LED_MANUAL 0x0019 | ||
161 | |||
162 | #define MARVELL_STATUS_HWCFG 0x0004 | ||
163 | |||
164 | #define MARVELL_CTRL_TXDELAY 0x0002 | ||
165 | #define MARVELL_CTRL_RXDELAY 0x0080 | ||
166 | |||
167 | #define PHY_MODE_RTL8211CL 0x000C | ||
168 | |||
169 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | 158 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ |
170 | struct asix_data { | 159 | struct asix_data { |
171 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; | 160 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; |
@@ -175,1506 +164,49 @@ struct asix_data { | |||
175 | u8 eeprom_len; | 164 | u8 eeprom_len; |
176 | }; | 165 | }; |
177 | 166 | ||
178 | struct ax88172_int_data { | 167 | int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
179 | __le16 res1; | 168 | u16 size, void *data); |
180 | u8 link; | ||
181 | __le16 res2; | ||
182 | u8 status; | ||
183 | __le16 res3; | ||
184 | } __packed; | ||
185 | |||
186 | static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
187 | u16 size, void *data) | ||
188 | { | ||
189 | void *buf; | ||
190 | int err = -ENOMEM; | ||
191 | |||
192 | netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
193 | cmd, value, index, size); | ||
194 | |||
195 | buf = kmalloc(size, GFP_KERNEL); | ||
196 | if (!buf) | ||
197 | goto out; | ||
198 | |||
199 | err = usb_control_msg( | ||
200 | dev->udev, | ||
201 | usb_rcvctrlpipe(dev->udev, 0), | ||
202 | cmd, | ||
203 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
204 | value, | ||
205 | index, | ||
206 | buf, | ||
207 | size, | ||
208 | USB_CTRL_GET_TIMEOUT); | ||
209 | if (err == size) | ||
210 | memcpy(data, buf, size); | ||
211 | else if (err >= 0) | ||
212 | err = -EINVAL; | ||
213 | kfree(buf); | ||
214 | |||
215 | out: | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
220 | u16 size, void *data) | ||
221 | { | ||
222 | void *buf = NULL; | ||
223 | int err = -ENOMEM; | ||
224 | |||
225 | netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
226 | cmd, value, index, size); | ||
227 | |||
228 | if (data) { | ||
229 | buf = kmemdup(data, size, GFP_KERNEL); | ||
230 | if (!buf) | ||
231 | goto out; | ||
232 | } | ||
233 | |||
234 | err = usb_control_msg( | ||
235 | dev->udev, | ||
236 | usb_sndctrlpipe(dev->udev, 0), | ||
237 | cmd, | ||
238 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
239 | value, | ||
240 | index, | ||
241 | buf, | ||
242 | size, | ||
243 | USB_CTRL_SET_TIMEOUT); | ||
244 | kfree(buf); | ||
245 | |||
246 | out: | ||
247 | return err; | ||
248 | } | ||
249 | |||
250 | static void asix_async_cmd_callback(struct urb *urb) | ||
251 | { | ||
252 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
253 | int status = urb->status; | ||
254 | |||
255 | if (status < 0) | ||
256 | printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", | ||
257 | status); | ||
258 | |||
259 | kfree(req); | ||
260 | usb_free_urb(urb); | ||
261 | } | ||
262 | |||
263 | static void | ||
264 | asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
265 | u16 size, void *data) | ||
266 | { | ||
267 | struct usb_ctrlrequest *req; | ||
268 | int status; | ||
269 | struct urb *urb; | ||
270 | |||
271 | netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
272 | cmd, value, index, size); | ||
273 | |||
274 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
275 | if (!urb) { | ||
276 | netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
281 | if (!req) { | ||
282 | netdev_err(dev->net, "Failed to allocate memory for control request\n"); | ||
283 | usb_free_urb(urb); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | ||
288 | req->bRequest = cmd; | ||
289 | req->wValue = cpu_to_le16(value); | ||
290 | req->wIndex = cpu_to_le16(index); | ||
291 | req->wLength = cpu_to_le16(size); | ||
292 | |||
293 | usb_fill_control_urb(urb, dev->udev, | ||
294 | usb_sndctrlpipe(dev->udev, 0), | ||
295 | (void *)req, data, size, | ||
296 | asix_async_cmd_callback, req); | ||
297 | |||
298 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
299 | if (status < 0) { | ||
300 | netdev_err(dev->net, "Error submitting the control message: status=%d\n", | ||
301 | status); | ||
302 | kfree(req); | ||
303 | usb_free_urb(urb); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
308 | { | ||
309 | int offset = 0; | ||
310 | |||
311 | while (offset + sizeof(u32) < skb->len) { | ||
312 | struct sk_buff *ax_skb; | ||
313 | u16 size; | ||
314 | u32 header = get_unaligned_le32(skb->data + offset); | ||
315 | |||
316 | offset += sizeof(u32); | ||
317 | |||
318 | /* get the packet length */ | ||
319 | size = (u16) (header & 0x7ff); | ||
320 | if (size != ((~header >> 16) & 0x07ff)) { | ||
321 | netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || | ||
326 | (size + offset > skb->len)) { | ||
327 | netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", | ||
328 | size); | ||
329 | return 0; | ||
330 | } | ||
331 | ax_skb = netdev_alloc_skb_ip_align(dev->net, size); | ||
332 | if (!ax_skb) | ||
333 | return 0; | ||
334 | |||
335 | skb_put(ax_skb, size); | ||
336 | memcpy(ax_skb->data, skb->data + offset, size); | ||
337 | usbnet_skb_return(dev, ax_skb); | ||
338 | |||
339 | offset += (size + 1) & 0xfffe; | ||
340 | } | ||
341 | |||
342 | if (skb->len != offset) { | ||
343 | netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", | ||
344 | skb->len); | ||
345 | return 0; | ||
346 | } | ||
347 | return 1; | ||
348 | } | ||
349 | |||
350 | static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
351 | gfp_t flags) | ||
352 | { | ||
353 | int padlen; | ||
354 | int headroom = skb_headroom(skb); | ||
355 | int tailroom = skb_tailroom(skb); | ||
356 | u32 packet_len; | ||
357 | u32 padbytes = 0xffff0000; | ||
358 | |||
359 | padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; | ||
360 | |||
361 | /* We need to push 4 bytes in front of frame (packet_len) | ||
362 | * and maybe add 4 bytes after the end (if padlen is 4) | ||
363 | * | ||
364 | * Avoid skb_copy_expand() expensive call, using following rules : | ||
365 | * - We are allowed to push 4 bytes in headroom if skb_header_cloned() | ||
366 | * is false (and if we have 4 bytes of headroom) | ||
367 | * - We are allowed to put 4 bytes at tail if skb_cloned() | ||
368 | * is false (and if we have 4 bytes of tailroom) | ||
369 | * | ||
370 | * TCP packets for example are cloned, but skb_header_release() | ||
371 | * was called in tcp stack, allowing us to use headroom for our needs. | ||
372 | */ | ||
373 | if (!skb_header_cloned(skb) && | ||
374 | !(padlen && skb_cloned(skb)) && | ||
375 | headroom + tailroom >= 4 + padlen) { | ||
376 | /* following should not happen, but better be safe */ | ||
377 | if (headroom < 4 || | ||
378 | tailroom < padlen) { | ||
379 | skb->data = memmove(skb->head + 4, skb->data, skb->len); | ||
380 | skb_set_tail_pointer(skb, skb->len); | ||
381 | } | ||
382 | } else { | ||
383 | struct sk_buff *skb2; | ||
384 | |||
385 | skb2 = skb_copy_expand(skb, 4, padlen, flags); | ||
386 | dev_kfree_skb_any(skb); | ||
387 | skb = skb2; | ||
388 | if (!skb) | ||
389 | return NULL; | ||
390 | } | ||
391 | |||
392 | packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; | ||
393 | skb_push(skb, 4); | ||
394 | cpu_to_le32s(&packet_len); | ||
395 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | ||
396 | |||
397 | if (padlen) { | ||
398 | cpu_to_le32s(&padbytes); | ||
399 | memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | ||
400 | skb_put(skb, sizeof(padbytes)); | ||
401 | } | ||
402 | return skb; | ||
403 | } | ||
404 | |||
405 | static void asix_status(struct usbnet *dev, struct urb *urb) | ||
406 | { | ||
407 | struct ax88172_int_data *event; | ||
408 | int link; | ||
409 | |||
410 | if (urb->actual_length < 8) | ||
411 | return; | ||
412 | |||
413 | event = urb->transfer_buffer; | ||
414 | link = event->link & 0x01; | ||
415 | if (netif_carrier_ok(dev->net) != link) { | ||
416 | if (link) { | ||
417 | netif_carrier_on(dev->net); | ||
418 | usbnet_defer_kevent (dev, EVENT_LINK_RESET ); | ||
419 | } else | ||
420 | netif_carrier_off(dev->net); | ||
421 | netdev_dbg(dev->net, "Link Status is: %d\n", link); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | static inline int asix_set_sw_mii(struct usbnet *dev) | ||
426 | { | ||
427 | int ret; | ||
428 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | ||
429 | if (ret < 0) | ||
430 | netdev_err(dev->net, "Failed to enable software MII access\n"); | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | static inline int asix_set_hw_mii(struct usbnet *dev) | ||
435 | { | ||
436 | int ret; | ||
437 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | ||
438 | if (ret < 0) | ||
439 | netdev_err(dev->net, "Failed to enable hardware MII access\n"); | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | static inline int asix_get_phy_addr(struct usbnet *dev) | ||
444 | { | ||
445 | u8 buf[2]; | ||
446 | int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); | ||
447 | |||
448 | netdev_dbg(dev->net, "asix_get_phy_addr()\n"); | ||
449 | |||
450 | if (ret < 0) { | ||
451 | netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); | ||
452 | goto out; | ||
453 | } | ||
454 | netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", | ||
455 | *((__le16 *)buf)); | ||
456 | ret = buf[1]; | ||
457 | |||
458 | out: | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | static int asix_sw_reset(struct usbnet *dev, u8 flags) | ||
463 | { | ||
464 | int ret; | ||
465 | |||
466 | ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); | ||
467 | if (ret < 0) | ||
468 | netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); | ||
469 | |||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | static u16 asix_read_rx_ctl(struct usbnet *dev) | ||
474 | { | ||
475 | __le16 v; | ||
476 | int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); | ||
477 | |||
478 | if (ret < 0) { | ||
479 | netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); | ||
480 | goto out; | ||
481 | } | ||
482 | ret = le16_to_cpu(v); | ||
483 | out: | ||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | ||
488 | { | ||
489 | int ret; | ||
490 | |||
491 | netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); | ||
492 | ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | ||
493 | if (ret < 0) | ||
494 | netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", | ||
495 | mode, ret); | ||
496 | |||
497 | return ret; | ||
498 | } | ||
499 | |||
500 | static u16 asix_read_medium_status(struct usbnet *dev) | ||
501 | { | ||
502 | __le16 v; | ||
503 | int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | ||
504 | |||
505 | if (ret < 0) { | ||
506 | netdev_err(dev->net, "Error reading Medium Status register: %02x\n", | ||
507 | ret); | ||
508 | return ret; /* TODO: callers not checking for error ret */ | ||
509 | } | ||
510 | |||
511 | return le16_to_cpu(v); | ||
512 | |||
513 | } | ||
514 | |||
515 | static int asix_write_medium_mode(struct usbnet *dev, u16 mode) | ||
516 | { | ||
517 | int ret; | ||
518 | |||
519 | netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); | ||
520 | ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
521 | if (ret < 0) | ||
522 | netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", | ||
523 | mode, ret); | ||
524 | |||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | ||
529 | { | ||
530 | int ret; | ||
531 | |||
532 | netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); | ||
533 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); | ||
534 | if (ret < 0) | ||
535 | netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", | ||
536 | value, ret); | ||
537 | |||
538 | if (sleep) | ||
539 | msleep(sleep); | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * AX88772 & AX88178 have a 16-bit RX_CTL value | ||
546 | */ | ||
547 | static void asix_set_multicast(struct net_device *net) | ||
548 | { | ||
549 | struct usbnet *dev = netdev_priv(net); | ||
550 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
551 | u16 rx_ctl = AX_DEFAULT_RX_CTL; | ||
552 | |||
553 | if (net->flags & IFF_PROMISC) { | ||
554 | rx_ctl |= AX_RX_CTL_PRO; | ||
555 | } else if (net->flags & IFF_ALLMULTI || | ||
556 | netdev_mc_count(net) > AX_MAX_MCAST) { | ||
557 | rx_ctl |= AX_RX_CTL_AMALL; | ||
558 | } else if (netdev_mc_empty(net)) { | ||
559 | /* just broadcast and directed */ | ||
560 | } else { | ||
561 | /* We use the 20 byte dev->data | ||
562 | * for our 8 byte filter buffer | ||
563 | * to avoid allocating memory that | ||
564 | * is tricky to free later */ | ||
565 | struct netdev_hw_addr *ha; | ||
566 | u32 crc_bits; | ||
567 | |||
568 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
569 | |||
570 | /* Build the multicast hash filter. */ | ||
571 | netdev_for_each_mc_addr(ha, net) { | ||
572 | crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | ||
573 | data->multi_filter[crc_bits >> 3] |= | ||
574 | 1 << (crc_bits & 7); | ||
575 | } | ||
576 | |||
577 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
578 | AX_MCAST_FILTER_SIZE, data->multi_filter); | ||
579 | |||
580 | rx_ctl |= AX_RX_CTL_AM; | ||
581 | } | ||
582 | |||
583 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
584 | } | ||
585 | |||
586 | static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | ||
587 | { | ||
588 | struct usbnet *dev = netdev_priv(netdev); | ||
589 | __le16 res; | ||
590 | |||
591 | mutex_lock(&dev->phy_mutex); | ||
592 | asix_set_sw_mii(dev); | ||
593 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, | ||
594 | (__u16)loc, 2, &res); | ||
595 | asix_set_hw_mii(dev); | ||
596 | mutex_unlock(&dev->phy_mutex); | ||
597 | |||
598 | netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | ||
599 | phy_id, loc, le16_to_cpu(res)); | ||
600 | |||
601 | return le16_to_cpu(res); | ||
602 | } | ||
603 | |||
604 | static void | ||
605 | asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | ||
606 | { | ||
607 | struct usbnet *dev = netdev_priv(netdev); | ||
608 | __le16 res = cpu_to_le16(val); | ||
609 | |||
610 | netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | ||
611 | phy_id, loc, val); | ||
612 | mutex_lock(&dev->phy_mutex); | ||
613 | asix_set_sw_mii(dev); | ||
614 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); | ||
615 | asix_set_hw_mii(dev); | ||
616 | mutex_unlock(&dev->phy_mutex); | ||
617 | } | ||
618 | |||
619 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | ||
620 | static u32 asix_get_phyid(struct usbnet *dev) | ||
621 | { | ||
622 | int phy_reg; | ||
623 | u32 phy_id; | ||
624 | int i; | ||
625 | |||
626 | /* Poll for the rare case the FW or phy isn't ready yet. */ | ||
627 | for (i = 0; i < 100; i++) { | ||
628 | phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); | ||
629 | if (phy_reg != 0 && phy_reg != 0xFFFF) | ||
630 | break; | ||
631 | mdelay(1); | ||
632 | } | ||
633 | |||
634 | if (phy_reg <= 0 || phy_reg == 0xFFFF) | ||
635 | return 0; | ||
636 | |||
637 | phy_id = (phy_reg & 0xffff) << 16; | ||
638 | |||
639 | phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); | ||
640 | if (phy_reg < 0) | ||
641 | return 0; | ||
642 | |||
643 | phy_id |= (phy_reg & 0xffff); | ||
644 | |||
645 | return phy_id; | ||
646 | } | ||
647 | |||
648 | static void | ||
649 | asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
650 | { | ||
651 | struct usbnet *dev = netdev_priv(net); | ||
652 | u8 opt; | ||
653 | |||
654 | if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | ||
655 | wolinfo->supported = 0; | ||
656 | wolinfo->wolopts = 0; | ||
657 | return; | ||
658 | } | ||
659 | wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | ||
660 | wolinfo->wolopts = 0; | ||
661 | if (opt & AX_MONITOR_LINK) | ||
662 | wolinfo->wolopts |= WAKE_PHY; | ||
663 | if (opt & AX_MONITOR_MAGIC) | ||
664 | wolinfo->wolopts |= WAKE_MAGIC; | ||
665 | } | ||
666 | |||
667 | static int | ||
668 | asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
669 | { | ||
670 | struct usbnet *dev = netdev_priv(net); | ||
671 | u8 opt = 0; | ||
672 | |||
673 | if (wolinfo->wolopts & WAKE_PHY) | ||
674 | opt |= AX_MONITOR_LINK; | ||
675 | if (wolinfo->wolopts & WAKE_MAGIC) | ||
676 | opt |= AX_MONITOR_MAGIC; | ||
677 | |||
678 | if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, | ||
679 | opt, 0, 0, NULL) < 0) | ||
680 | return -EINVAL; | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static int asix_get_eeprom_len(struct net_device *net) | ||
686 | { | ||
687 | struct usbnet *dev = netdev_priv(net); | ||
688 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
689 | |||
690 | return data->eeprom_len; | ||
691 | } | ||
692 | |||
693 | static int asix_get_eeprom(struct net_device *net, | ||
694 | struct ethtool_eeprom *eeprom, u8 *data) | ||
695 | { | ||
696 | struct usbnet *dev = netdev_priv(net); | ||
697 | __le16 *ebuf = (__le16 *)data; | ||
698 | int i; | ||
699 | |||
700 | /* Crude hack to ensure that we don't overwrite memory | ||
701 | * if an odd length is supplied | ||
702 | */ | ||
703 | if (eeprom->len % 2) | ||
704 | return -EINVAL; | ||
705 | |||
706 | eeprom->magic = AX_EEPROM_MAGIC; | ||
707 | |||
708 | /* ax8817x returns 2 bytes from eeprom on read */ | ||
709 | for (i=0; i < eeprom->len / 2; i++) { | ||
710 | if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, | ||
711 | eeprom->offset + i, 0, 2, &ebuf[i]) < 0) | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static void asix_get_drvinfo (struct net_device *net, | ||
718 | struct ethtool_drvinfo *info) | ||
719 | { | ||
720 | struct usbnet *dev = netdev_priv(net); | ||
721 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
722 | |||
723 | /* Inherit standard device info */ | ||
724 | usbnet_get_drvinfo(net, info); | ||
725 | strncpy (info->driver, DRIVER_NAME, sizeof info->driver); | ||
726 | strncpy (info->version, DRIVER_VERSION, sizeof info->version); | ||
727 | info->eedump_len = data->eeprom_len; | ||
728 | } | ||
729 | |||
730 | static u32 asix_get_link(struct net_device *net) | ||
731 | { | ||
732 | struct usbnet *dev = netdev_priv(net); | ||
733 | |||
734 | return mii_link_ok(&dev->mii); | ||
735 | } | ||
736 | |||
737 | static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) | ||
738 | { | ||
739 | struct usbnet *dev = netdev_priv(net); | ||
740 | |||
741 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | ||
742 | } | ||
743 | |||
744 | static int asix_set_mac_address(struct net_device *net, void *p) | ||
745 | { | ||
746 | struct usbnet *dev = netdev_priv(net); | ||
747 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
748 | struct sockaddr *addr = p; | ||
749 | |||
750 | if (netif_running(net)) | ||
751 | return -EBUSY; | ||
752 | if (!is_valid_ether_addr(addr->sa_data)) | ||
753 | return -EADDRNOTAVAIL; | ||
754 | |||
755 | memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | ||
756 | |||
757 | /* We use the 20 byte dev->data | ||
758 | * for our 6 byte mac buffer | ||
759 | * to avoid allocating memory that | ||
760 | * is tricky to free later */ | ||
761 | memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); | ||
762 | asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
763 | data->mac_addr); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | /* We need to override some ethtool_ops so we require our | ||
769 | own structure so we don't interfere with other usbnet | ||
770 | devices that may be connected at the same time. */ | ||
771 | static const struct ethtool_ops ax88172_ethtool_ops = { | ||
772 | .get_drvinfo = asix_get_drvinfo, | ||
773 | .get_link = asix_get_link, | ||
774 | .get_msglevel = usbnet_get_msglevel, | ||
775 | .set_msglevel = usbnet_set_msglevel, | ||
776 | .get_wol = asix_get_wol, | ||
777 | .set_wol = asix_set_wol, | ||
778 | .get_eeprom_len = asix_get_eeprom_len, | ||
779 | .get_eeprom = asix_get_eeprom, | ||
780 | .get_settings = usbnet_get_settings, | ||
781 | .set_settings = usbnet_set_settings, | ||
782 | .nway_reset = usbnet_nway_reset, | ||
783 | }; | ||
784 | |||
785 | static void ax88172_set_multicast(struct net_device *net) | ||
786 | { | ||
787 | struct usbnet *dev = netdev_priv(net); | ||
788 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
789 | u8 rx_ctl = 0x8c; | ||
790 | |||
791 | if (net->flags & IFF_PROMISC) { | ||
792 | rx_ctl |= 0x01; | ||
793 | } else if (net->flags & IFF_ALLMULTI || | ||
794 | netdev_mc_count(net) > AX_MAX_MCAST) { | ||
795 | rx_ctl |= 0x02; | ||
796 | } else if (netdev_mc_empty(net)) { | ||
797 | /* just broadcast and directed */ | ||
798 | } else { | ||
799 | /* We use the 20 byte dev->data | ||
800 | * for our 8 byte filter buffer | ||
801 | * to avoid allocating memory that | ||
802 | * is tricky to free later */ | ||
803 | struct netdev_hw_addr *ha; | ||
804 | u32 crc_bits; | ||
805 | |||
806 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
807 | 169 | ||
808 | /* Build the multicast hash filter. */ | 170 | int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
809 | netdev_for_each_mc_addr(ha, net) { | 171 | u16 size, void *data); |
810 | crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | ||
811 | data->multi_filter[crc_bits >> 3] |= | ||
812 | 1 << (crc_bits & 7); | ||
813 | } | ||
814 | 172 | ||
815 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | 173 | void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, |
816 | AX_MCAST_FILTER_SIZE, data->multi_filter); | 174 | u16 index, u16 size, void *data); |
817 | 175 | ||
818 | rx_ctl |= 0x10; | 176 | int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb); |
819 | } | ||
820 | 177 | ||
821 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | 178 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
822 | } | 179 | gfp_t flags); |
823 | 180 | ||
824 | static int ax88172_link_reset(struct usbnet *dev) | 181 | int asix_set_sw_mii(struct usbnet *dev); |
825 | { | 182 | int asix_set_hw_mii(struct usbnet *dev); |
826 | u8 mode; | ||
827 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | ||
828 | 183 | ||
829 | mii_check_media(&dev->mii, 1, 1); | 184 | int asix_get_phy_addr(struct usbnet *dev); |
830 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
831 | mode = AX88172_MEDIUM_DEFAULT; | ||
832 | 185 | ||
833 | if (ecmd.duplex != DUPLEX_FULL) | 186 | int asix_sw_reset(struct usbnet *dev, u8 flags); |
834 | mode |= ~AX88172_MEDIUM_FD; | ||
835 | 187 | ||
836 | netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | 188 | u16 asix_read_rx_ctl(struct usbnet *dev); |
837 | ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | 189 | int asix_write_rx_ctl(struct usbnet *dev, u16 mode); |
838 | 190 | ||
839 | asix_write_medium_mode(dev, mode); | 191 | u16 asix_read_medium_status(struct usbnet *dev); |
840 | 192 | int asix_write_medium_mode(struct usbnet *dev, u16 mode); | |
841 | return 0; | ||
842 | } | ||
843 | |||
844 | static const struct net_device_ops ax88172_netdev_ops = { | ||
845 | .ndo_open = usbnet_open, | ||
846 | .ndo_stop = usbnet_stop, | ||
847 | .ndo_start_xmit = usbnet_start_xmit, | ||
848 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
849 | .ndo_change_mtu = usbnet_change_mtu, | ||
850 | .ndo_set_mac_address = eth_mac_addr, | ||
851 | .ndo_validate_addr = eth_validate_addr, | ||
852 | .ndo_do_ioctl = asix_ioctl, | ||
853 | .ndo_set_rx_mode = ax88172_set_multicast, | ||
854 | }; | ||
855 | |||
856 | static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) | ||
857 | { | ||
858 | int ret = 0; | ||
859 | u8 buf[ETH_ALEN]; | ||
860 | int i; | ||
861 | unsigned long gpio_bits = dev->driver_info->data; | ||
862 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
863 | |||
864 | data->eeprom_len = AX88172_EEPROM_LEN; | ||
865 | |||
866 | usbnet_get_endpoints(dev,intf); | ||
867 | |||
868 | /* Toggle the GPIOs in a manufacturer/model specific way */ | ||
869 | for (i = 2; i >= 0; i--) { | ||
870 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, | ||
871 | (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); | ||
872 | if (ret < 0) | ||
873 | goto out; | ||
874 | msleep(5); | ||
875 | } | ||
876 | |||
877 | ret = asix_write_rx_ctl(dev, 0x80); | ||
878 | if (ret < 0) | ||
879 | goto out; | ||
880 | |||
881 | /* Get the MAC address */ | ||
882 | ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | ||
883 | if (ret < 0) { | ||
884 | dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); | ||
885 | goto out; | ||
886 | } | ||
887 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
888 | |||
889 | /* Initialize MII structure */ | ||
890 | dev->mii.dev = dev->net; | ||
891 | dev->mii.mdio_read = asix_mdio_read; | ||
892 | dev->mii.mdio_write = asix_mdio_write; | ||
893 | dev->mii.phy_id_mask = 0x3f; | ||
894 | dev->mii.reg_num_mask = 0x1f; | ||
895 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
896 | |||
897 | dev->net->netdev_ops = &ax88172_netdev_ops; | ||
898 | dev->net->ethtool_ops = &ax88172_ethtool_ops; | ||
899 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
900 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
901 | |||
902 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
903 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
904 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | ||
905 | mii_nway_restart(&dev->mii); | ||
906 | |||
907 | return 0; | ||
908 | |||
909 | out: | ||
910 | return ret; | ||
911 | } | ||
912 | |||
913 | static const struct ethtool_ops ax88772_ethtool_ops = { | ||
914 | .get_drvinfo = asix_get_drvinfo, | ||
915 | .get_link = asix_get_link, | ||
916 | .get_msglevel = usbnet_get_msglevel, | ||
917 | .set_msglevel = usbnet_set_msglevel, | ||
918 | .get_wol = asix_get_wol, | ||
919 | .set_wol = asix_set_wol, | ||
920 | .get_eeprom_len = asix_get_eeprom_len, | ||
921 | .get_eeprom = asix_get_eeprom, | ||
922 | .get_settings = usbnet_get_settings, | ||
923 | .set_settings = usbnet_set_settings, | ||
924 | .nway_reset = usbnet_nway_reset, | ||
925 | }; | ||
926 | 193 | ||
927 | static int ax88772_link_reset(struct usbnet *dev) | 194 | int asix_write_gpio(struct usbnet *dev, u16 value, int sleep); |
928 | { | ||
929 | u16 mode; | ||
930 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | ||
931 | 195 | ||
932 | mii_check_media(&dev->mii, 1, 1); | 196 | void asix_set_multicast(struct net_device *net); |
933 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
934 | mode = AX88772_MEDIUM_DEFAULT; | ||
935 | 197 | ||
936 | if (ethtool_cmd_speed(&ecmd) != SPEED_100) | 198 | int asix_mdio_read(struct net_device *netdev, int phy_id, int loc); |
937 | mode &= ~AX_MEDIUM_PS; | 199 | void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val); |
938 | 200 | ||
939 | if (ecmd.duplex != DUPLEX_FULL) | 201 | void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); |
940 | mode &= ~AX_MEDIUM_FD; | 202 | int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); |
941 | 203 | ||
942 | netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | 204 | int asix_get_eeprom_len(struct net_device *net); |
943 | ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | 205 | int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, |
944 | 206 | u8 *data); | |
945 | asix_write_medium_mode(dev, mode); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int ax88772_reset(struct usbnet *dev) | ||
951 | { | ||
952 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
953 | int ret, embd_phy; | ||
954 | u16 rx_ctl; | ||
955 | |||
956 | ret = asix_write_gpio(dev, | ||
957 | AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); | ||
958 | if (ret < 0) | ||
959 | goto out; | ||
960 | |||
961 | embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); | ||
962 | |||
963 | ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | ||
964 | if (ret < 0) { | ||
965 | dbg("Select PHY #1 failed: %d", ret); | ||
966 | goto out; | ||
967 | } | ||
968 | |||
969 | ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); | ||
970 | if (ret < 0) | ||
971 | goto out; | ||
972 | |||
973 | msleep(150); | ||
974 | |||
975 | ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); | ||
976 | if (ret < 0) | ||
977 | goto out; | ||
978 | |||
979 | msleep(150); | ||
980 | |||
981 | if (embd_phy) { | ||
982 | ret = asix_sw_reset(dev, AX_SWRESET_IPRL); | ||
983 | if (ret < 0) | ||
984 | goto out; | ||
985 | } else { | ||
986 | ret = asix_sw_reset(dev, AX_SWRESET_PRTE); | ||
987 | if (ret < 0) | ||
988 | goto out; | ||
989 | } | ||
990 | |||
991 | msleep(150); | ||
992 | rx_ctl = asix_read_rx_ctl(dev); | ||
993 | dbg("RX_CTL is 0x%04x after software reset", rx_ctl); | ||
994 | ret = asix_write_rx_ctl(dev, 0x0000); | ||
995 | if (ret < 0) | ||
996 | goto out; | ||
997 | |||
998 | rx_ctl = asix_read_rx_ctl(dev); | ||
999 | dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); | ||
1000 | |||
1001 | ret = asix_sw_reset(dev, AX_SWRESET_PRL); | ||
1002 | if (ret < 0) | ||
1003 | goto out; | ||
1004 | |||
1005 | msleep(150); | ||
1006 | |||
1007 | ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); | ||
1008 | if (ret < 0) | ||
1009 | goto out; | ||
1010 | |||
1011 | msleep(150); | ||
1012 | |||
1013 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
1014 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
1015 | ADVERTISE_ALL | ADVERTISE_CSMA); | ||
1016 | mii_nway_restart(&dev->mii); | ||
1017 | |||
1018 | ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); | ||
1019 | if (ret < 0) | ||
1020 | goto out; | ||
1021 | |||
1022 | ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, | ||
1023 | AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, | ||
1024 | AX88772_IPG2_DEFAULT, 0, NULL); | ||
1025 | if (ret < 0) { | ||
1026 | dbg("Write IPG,IPG1,IPG2 failed: %d", ret); | ||
1027 | goto out; | ||
1028 | } | ||
1029 | |||
1030 | /* Rewrite MAC address */ | ||
1031 | memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | ||
1032 | ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
1033 | data->mac_addr); | ||
1034 | if (ret < 0) | ||
1035 | goto out; | ||
1036 | |||
1037 | /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | ||
1038 | ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | ||
1039 | if (ret < 0) | ||
1040 | goto out; | ||
1041 | |||
1042 | rx_ctl = asix_read_rx_ctl(dev); | ||
1043 | dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); | ||
1044 | |||
1045 | rx_ctl = asix_read_medium_status(dev); | ||
1046 | dbg("Medium Status is 0x%04x after all initializations", rx_ctl); | ||
1047 | |||
1048 | return 0; | ||
1049 | |||
1050 | out: | ||
1051 | return ret; | ||
1052 | |||
1053 | } | ||
1054 | |||
1055 | static const struct net_device_ops ax88772_netdev_ops = { | ||
1056 | .ndo_open = usbnet_open, | ||
1057 | .ndo_stop = usbnet_stop, | ||
1058 | .ndo_start_xmit = usbnet_start_xmit, | ||
1059 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
1060 | .ndo_change_mtu = usbnet_change_mtu, | ||
1061 | .ndo_set_mac_address = asix_set_mac_address, | ||
1062 | .ndo_validate_addr = eth_validate_addr, | ||
1063 | .ndo_do_ioctl = asix_ioctl, | ||
1064 | .ndo_set_rx_mode = asix_set_multicast, | ||
1065 | }; | ||
1066 | |||
1067 | static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | ||
1068 | { | ||
1069 | int ret, embd_phy; | ||
1070 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1071 | u8 buf[ETH_ALEN]; | ||
1072 | u32 phyid; | ||
1073 | |||
1074 | data->eeprom_len = AX88772_EEPROM_LEN; | ||
1075 | |||
1076 | usbnet_get_endpoints(dev,intf); | ||
1077 | |||
1078 | /* Get the MAC address */ | ||
1079 | ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | ||
1080 | if (ret < 0) { | ||
1081 | dbg("Failed to read MAC address: %d", ret); | ||
1082 | return ret; | ||
1083 | } | ||
1084 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
1085 | |||
1086 | /* Initialize MII structure */ | ||
1087 | dev->mii.dev = dev->net; | ||
1088 | dev->mii.mdio_read = asix_mdio_read; | ||
1089 | dev->mii.mdio_write = asix_mdio_write; | ||
1090 | dev->mii.phy_id_mask = 0x1f; | ||
1091 | dev->mii.reg_num_mask = 0x1f; | ||
1092 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
1093 | |||
1094 | dev->net->netdev_ops = &ax88772_netdev_ops; | ||
1095 | dev->net->ethtool_ops = &ax88772_ethtool_ops; | ||
1096 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
1097 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
1098 | |||
1099 | embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); | ||
1100 | |||
1101 | /* Reset the PHY to normal operation mode */ | ||
1102 | ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | ||
1103 | if (ret < 0) { | ||
1104 | dbg("Select PHY #1 failed: %d", ret); | ||
1105 | return ret; | ||
1106 | } | ||
1107 | |||
1108 | ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); | ||
1109 | if (ret < 0) | ||
1110 | return ret; | ||
1111 | |||
1112 | msleep(150); | ||
1113 | |||
1114 | ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); | ||
1115 | if (ret < 0) | ||
1116 | return ret; | ||
1117 | |||
1118 | msleep(150); | ||
1119 | |||
1120 | ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); | ||
1121 | |||
1122 | /* Read PHYID register *AFTER* the PHY was reset properly */ | ||
1123 | phyid = asix_get_phyid(dev); | ||
1124 | dbg("PHYID=0x%08x", phyid); | ||
1125 | |||
1126 | /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | ||
1127 | if (dev->driver_info->flags & FLAG_FRAMING_AX) { | ||
1128 | /* hard_mtu is still the default - the device does not support | ||
1129 | jumbo eth frames */ | ||
1130 | dev->rx_urb_size = 2048; | ||
1131 | } | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static const struct ethtool_ops ax88178_ethtool_ops = { | ||
1137 | .get_drvinfo = asix_get_drvinfo, | ||
1138 | .get_link = asix_get_link, | ||
1139 | .get_msglevel = usbnet_get_msglevel, | ||
1140 | .set_msglevel = usbnet_set_msglevel, | ||
1141 | .get_wol = asix_get_wol, | ||
1142 | .set_wol = asix_set_wol, | ||
1143 | .get_eeprom_len = asix_get_eeprom_len, | ||
1144 | .get_eeprom = asix_get_eeprom, | ||
1145 | .get_settings = usbnet_get_settings, | ||
1146 | .set_settings = usbnet_set_settings, | ||
1147 | .nway_reset = usbnet_nway_reset, | ||
1148 | }; | ||
1149 | |||
1150 | static int marvell_phy_init(struct usbnet *dev) | ||
1151 | { | ||
1152 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1153 | u16 reg; | ||
1154 | |||
1155 | netdev_dbg(dev->net, "marvell_phy_init()\n"); | ||
1156 | |||
1157 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); | ||
1158 | netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); | ||
1159 | |||
1160 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, | ||
1161 | MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); | ||
1162 | |||
1163 | if (data->ledmode) { | ||
1164 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, | ||
1165 | MII_MARVELL_LED_CTRL); | ||
1166 | netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); | ||
1167 | |||
1168 | reg &= 0xf8ff; | ||
1169 | reg |= (1 + 0x0100); | ||
1170 | asix_mdio_write(dev->net, dev->mii.phy_id, | ||
1171 | MII_MARVELL_LED_CTRL, reg); | ||
1172 | |||
1173 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, | ||
1174 | MII_MARVELL_LED_CTRL); | ||
1175 | netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); | ||
1176 | reg &= 0xfc0f; | ||
1177 | } | ||
1178 | |||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1182 | static int rtl8211cl_phy_init(struct usbnet *dev) | ||
1183 | { | ||
1184 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1185 | |||
1186 | netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); | ||
1187 | |||
1188 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); | ||
1189 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); | ||
1190 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, | ||
1191 | asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); | ||
1192 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); | ||
1193 | |||
1194 | if (data->ledmode == 12) { | ||
1195 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); | ||
1196 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); | ||
1197 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); | ||
1198 | } | ||
1199 | |||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | static int marvell_led_status(struct usbnet *dev, u16 speed) | ||
1204 | { | ||
1205 | u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); | ||
1206 | |||
1207 | netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); | ||
1208 | |||
1209 | /* Clear out the center LED bits - 0x03F0 */ | ||
1210 | reg &= 0xfc0f; | ||
1211 | |||
1212 | switch (speed) { | ||
1213 | case SPEED_1000: | ||
1214 | reg |= 0x03e0; | ||
1215 | break; | ||
1216 | case SPEED_100: | ||
1217 | reg |= 0x03b0; | ||
1218 | break; | ||
1219 | default: | ||
1220 | reg |= 0x02f0; | ||
1221 | } | ||
1222 | |||
1223 | netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); | ||
1224 | asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); | ||
1225 | |||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static int ax88178_reset(struct usbnet *dev) | ||
1230 | { | ||
1231 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1232 | int ret; | ||
1233 | __le16 eeprom; | ||
1234 | u8 status; | ||
1235 | int gpio0 = 0; | ||
1236 | u32 phyid; | ||
1237 | |||
1238 | asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); | ||
1239 | dbg("GPIO Status: 0x%04x", status); | ||
1240 | |||
1241 | asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); | ||
1242 | asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); | ||
1243 | asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); | ||
1244 | |||
1245 | dbg("EEPROM index 0x17 is 0x%04x", eeprom); | ||
1246 | |||
1247 | if (eeprom == cpu_to_le16(0xffff)) { | ||
1248 | data->phymode = PHY_MODE_MARVELL; | ||
1249 | data->ledmode = 0; | ||
1250 | gpio0 = 1; | ||
1251 | } else { | ||
1252 | data->phymode = le16_to_cpu(eeprom) & 0x7F; | ||
1253 | data->ledmode = le16_to_cpu(eeprom) >> 8; | ||
1254 | gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; | ||
1255 | } | ||
1256 | dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); | ||
1257 | |||
1258 | /* Power up external GigaPHY through AX88178 GPIO pin */ | ||
1259 | asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); | ||
1260 | if ((le16_to_cpu(eeprom) >> 8) != 1) { | ||
1261 | asix_write_gpio(dev, 0x003c, 30); | ||
1262 | asix_write_gpio(dev, 0x001c, 300); | ||
1263 | asix_write_gpio(dev, 0x003c, 30); | ||
1264 | } else { | ||
1265 | dbg("gpio phymode == 1 path"); | ||
1266 | asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); | ||
1267 | asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); | ||
1268 | } | ||
1269 | |||
1270 | /* Read PHYID register *AFTER* powering up PHY */ | ||
1271 | phyid = asix_get_phyid(dev); | ||
1272 | dbg("PHYID=0x%08x", phyid); | ||
1273 | |||
1274 | /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ | ||
1275 | asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); | ||
1276 | |||
1277 | asix_sw_reset(dev, 0); | ||
1278 | msleep(150); | ||
1279 | |||
1280 | asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); | ||
1281 | msleep(150); | ||
1282 | |||
1283 | asix_write_rx_ctl(dev, 0); | ||
1284 | |||
1285 | if (data->phymode == PHY_MODE_MARVELL) { | ||
1286 | marvell_phy_init(dev); | ||
1287 | msleep(60); | ||
1288 | } else if (data->phymode == PHY_MODE_RTL8211CL) | ||
1289 | rtl8211cl_phy_init(dev); | ||
1290 | |||
1291 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, | ||
1292 | BMCR_RESET | BMCR_ANENABLE); | ||
1293 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
1294 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | ||
1295 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, | ||
1296 | ADVERTISE_1000FULL); | ||
1297 | |||
1298 | mii_nway_restart(&dev->mii); | ||
1299 | |||
1300 | ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); | ||
1301 | if (ret < 0) | ||
1302 | return ret; | ||
1303 | |||
1304 | /* Rewrite MAC address */ | ||
1305 | memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | ||
1306 | ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
1307 | data->mac_addr); | ||
1308 | if (ret < 0) | ||
1309 | return ret; | ||
1310 | |||
1311 | ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | ||
1312 | if (ret < 0) | ||
1313 | return ret; | ||
1314 | |||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1318 | static int ax88178_link_reset(struct usbnet *dev) | ||
1319 | { | ||
1320 | u16 mode; | ||
1321 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | ||
1322 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1323 | u32 speed; | ||
1324 | |||
1325 | netdev_dbg(dev->net, "ax88178_link_reset()\n"); | ||
1326 | |||
1327 | mii_check_media(&dev->mii, 1, 1); | ||
1328 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
1329 | mode = AX88178_MEDIUM_DEFAULT; | ||
1330 | speed = ethtool_cmd_speed(&ecmd); | ||
1331 | |||
1332 | if (speed == SPEED_1000) | ||
1333 | mode |= AX_MEDIUM_GM; | ||
1334 | else if (speed == SPEED_100) | ||
1335 | mode |= AX_MEDIUM_PS; | ||
1336 | else | ||
1337 | mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); | ||
1338 | |||
1339 | mode |= AX_MEDIUM_ENCK; | ||
1340 | |||
1341 | if (ecmd.duplex == DUPLEX_FULL) | ||
1342 | mode |= AX_MEDIUM_FD; | ||
1343 | else | ||
1344 | mode &= ~AX_MEDIUM_FD; | ||
1345 | |||
1346 | netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | ||
1347 | speed, ecmd.duplex, mode); | ||
1348 | |||
1349 | asix_write_medium_mode(dev, mode); | ||
1350 | |||
1351 | if (data->phymode == PHY_MODE_MARVELL && data->ledmode) | ||
1352 | marvell_led_status(dev, speed); | ||
1353 | |||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
1357 | static void ax88178_set_mfb(struct usbnet *dev) | ||
1358 | { | ||
1359 | u16 mfb = AX_RX_CTL_MFB_16384; | ||
1360 | u16 rxctl; | ||
1361 | u16 medium; | ||
1362 | int old_rx_urb_size = dev->rx_urb_size; | ||
1363 | |||
1364 | if (dev->hard_mtu < 2048) { | ||
1365 | dev->rx_urb_size = 2048; | ||
1366 | mfb = AX_RX_CTL_MFB_2048; | ||
1367 | } else if (dev->hard_mtu < 4096) { | ||
1368 | dev->rx_urb_size = 4096; | ||
1369 | mfb = AX_RX_CTL_MFB_4096; | ||
1370 | } else if (dev->hard_mtu < 8192) { | ||
1371 | dev->rx_urb_size = 8192; | ||
1372 | mfb = AX_RX_CTL_MFB_8192; | ||
1373 | } else if (dev->hard_mtu < 16384) { | ||
1374 | dev->rx_urb_size = 16384; | ||
1375 | mfb = AX_RX_CTL_MFB_16384; | ||
1376 | } | ||
1377 | |||
1378 | rxctl = asix_read_rx_ctl(dev); | ||
1379 | asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); | ||
1380 | |||
1381 | medium = asix_read_medium_status(dev); | ||
1382 | if (dev->net->mtu > 1500) | ||
1383 | medium |= AX_MEDIUM_JFE; | ||
1384 | else | ||
1385 | medium &= ~AX_MEDIUM_JFE; | ||
1386 | asix_write_medium_mode(dev, medium); | ||
1387 | |||
1388 | if (dev->rx_urb_size > old_rx_urb_size) | ||
1389 | usbnet_unlink_rx_urbs(dev); | ||
1390 | } | ||
1391 | |||
1392 | static int ax88178_change_mtu(struct net_device *net, int new_mtu) | ||
1393 | { | ||
1394 | struct usbnet *dev = netdev_priv(net); | ||
1395 | int ll_mtu = new_mtu + net->hard_header_len + 4; | ||
1396 | |||
1397 | netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); | ||
1398 | |||
1399 | if (new_mtu <= 0 || ll_mtu > 16384) | ||
1400 | return -EINVAL; | ||
1401 | |||
1402 | if ((ll_mtu % dev->maxpacket) == 0) | ||
1403 | return -EDOM; | ||
1404 | |||
1405 | net->mtu = new_mtu; | ||
1406 | dev->hard_mtu = net->mtu + net->hard_header_len; | ||
1407 | ax88178_set_mfb(dev); | ||
1408 | |||
1409 | return 0; | ||
1410 | } | ||
1411 | |||
1412 | static const struct net_device_ops ax88178_netdev_ops = { | ||
1413 | .ndo_open = usbnet_open, | ||
1414 | .ndo_stop = usbnet_stop, | ||
1415 | .ndo_start_xmit = usbnet_start_xmit, | ||
1416 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
1417 | .ndo_set_mac_address = asix_set_mac_address, | ||
1418 | .ndo_validate_addr = eth_validate_addr, | ||
1419 | .ndo_set_rx_mode = asix_set_multicast, | ||
1420 | .ndo_do_ioctl = asix_ioctl, | ||
1421 | .ndo_change_mtu = ax88178_change_mtu, | ||
1422 | }; | ||
1423 | |||
1424 | static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) | ||
1425 | { | ||
1426 | int ret; | ||
1427 | u8 buf[ETH_ALEN]; | ||
1428 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1429 | |||
1430 | data->eeprom_len = AX88772_EEPROM_LEN; | ||
1431 | |||
1432 | usbnet_get_endpoints(dev,intf); | ||
1433 | |||
1434 | /* Get the MAC address */ | ||
1435 | ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | ||
1436 | if (ret < 0) { | ||
1437 | dbg("Failed to read MAC address: %d", ret); | ||
1438 | return ret; | ||
1439 | } | ||
1440 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
1441 | |||
1442 | /* Initialize MII structure */ | ||
1443 | dev->mii.dev = dev->net; | ||
1444 | dev->mii.mdio_read = asix_mdio_read; | ||
1445 | dev->mii.mdio_write = asix_mdio_write; | ||
1446 | dev->mii.phy_id_mask = 0x1f; | ||
1447 | dev->mii.reg_num_mask = 0xff; | ||
1448 | dev->mii.supports_gmii = 1; | ||
1449 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
1450 | |||
1451 | dev->net->netdev_ops = &ax88178_netdev_ops; | ||
1452 | dev->net->ethtool_ops = &ax88178_ethtool_ops; | ||
1453 | |||
1454 | /* Blink LEDS so users know driver saw dongle */ | ||
1455 | asix_sw_reset(dev, 0); | ||
1456 | msleep(150); | ||
1457 | |||
1458 | asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); | ||
1459 | msleep(150); | ||
1460 | |||
1461 | /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | ||
1462 | if (dev->driver_info->flags & FLAG_FRAMING_AX) { | ||
1463 | /* hard_mtu is still the default - the device does not support | ||
1464 | jumbo eth frames */ | ||
1465 | dev->rx_urb_size = 2048; | ||
1466 | } | ||
1467 | |||
1468 | return 0; | ||
1469 | } | ||
1470 | |||
1471 | static const struct driver_info ax8817x_info = { | ||
1472 | .description = "ASIX AX8817x USB 2.0 Ethernet", | ||
1473 | .bind = ax88172_bind, | ||
1474 | .status = asix_status, | ||
1475 | .link_reset = ax88172_link_reset, | ||
1476 | .reset = ax88172_link_reset, | ||
1477 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1478 | .data = 0x00130103, | ||
1479 | }; | ||
1480 | |||
1481 | static const struct driver_info dlink_dub_e100_info = { | ||
1482 | .description = "DLink DUB-E100 USB Ethernet", | ||
1483 | .bind = ax88172_bind, | ||
1484 | .status = asix_status, | ||
1485 | .link_reset = ax88172_link_reset, | ||
1486 | .reset = ax88172_link_reset, | ||
1487 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1488 | .data = 0x009f9d9f, | ||
1489 | }; | ||
1490 | |||
1491 | static const struct driver_info netgear_fa120_info = { | ||
1492 | .description = "Netgear FA-120 USB Ethernet", | ||
1493 | .bind = ax88172_bind, | ||
1494 | .status = asix_status, | ||
1495 | .link_reset = ax88172_link_reset, | ||
1496 | .reset = ax88172_link_reset, | ||
1497 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1498 | .data = 0x00130103, | ||
1499 | }; | ||
1500 | |||
1501 | static const struct driver_info hawking_uf200_info = { | ||
1502 | .description = "Hawking UF200 USB Ethernet", | ||
1503 | .bind = ax88172_bind, | ||
1504 | .status = asix_status, | ||
1505 | .link_reset = ax88172_link_reset, | ||
1506 | .reset = ax88172_link_reset, | ||
1507 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1508 | .data = 0x001f1d1f, | ||
1509 | }; | ||
1510 | |||
1511 | static const struct driver_info ax88772_info = { | ||
1512 | .description = "ASIX AX88772 USB 2.0 Ethernet", | ||
1513 | .bind = ax88772_bind, | ||
1514 | .status = asix_status, | ||
1515 | .link_reset = ax88772_link_reset, | ||
1516 | .reset = ax88772_reset, | ||
1517 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, | ||
1518 | .rx_fixup = asix_rx_fixup, | ||
1519 | .tx_fixup = asix_tx_fixup, | ||
1520 | }; | ||
1521 | |||
1522 | static const struct driver_info ax88178_info = { | ||
1523 | .description = "ASIX AX88178 USB 2.0 Ethernet", | ||
1524 | .bind = ax88178_bind, | ||
1525 | .status = asix_status, | ||
1526 | .link_reset = ax88178_link_reset, | ||
1527 | .reset = ax88178_reset, | ||
1528 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, | ||
1529 | .rx_fixup = asix_rx_fixup, | ||
1530 | .tx_fixup = asix_tx_fixup, | ||
1531 | }; | ||
1532 | |||
1533 | static const struct usb_device_id products [] = { | ||
1534 | { | ||
1535 | // Linksys USB200M | ||
1536 | USB_DEVICE (0x077b, 0x2226), | ||
1537 | .driver_info = (unsigned long) &ax8817x_info, | ||
1538 | }, { | ||
1539 | // Netgear FA120 | ||
1540 | USB_DEVICE (0x0846, 0x1040), | ||
1541 | .driver_info = (unsigned long) &netgear_fa120_info, | ||
1542 | }, { | ||
1543 | // DLink DUB-E100 | ||
1544 | USB_DEVICE (0x2001, 0x1a00), | ||
1545 | .driver_info = (unsigned long) &dlink_dub_e100_info, | ||
1546 | }, { | ||
1547 | // Intellinet, ST Lab USB Ethernet | ||
1548 | USB_DEVICE (0x0b95, 0x1720), | ||
1549 | .driver_info = (unsigned long) &ax8817x_info, | ||
1550 | }, { | ||
1551 | // Hawking UF200, TrendNet TU2-ET100 | ||
1552 | USB_DEVICE (0x07b8, 0x420a), | ||
1553 | .driver_info = (unsigned long) &hawking_uf200_info, | ||
1554 | }, { | ||
1555 | // Billionton Systems, USB2AR | ||
1556 | USB_DEVICE (0x08dd, 0x90ff), | ||
1557 | .driver_info = (unsigned long) &ax8817x_info, | ||
1558 | }, { | ||
1559 | // ATEN UC210T | ||
1560 | USB_DEVICE (0x0557, 0x2009), | ||
1561 | .driver_info = (unsigned long) &ax8817x_info, | ||
1562 | }, { | ||
1563 | // Buffalo LUA-U2-KTX | ||
1564 | USB_DEVICE (0x0411, 0x003d), | ||
1565 | .driver_info = (unsigned long) &ax8817x_info, | ||
1566 | }, { | ||
1567 | // Buffalo LUA-U2-GT 10/100/1000 | ||
1568 | USB_DEVICE (0x0411, 0x006e), | ||
1569 | .driver_info = (unsigned long) &ax88178_info, | ||
1570 | }, { | ||
1571 | // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" | ||
1572 | USB_DEVICE (0x6189, 0x182d), | ||
1573 | .driver_info = (unsigned long) &ax8817x_info, | ||
1574 | }, { | ||
1575 | // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" | ||
1576 | USB_DEVICE (0x0df6, 0x0056), | ||
1577 | .driver_info = (unsigned long) &ax88178_info, | ||
1578 | }, { | ||
1579 | // corega FEther USB2-TX | ||
1580 | USB_DEVICE (0x07aa, 0x0017), | ||
1581 | .driver_info = (unsigned long) &ax8817x_info, | ||
1582 | }, { | ||
1583 | // Surecom EP-1427X-2 | ||
1584 | USB_DEVICE (0x1189, 0x0893), | ||
1585 | .driver_info = (unsigned long) &ax8817x_info, | ||
1586 | }, { | ||
1587 | // goodway corp usb gwusb2e | ||
1588 | USB_DEVICE (0x1631, 0x6200), | ||
1589 | .driver_info = (unsigned long) &ax8817x_info, | ||
1590 | }, { | ||
1591 | // JVC MP-PRX1 Port Replicator | ||
1592 | USB_DEVICE (0x04f1, 0x3008), | ||
1593 | .driver_info = (unsigned long) &ax8817x_info, | ||
1594 | }, { | ||
1595 | // ASIX AX88772B 10/100 | ||
1596 | USB_DEVICE (0x0b95, 0x772b), | ||
1597 | .driver_info = (unsigned long) &ax88772_info, | ||
1598 | }, { | ||
1599 | // ASIX AX88772 10/100 | ||
1600 | USB_DEVICE (0x0b95, 0x7720), | ||
1601 | .driver_info = (unsigned long) &ax88772_info, | ||
1602 | }, { | ||
1603 | // ASIX AX88178 10/100/1000 | ||
1604 | USB_DEVICE (0x0b95, 0x1780), | ||
1605 | .driver_info = (unsigned long) &ax88178_info, | ||
1606 | }, { | ||
1607 | // Logitec LAN-GTJ/U2A | ||
1608 | USB_DEVICE (0x0789, 0x0160), | ||
1609 | .driver_info = (unsigned long) &ax88178_info, | ||
1610 | }, { | ||
1611 | // Linksys USB200M Rev 2 | ||
1612 | USB_DEVICE (0x13b1, 0x0018), | ||
1613 | .driver_info = (unsigned long) &ax88772_info, | ||
1614 | }, { | ||
1615 | // 0Q0 cable ethernet | ||
1616 | USB_DEVICE (0x1557, 0x7720), | ||
1617 | .driver_info = (unsigned long) &ax88772_info, | ||
1618 | }, { | ||
1619 | // DLink DUB-E100 H/W Ver B1 | ||
1620 | USB_DEVICE (0x07d1, 0x3c05), | ||
1621 | .driver_info = (unsigned long) &ax88772_info, | ||
1622 | }, { | ||
1623 | // DLink DUB-E100 H/W Ver B1 Alternate | ||
1624 | USB_DEVICE (0x2001, 0x3c05), | ||
1625 | .driver_info = (unsigned long) &ax88772_info, | ||
1626 | }, { | ||
1627 | // Linksys USB1000 | ||
1628 | USB_DEVICE (0x1737, 0x0039), | ||
1629 | .driver_info = (unsigned long) &ax88178_info, | ||
1630 | }, { | ||
1631 | // IO-DATA ETG-US2 | ||
1632 | USB_DEVICE (0x04bb, 0x0930), | ||
1633 | .driver_info = (unsigned long) &ax88178_info, | ||
1634 | }, { | ||
1635 | // Belkin F5D5055 | ||
1636 | USB_DEVICE(0x050d, 0x5055), | ||
1637 | .driver_info = (unsigned long) &ax88178_info, | ||
1638 | }, { | ||
1639 | // Apple USB Ethernet Adapter | ||
1640 | USB_DEVICE(0x05ac, 0x1402), | ||
1641 | .driver_info = (unsigned long) &ax88772_info, | ||
1642 | }, { | ||
1643 | // Cables-to-Go USB Ethernet Adapter | ||
1644 | USB_DEVICE(0x0b95, 0x772a), | ||
1645 | .driver_info = (unsigned long) &ax88772_info, | ||
1646 | }, { | ||
1647 | // ABOCOM for pci | ||
1648 | USB_DEVICE(0x14ea, 0xab11), | ||
1649 | .driver_info = (unsigned long) &ax88178_info, | ||
1650 | }, { | ||
1651 | // ASIX 88772a | ||
1652 | USB_DEVICE(0x0db0, 0xa877), | ||
1653 | .driver_info = (unsigned long) &ax88772_info, | ||
1654 | }, { | ||
1655 | // Asus USB Ethernet Adapter | ||
1656 | USB_DEVICE (0x0b95, 0x7e2b), | ||
1657 | .driver_info = (unsigned long) &ax88772_info, | ||
1658 | }, | ||
1659 | { }, // END | ||
1660 | }; | ||
1661 | MODULE_DEVICE_TABLE(usb, products); | ||
1662 | |||
1663 | static struct usb_driver asix_driver = { | ||
1664 | .name = DRIVER_NAME, | ||
1665 | .id_table = products, | ||
1666 | .probe = usbnet_probe, | ||
1667 | .suspend = usbnet_suspend, | ||
1668 | .resume = usbnet_resume, | ||
1669 | .disconnect = usbnet_disconnect, | ||
1670 | .supports_autosuspend = 1, | ||
1671 | .disable_hub_initiated_lpm = 1, | ||
1672 | }; | ||
1673 | 207 | ||
1674 | module_usb_driver(asix_driver); | 208 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info); |
1675 | 209 | ||
1676 | MODULE_AUTHOR("David Hollis"); | 210 | int asix_set_mac_address(struct net_device *net, void *p); |
1677 | MODULE_VERSION(DRIVER_VERSION); | ||
1678 | MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); | ||
1679 | MODULE_LICENSE("GPL"); | ||
1680 | 211 | ||
212 | #endif /* _ASIX_H */ | ||
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 6564c32d3af..3c1429a25ca 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c | |||
@@ -20,171 +20,10 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | // #define DEBUG // error path messages, extra info | 23 | #include "asix.h" |
24 | // #define VERBOSE // more; success messages | 24 | |
25 | 25 | int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
26 | #include <linux/module.h> | 26 | u16 size, void *data) |
27 | #include <linux/kmod.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/usb.h> | ||
35 | #include <linux/crc32.h> | ||
36 | #include <linux/usb/usbnet.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/if_vlan.h> | ||
39 | |||
40 | #define DRIVER_VERSION "22-Dec-2011" | ||
41 | #define DRIVER_NAME "asix" | ||
42 | |||
43 | /* ASIX AX8817X based USB 2.0 Ethernet Devices */ | ||
44 | |||
45 | #define AX_CMD_SET_SW_MII 0x06 | ||
46 | #define AX_CMD_READ_MII_REG 0x07 | ||
47 | #define AX_CMD_WRITE_MII_REG 0x08 | ||
48 | #define AX_CMD_SET_HW_MII 0x0a | ||
49 | #define AX_CMD_READ_EEPROM 0x0b | ||
50 | #define AX_CMD_WRITE_EEPROM 0x0c | ||
51 | #define AX_CMD_WRITE_ENABLE 0x0d | ||
52 | #define AX_CMD_WRITE_DISABLE 0x0e | ||
53 | #define AX_CMD_READ_RX_CTL 0x0f | ||
54 | #define AX_CMD_WRITE_RX_CTL 0x10 | ||
55 | #define AX_CMD_READ_IPG012 0x11 | ||
56 | #define AX_CMD_WRITE_IPG0 0x12 | ||
57 | #define AX_CMD_WRITE_IPG1 0x13 | ||
58 | #define AX_CMD_READ_NODE_ID 0x13 | ||
59 | #define AX_CMD_WRITE_NODE_ID 0x14 | ||
60 | #define AX_CMD_WRITE_IPG2 0x14 | ||
61 | #define AX_CMD_WRITE_MULTI_FILTER 0x16 | ||
62 | #define AX88172_CMD_READ_NODE_ID 0x17 | ||
63 | #define AX_CMD_READ_PHY_ID 0x19 | ||
64 | #define AX_CMD_READ_MEDIUM_STATUS 0x1a | ||
65 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b | ||
66 | #define AX_CMD_READ_MONITOR_MODE 0x1c | ||
67 | #define AX_CMD_WRITE_MONITOR_MODE 0x1d | ||
68 | #define AX_CMD_READ_GPIOS 0x1e | ||
69 | #define AX_CMD_WRITE_GPIOS 0x1f | ||
70 | #define AX_CMD_SW_RESET 0x20 | ||
71 | #define AX_CMD_SW_PHY_STATUS 0x21 | ||
72 | #define AX_CMD_SW_PHY_SELECT 0x22 | ||
73 | |||
74 | #define AX_MONITOR_MODE 0x01 | ||
75 | #define AX_MONITOR_LINK 0x02 | ||
76 | #define AX_MONITOR_MAGIC 0x04 | ||
77 | #define AX_MONITOR_HSFS 0x10 | ||
78 | |||
79 | /* AX88172 Medium Status Register values */ | ||
80 | #define AX88172_MEDIUM_FD 0x02 | ||
81 | #define AX88172_MEDIUM_TX 0x04 | ||
82 | #define AX88172_MEDIUM_FC 0x10 | ||
83 | #define AX88172_MEDIUM_DEFAULT \ | ||
84 | ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) | ||
85 | |||
86 | #define AX_MCAST_FILTER_SIZE 8 | ||
87 | #define AX_MAX_MCAST 64 | ||
88 | |||
89 | #define AX_SWRESET_CLEAR 0x00 | ||
90 | #define AX_SWRESET_RR 0x01 | ||
91 | #define AX_SWRESET_RT 0x02 | ||
92 | #define AX_SWRESET_PRTE 0x04 | ||
93 | #define AX_SWRESET_PRL 0x08 | ||
94 | #define AX_SWRESET_BZ 0x10 | ||
95 | #define AX_SWRESET_IPRL 0x20 | ||
96 | #define AX_SWRESET_IPPD 0x40 | ||
97 | |||
98 | #define AX88772_IPG0_DEFAULT 0x15 | ||
99 | #define AX88772_IPG1_DEFAULT 0x0c | ||
100 | #define AX88772_IPG2_DEFAULT 0x12 | ||
101 | |||
102 | /* AX88772 & AX88178 Medium Mode Register */ | ||
103 | #define AX_MEDIUM_PF 0x0080 | ||
104 | #define AX_MEDIUM_JFE 0x0040 | ||
105 | #define AX_MEDIUM_TFC 0x0020 | ||
106 | #define AX_MEDIUM_RFC 0x0010 | ||
107 | #define AX_MEDIUM_ENCK 0x0008 | ||
108 | #define AX_MEDIUM_AC 0x0004 | ||
109 | #define AX_MEDIUM_FD 0x0002 | ||
110 | #define AX_MEDIUM_GM 0x0001 | ||
111 | #define AX_MEDIUM_SM 0x1000 | ||
112 | #define AX_MEDIUM_SBP 0x0800 | ||
113 | #define AX_MEDIUM_PS 0x0200 | ||
114 | #define AX_MEDIUM_RE 0x0100 | ||
115 | |||
116 | #define AX88178_MEDIUM_DEFAULT \ | ||
117 | (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ | ||
118 | AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ | ||
119 | AX_MEDIUM_RE) | ||
120 | |||
121 | #define AX88772_MEDIUM_DEFAULT \ | ||
122 | (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ | ||
123 | AX_MEDIUM_TFC | AX_MEDIUM_PS | \ | ||
124 | AX_MEDIUM_AC | AX_MEDIUM_RE) | ||
125 | |||
126 | /* AX88772 & AX88178 RX_CTL values */ | ||
127 | #define AX_RX_CTL_SO 0x0080 | ||
128 | #define AX_RX_CTL_AP 0x0020 | ||
129 | #define AX_RX_CTL_AM 0x0010 | ||
130 | #define AX_RX_CTL_AB 0x0008 | ||
131 | #define AX_RX_CTL_SEP 0x0004 | ||
132 | #define AX_RX_CTL_AMALL 0x0002 | ||
133 | #define AX_RX_CTL_PRO 0x0001 | ||
134 | #define AX_RX_CTL_MFB_2048 0x0000 | ||
135 | #define AX_RX_CTL_MFB_4096 0x0100 | ||
136 | #define AX_RX_CTL_MFB_8192 0x0200 | ||
137 | #define AX_RX_CTL_MFB_16384 0x0300 | ||
138 | |||
139 | #define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) | ||
140 | |||
141 | /* GPIO 0 .. 2 toggles */ | ||
142 | #define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ | ||
143 | #define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ | ||
144 | #define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ | ||
145 | #define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ | ||
146 | #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ | ||
147 | #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ | ||
148 | #define AX_GPIO_RESERVED 0x40 /* Reserved */ | ||
149 | #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ | ||
150 | |||
151 | #define AX_EEPROM_MAGIC 0xdeadbeef | ||
152 | #define AX88172_EEPROM_LEN 0x40 | ||
153 | #define AX88772_EEPROM_LEN 0xff | ||
154 | |||
155 | #define PHY_MODE_MARVELL 0x0000 | ||
156 | #define MII_MARVELL_LED_CTRL 0x0018 | ||
157 | #define MII_MARVELL_STATUS 0x001b | ||
158 | #define MII_MARVELL_CTRL 0x0014 | ||
159 | |||
160 | #define MARVELL_LED_MANUAL 0x0019 | ||
161 | |||
162 | #define MARVELL_STATUS_HWCFG 0x0004 | ||
163 | |||
164 | #define MARVELL_CTRL_TXDELAY 0x0002 | ||
165 | #define MARVELL_CTRL_RXDELAY 0x0080 | ||
166 | |||
167 | #define PHY_MODE_RTL8211CL 0x000C | ||
168 | |||
169 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | ||
170 | struct asix_data { | ||
171 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; | ||
172 | u8 mac_addr[ETH_ALEN]; | ||
173 | u8 phymode; | ||
174 | u8 ledmode; | ||
175 | u8 eeprom_len; | ||
176 | }; | ||
177 | |||
178 | struct ax88172_int_data { | ||
179 | __le16 res1; | ||
180 | u8 link; | ||
181 | __le16 res2; | ||
182 | u8 status; | ||
183 | __le16 res3; | ||
184 | } __packed; | ||
185 | |||
186 | static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
187 | u16 size, void *data) | ||
188 | { | 27 | { |
189 | void *buf; | 28 | void *buf; |
190 | int err = -ENOMEM; | 29 | int err = -ENOMEM; |
@@ -216,8 +55,8 @@ out: | |||
216 | return err; | 55 | return err; |
217 | } | 56 | } |
218 | 57 | ||
219 | static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | 58 | int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
220 | u16 size, void *data) | 59 | u16 size, void *data) |
221 | { | 60 | { |
222 | void *buf = NULL; | 61 | void *buf = NULL; |
223 | int err = -ENOMEM; | 62 | int err = -ENOMEM; |
@@ -260,9 +99,8 @@ static void asix_async_cmd_callback(struct urb *urb) | |||
260 | usb_free_urb(urb); | 99 | usb_free_urb(urb); |
261 | } | 100 | } |
262 | 101 | ||
263 | static void | 102 | void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
264 | asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | 103 | u16 size, void *data) |
265 | u16 size, void *data) | ||
266 | { | 104 | { |
267 | struct usb_ctrlrequest *req; | 105 | struct usb_ctrlrequest *req; |
268 | int status; | 106 | int status; |
@@ -304,7 +142,7 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |||
304 | } | 142 | } |
305 | } | 143 | } |
306 | 144 | ||
307 | static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 145 | int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
308 | { | 146 | { |
309 | int offset = 0; | 147 | int offset = 0; |
310 | 148 | ||
@@ -347,8 +185,8 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
347 | return 1; | 185 | return 1; |
348 | } | 186 | } |
349 | 187 | ||
350 | static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | 188 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
351 | gfp_t flags) | 189 | gfp_t flags) |
352 | { | 190 | { |
353 | int padlen; | 191 | int padlen; |
354 | int headroom = skb_headroom(skb); | 192 | int headroom = skb_headroom(skb); |
@@ -402,27 +240,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |||
402 | return skb; | 240 | return skb; |
403 | } | 241 | } |
404 | 242 | ||
405 | static void asix_status(struct usbnet *dev, struct urb *urb) | 243 | int asix_set_sw_mii(struct usbnet *dev) |
406 | { | ||
407 | struct ax88172_int_data *event; | ||
408 | int link; | ||
409 | |||
410 | if (urb->actual_length < 8) | ||
411 | return; | ||
412 | |||
413 | event = urb->transfer_buffer; | ||
414 | link = event->link & 0x01; | ||
415 | if (netif_carrier_ok(dev->net) != link) { | ||
416 | if (link) { | ||
417 | netif_carrier_on(dev->net); | ||
418 | usbnet_defer_kevent (dev, EVENT_LINK_RESET ); | ||
419 | } else | ||
420 | netif_carrier_off(dev->net); | ||
421 | netdev_dbg(dev->net, "Link Status is: %d\n", link); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | static inline int asix_set_sw_mii(struct usbnet *dev) | ||
426 | { | 244 | { |
427 | int ret; | 245 | int ret; |
428 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | 246 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); |
@@ -431,7 +249,7 @@ static inline int asix_set_sw_mii(struct usbnet *dev) | |||
431 | return ret; | 249 | return ret; |
432 | } | 250 | } |
433 | 251 | ||
434 | static inline int asix_set_hw_mii(struct usbnet *dev) | 252 | int asix_set_hw_mii(struct usbnet *dev) |
435 | { | 253 | { |
436 | int ret; | 254 | int ret; |
437 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | 255 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); |
@@ -440,7 +258,7 @@ static inline int asix_set_hw_mii(struct usbnet *dev) | |||
440 | return ret; | 258 | return ret; |
441 | } | 259 | } |
442 | 260 | ||
443 | static inline int asix_get_phy_addr(struct usbnet *dev) | 261 | int asix_get_phy_addr(struct usbnet *dev) |
444 | { | 262 | { |
445 | u8 buf[2]; | 263 | u8 buf[2]; |
446 | int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); | 264 | int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
@@ -459,7 +277,7 @@ out: | |||
459 | return ret; | 277 | return ret; |
460 | } | 278 | } |
461 | 279 | ||
462 | static int asix_sw_reset(struct usbnet *dev, u8 flags) | 280 | int asix_sw_reset(struct usbnet *dev, u8 flags) |
463 | { | 281 | { |
464 | int ret; | 282 | int ret; |
465 | 283 | ||
@@ -470,7 +288,7 @@ static int asix_sw_reset(struct usbnet *dev, u8 flags) | |||
470 | return ret; | 288 | return ret; |
471 | } | 289 | } |
472 | 290 | ||
473 | static u16 asix_read_rx_ctl(struct usbnet *dev) | 291 | u16 asix_read_rx_ctl(struct usbnet *dev) |
474 | { | 292 | { |
475 | __le16 v; | 293 | __le16 v; |
476 | int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); | 294 | int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); |
@@ -484,7 +302,7 @@ out: | |||
484 | return ret; | 302 | return ret; |
485 | } | 303 | } |
486 | 304 | ||
487 | static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | 305 | int asix_write_rx_ctl(struct usbnet *dev, u16 mode) |
488 | { | 306 | { |
489 | int ret; | 307 | int ret; |
490 | 308 | ||
@@ -497,7 +315,7 @@ static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | |||
497 | return ret; | 315 | return ret; |
498 | } | 316 | } |
499 | 317 | ||
500 | static u16 asix_read_medium_status(struct usbnet *dev) | 318 | u16 asix_read_medium_status(struct usbnet *dev) |
501 | { | 319 | { |
502 | __le16 v; | 320 | __le16 v; |
503 | int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | 321 | int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); |
@@ -512,7 +330,7 @@ static u16 asix_read_medium_status(struct usbnet *dev) | |||
512 | 330 | ||
513 | } | 331 | } |
514 | 332 | ||
515 | static int asix_write_medium_mode(struct usbnet *dev, u16 mode) | 333 | int asix_write_medium_mode(struct usbnet *dev, u16 mode) |
516 | { | 334 | { |
517 | int ret; | 335 | int ret; |
518 | 336 | ||
@@ -525,7 +343,7 @@ static int asix_write_medium_mode(struct usbnet *dev, u16 mode) | |||
525 | return ret; | 343 | return ret; |
526 | } | 344 | } |
527 | 345 | ||
528 | static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | 346 | int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) |
529 | { | 347 | { |
530 | int ret; | 348 | int ret; |
531 | 349 | ||
@@ -544,7 +362,7 @@ static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | |||
544 | /* | 362 | /* |
545 | * AX88772 & AX88178 have a 16-bit RX_CTL value | 363 | * AX88772 & AX88178 have a 16-bit RX_CTL value |
546 | */ | 364 | */ |
547 | static void asix_set_multicast(struct net_device *net) | 365 | void asix_set_multicast(struct net_device *net) |
548 | { | 366 | { |
549 | struct usbnet *dev = netdev_priv(net); | 367 | struct usbnet *dev = netdev_priv(net); |
550 | struct asix_data *data = (struct asix_data *)&dev->data; | 368 | struct asix_data *data = (struct asix_data *)&dev->data; |
@@ -583,7 +401,7 @@ static void asix_set_multicast(struct net_device *net) | |||
583 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | 401 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); |
584 | } | 402 | } |
585 | 403 | ||
586 | static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | 404 | int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) |
587 | { | 405 | { |
588 | struct usbnet *dev = netdev_priv(netdev); | 406 | struct usbnet *dev = netdev_priv(netdev); |
589 | __le16 res; | 407 | __le16 res; |
@@ -601,8 +419,7 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | |||
601 | return le16_to_cpu(res); | 419 | return le16_to_cpu(res); |
602 | } | 420 | } |
603 | 421 | ||
604 | static void | 422 | void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) |
605 | asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | ||
606 | { | 423 | { |
607 | struct usbnet *dev = netdev_priv(netdev); | 424 | struct usbnet *dev = netdev_priv(netdev); |
608 | __le16 res = cpu_to_le16(val); | 425 | __le16 res = cpu_to_le16(val); |
@@ -616,37 +433,7 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | |||
616 | mutex_unlock(&dev->phy_mutex); | 433 | mutex_unlock(&dev->phy_mutex); |
617 | } | 434 | } |
618 | 435 | ||
619 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | 436 | void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) |
620 | static u32 asix_get_phyid(struct usbnet *dev) | ||
621 | { | ||
622 | int phy_reg; | ||
623 | u32 phy_id; | ||
624 | int i; | ||
625 | |||
626 | /* Poll for the rare case the FW or phy isn't ready yet. */ | ||
627 | for (i = 0; i < 100; i++) { | ||
628 | phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); | ||
629 | if (phy_reg != 0 && phy_reg != 0xFFFF) | ||
630 | break; | ||
631 | mdelay(1); | ||
632 | } | ||
633 | |||
634 | if (phy_reg <= 0 || phy_reg == 0xFFFF) | ||
635 | return 0; | ||
636 | |||
637 | phy_id = (phy_reg & 0xffff) << 16; | ||
638 | |||
639 | phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); | ||
640 | if (phy_reg < 0) | ||
641 | return 0; | ||
642 | |||
643 | phy_id |= (phy_reg & 0xffff); | ||
644 | |||
645 | return phy_id; | ||
646 | } | ||
647 | |||
648 | static void | ||
649 | asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
650 | { | 437 | { |
651 | struct usbnet *dev = netdev_priv(net); | 438 | struct usbnet *dev = netdev_priv(net); |
652 | u8 opt; | 439 | u8 opt; |
@@ -664,8 +451,7 @@ asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |||
664 | wolinfo->wolopts |= WAKE_MAGIC; | 451 | wolinfo->wolopts |= WAKE_MAGIC; |
665 | } | 452 | } |
666 | 453 | ||
667 | static int | 454 | int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) |
668 | asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
669 | { | 455 | { |
670 | struct usbnet *dev = netdev_priv(net); | 456 | struct usbnet *dev = netdev_priv(net); |
671 | u8 opt = 0; | 457 | u8 opt = 0; |
@@ -682,7 +468,7 @@ asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |||
682 | return 0; | 468 | return 0; |
683 | } | 469 | } |
684 | 470 | ||
685 | static int asix_get_eeprom_len(struct net_device *net) | 471 | int asix_get_eeprom_len(struct net_device *net) |
686 | { | 472 | { |
687 | struct usbnet *dev = netdev_priv(net); | 473 | struct usbnet *dev = netdev_priv(net); |
688 | struct asix_data *data = (struct asix_data *)&dev->data; | 474 | struct asix_data *data = (struct asix_data *)&dev->data; |
@@ -690,8 +476,8 @@ static int asix_get_eeprom_len(struct net_device *net) | |||
690 | return data->eeprom_len; | 476 | return data->eeprom_len; |
691 | } | 477 | } |
692 | 478 | ||
693 | static int asix_get_eeprom(struct net_device *net, | 479 | int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, |
694 | struct ethtool_eeprom *eeprom, u8 *data) | 480 | u8 *data) |
695 | { | 481 | { |
696 | struct usbnet *dev = netdev_priv(net); | 482 | struct usbnet *dev = netdev_priv(net); |
697 | __le16 *ebuf = (__le16 *)data; | 483 | __le16 *ebuf = (__le16 *)data; |
@@ -714,8 +500,7 @@ static int asix_get_eeprom(struct net_device *net, | |||
714 | return 0; | 500 | return 0; |
715 | } | 501 | } |
716 | 502 | ||
717 | static void asix_get_drvinfo (struct net_device *net, | 503 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) |
718 | struct ethtool_drvinfo *info) | ||
719 | { | 504 | { |
720 | struct usbnet *dev = netdev_priv(net); | 505 | struct usbnet *dev = netdev_priv(net); |
721 | struct asix_data *data = (struct asix_data *)&dev->data; | 506 | struct asix_data *data = (struct asix_data *)&dev->data; |
@@ -727,21 +512,7 @@ static void asix_get_drvinfo (struct net_device *net, | |||
727 | info->eedump_len = data->eeprom_len; | 512 | info->eedump_len = data->eeprom_len; |
728 | } | 513 | } |
729 | 514 | ||
730 | static u32 asix_get_link(struct net_device *net) | 515 | int asix_set_mac_address(struct net_device *net, void *p) |
731 | { | ||
732 | struct usbnet *dev = netdev_priv(net); | ||
733 | |||
734 | return mii_link_ok(&dev->mii); | ||
735 | } | ||
736 | |||
737 | static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) | ||
738 | { | ||
739 | struct usbnet *dev = netdev_priv(net); | ||
740 | |||
741 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | ||
742 | } | ||
743 | |||
744 | static int asix_set_mac_address(struct net_device *net, void *p) | ||
745 | { | 516 | { |
746 | struct usbnet *dev = netdev_priv(net); | 517 | struct usbnet *dev = netdev_priv(net); |
747 | struct asix_data *data = (struct asix_data *)&dev->data; | 518 | struct asix_data *data = (struct asix_data *)&dev->data; |
@@ -764,917 +535,3 @@ static int asix_set_mac_address(struct net_device *net, void *p) | |||
764 | 535 | ||
765 | return 0; | 536 | return 0; |
766 | } | 537 | } |
767 | |||
768 | /* We need to override some ethtool_ops so we require our | ||
769 | own structure so we don't interfere with other usbnet | ||
770 | devices that may be connected at the same time. */ | ||
771 | static const struct ethtool_ops ax88172_ethtool_ops = { | ||
772 | .get_drvinfo = asix_get_drvinfo, | ||
773 | .get_link = asix_get_link, | ||
774 | .get_msglevel = usbnet_get_msglevel, | ||
775 | .set_msglevel = usbnet_set_msglevel, | ||
776 | .get_wol = asix_get_wol, | ||
777 | .set_wol = asix_set_wol, | ||
778 | .get_eeprom_len = asix_get_eeprom_len, | ||
779 | .get_eeprom = asix_get_eeprom, | ||
780 | .get_settings = usbnet_get_settings, | ||
781 | .set_settings = usbnet_set_settings, | ||
782 | .nway_reset = usbnet_nway_reset, | ||
783 | }; | ||
784 | |||
785 | static void ax88172_set_multicast(struct net_device *net) | ||
786 | { | ||
787 | struct usbnet *dev = netdev_priv(net); | ||
788 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
789 | u8 rx_ctl = 0x8c; | ||
790 | |||
791 | if (net->flags & IFF_PROMISC) { | ||
792 | rx_ctl |= 0x01; | ||
793 | } else if (net->flags & IFF_ALLMULTI || | ||
794 | netdev_mc_count(net) > AX_MAX_MCAST) { | ||
795 | rx_ctl |= 0x02; | ||
796 | } else if (netdev_mc_empty(net)) { | ||
797 | /* just broadcast and directed */ | ||
798 | } else { | ||
799 | /* We use the 20 byte dev->data | ||
800 | * for our 8 byte filter buffer | ||
801 | * to avoid allocating memory that | ||
802 | * is tricky to free later */ | ||
803 | struct netdev_hw_addr *ha; | ||
804 | u32 crc_bits; | ||
805 | |||
806 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
807 | |||
808 | /* Build the multicast hash filter. */ | ||
809 | netdev_for_each_mc_addr(ha, net) { | ||
810 | crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | ||
811 | data->multi_filter[crc_bits >> 3] |= | ||
812 | 1 << (crc_bits & 7); | ||
813 | } | ||
814 | |||
815 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
816 | AX_MCAST_FILTER_SIZE, data->multi_filter); | ||
817 | |||
818 | rx_ctl |= 0x10; | ||
819 | } | ||
820 | |||
821 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
822 | } | ||
823 | |||
824 | static int ax88172_link_reset(struct usbnet *dev) | ||
825 | { | ||
826 | u8 mode; | ||
827 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | ||
828 | |||
829 | mii_check_media(&dev->mii, 1, 1); | ||
830 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
831 | mode = AX88172_MEDIUM_DEFAULT; | ||
832 | |||
833 | if (ecmd.duplex != DUPLEX_FULL) | ||
834 | mode |= ~AX88172_MEDIUM_FD; | ||
835 | |||
836 | netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | ||
837 | ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | ||
838 | |||
839 | asix_write_medium_mode(dev, mode); | ||
840 | |||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | static const struct net_device_ops ax88172_netdev_ops = { | ||
845 | .ndo_open = usbnet_open, | ||
846 | .ndo_stop = usbnet_stop, | ||
847 | .ndo_start_xmit = usbnet_start_xmit, | ||
848 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
849 | .ndo_change_mtu = usbnet_change_mtu, | ||
850 | .ndo_set_mac_address = eth_mac_addr, | ||
851 | .ndo_validate_addr = eth_validate_addr, | ||
852 | .ndo_do_ioctl = asix_ioctl, | ||
853 | .ndo_set_rx_mode = ax88172_set_multicast, | ||
854 | }; | ||
855 | |||
856 | static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) | ||
857 | { | ||
858 | int ret = 0; | ||
859 | u8 buf[ETH_ALEN]; | ||
860 | int i; | ||
861 | unsigned long gpio_bits = dev->driver_info->data; | ||
862 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
863 | |||
864 | data->eeprom_len = AX88172_EEPROM_LEN; | ||
865 | |||
866 | usbnet_get_endpoints(dev,intf); | ||
867 | |||
868 | /* Toggle the GPIOs in a manufacturer/model specific way */ | ||
869 | for (i = 2; i >= 0; i--) { | ||
870 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, | ||
871 | (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); | ||
872 | if (ret < 0) | ||
873 | goto out; | ||
874 | msleep(5); | ||
875 | } | ||
876 | |||
877 | ret = asix_write_rx_ctl(dev, 0x80); | ||
878 | if (ret < 0) | ||
879 | goto out; | ||
880 | |||
881 | /* Get the MAC address */ | ||
882 | ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | ||
883 | if (ret < 0) { | ||
884 | dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); | ||
885 | goto out; | ||
886 | } | ||
887 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
888 | |||
889 | /* Initialize MII structure */ | ||
890 | dev->mii.dev = dev->net; | ||
891 | dev->mii.mdio_read = asix_mdio_read; | ||
892 | dev->mii.mdio_write = asix_mdio_write; | ||
893 | dev->mii.phy_id_mask = 0x3f; | ||
894 | dev->mii.reg_num_mask = 0x1f; | ||
895 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
896 | |||
897 | dev->net->netdev_ops = &ax88172_netdev_ops; | ||
898 | dev->net->ethtool_ops = &ax88172_ethtool_ops; | ||
899 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
900 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
901 | |||
902 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
903 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
904 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | ||
905 | mii_nway_restart(&dev->mii); | ||
906 | |||
907 | return 0; | ||
908 | |||
909 | out: | ||
910 | return ret; | ||
911 | } | ||
912 | |||
913 | static const struct ethtool_ops ax88772_ethtool_ops = { | ||
914 | .get_drvinfo = asix_get_drvinfo, | ||
915 | .get_link = asix_get_link, | ||
916 | .get_msglevel = usbnet_get_msglevel, | ||
917 | .set_msglevel = usbnet_set_msglevel, | ||
918 | .get_wol = asix_get_wol, | ||
919 | .set_wol = asix_set_wol, | ||
920 | .get_eeprom_len = asix_get_eeprom_len, | ||
921 | .get_eeprom = asix_get_eeprom, | ||
922 | .get_settings = usbnet_get_settings, | ||
923 | .set_settings = usbnet_set_settings, | ||
924 | .nway_reset = usbnet_nway_reset, | ||
925 | }; | ||
926 | |||
927 | static int ax88772_link_reset(struct usbnet *dev) | ||
928 | { | ||
929 | u16 mode; | ||
930 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | ||
931 | |||
932 | mii_check_media(&dev->mii, 1, 1); | ||
933 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
934 | mode = AX88772_MEDIUM_DEFAULT; | ||
935 | |||
936 | if (ethtool_cmd_speed(&ecmd) != SPEED_100) | ||
937 | mode &= ~AX_MEDIUM_PS; | ||
938 | |||
939 | if (ecmd.duplex != DUPLEX_FULL) | ||
940 | mode &= ~AX_MEDIUM_FD; | ||
941 | |||
942 | netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | ||
943 | ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | ||
944 | |||
945 | asix_write_medium_mode(dev, mode); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int ax88772_reset(struct usbnet *dev) | ||
951 | { | ||
952 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
953 | int ret, embd_phy; | ||
954 | u16 rx_ctl; | ||
955 | |||
956 | ret = asix_write_gpio(dev, | ||
957 | AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); | ||
958 | if (ret < 0) | ||
959 | goto out; | ||
960 | |||
961 | embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); | ||
962 | |||
963 | ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | ||
964 | if (ret < 0) { | ||
965 | dbg("Select PHY #1 failed: %d", ret); | ||
966 | goto out; | ||
967 | } | ||
968 | |||
969 | ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); | ||
970 | if (ret < 0) | ||
971 | goto out; | ||
972 | |||
973 | msleep(150); | ||
974 | |||
975 | ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); | ||
976 | if (ret < 0) | ||
977 | goto out; | ||
978 | |||
979 | msleep(150); | ||
980 | |||
981 | if (embd_phy) { | ||
982 | ret = asix_sw_reset(dev, AX_SWRESET_IPRL); | ||
983 | if (ret < 0) | ||
984 | goto out; | ||
985 | } else { | ||
986 | ret = asix_sw_reset(dev, AX_SWRESET_PRTE); | ||
987 | if (ret < 0) | ||
988 | goto out; | ||
989 | } | ||
990 | |||
991 | msleep(150); | ||
992 | rx_ctl = asix_read_rx_ctl(dev); | ||
993 | dbg("RX_CTL is 0x%04x after software reset", rx_ctl); | ||
994 | ret = asix_write_rx_ctl(dev, 0x0000); | ||
995 | if (ret < 0) | ||
996 | goto out; | ||
997 | |||
998 | rx_ctl = asix_read_rx_ctl(dev); | ||
999 | dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); | ||
1000 | |||
1001 | ret = asix_sw_reset(dev, AX_SWRESET_PRL); | ||
1002 | if (ret < 0) | ||
1003 | goto out; | ||
1004 | |||
1005 | msleep(150); | ||
1006 | |||
1007 | ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); | ||
1008 | if (ret < 0) | ||
1009 | goto out; | ||
1010 | |||
1011 | msleep(150); | ||
1012 | |||
1013 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | ||
1014 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
1015 | ADVERTISE_ALL | ADVERTISE_CSMA); | ||
1016 | mii_nway_restart(&dev->mii); | ||
1017 | |||
1018 | ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); | ||
1019 | if (ret < 0) | ||
1020 | goto out; | ||
1021 | |||
1022 | ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, | ||
1023 | AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, | ||
1024 | AX88772_IPG2_DEFAULT, 0, NULL); | ||
1025 | if (ret < 0) { | ||
1026 | dbg("Write IPG,IPG1,IPG2 failed: %d", ret); | ||
1027 | goto out; | ||
1028 | } | ||
1029 | |||
1030 | /* Rewrite MAC address */ | ||
1031 | memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | ||
1032 | ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
1033 | data->mac_addr); | ||
1034 | if (ret < 0) | ||
1035 | goto out; | ||
1036 | |||
1037 | /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | ||
1038 | ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | ||
1039 | if (ret < 0) | ||
1040 | goto out; | ||
1041 | |||
1042 | rx_ctl = asix_read_rx_ctl(dev); | ||
1043 | dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); | ||
1044 | |||
1045 | rx_ctl = asix_read_medium_status(dev); | ||
1046 | dbg("Medium Status is 0x%04x after all initializations", rx_ctl); | ||
1047 | |||
1048 | return 0; | ||
1049 | |||
1050 | out: | ||
1051 | return ret; | ||
1052 | |||
1053 | } | ||
1054 | |||
1055 | static const struct net_device_ops ax88772_netdev_ops = { | ||
1056 | .ndo_open = usbnet_open, | ||
1057 | .ndo_stop = usbnet_stop, | ||
1058 | .ndo_start_xmit = usbnet_start_xmit, | ||
1059 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
1060 | .ndo_change_mtu = usbnet_change_mtu, | ||
1061 | .ndo_set_mac_address = asix_set_mac_address, | ||
1062 | .ndo_validate_addr = eth_validate_addr, | ||
1063 | .ndo_do_ioctl = asix_ioctl, | ||
1064 | .ndo_set_rx_mode = asix_set_multicast, | ||
1065 | }; | ||
1066 | |||
1067 | static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | ||
1068 | { | ||
1069 | int ret, embd_phy; | ||
1070 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1071 | u8 buf[ETH_ALEN]; | ||
1072 | u32 phyid; | ||
1073 | |||
1074 | data->eeprom_len = AX88772_EEPROM_LEN; | ||
1075 | |||
1076 | usbnet_get_endpoints(dev,intf); | ||
1077 | |||
1078 | /* Get the MAC address */ | ||
1079 | ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | ||
1080 | if (ret < 0) { | ||
1081 | dbg("Failed to read MAC address: %d", ret); | ||
1082 | return ret; | ||
1083 | } | ||
1084 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
1085 | |||
1086 | /* Initialize MII structure */ | ||
1087 | dev->mii.dev = dev->net; | ||
1088 | dev->mii.mdio_read = asix_mdio_read; | ||
1089 | dev->mii.mdio_write = asix_mdio_write; | ||
1090 | dev->mii.phy_id_mask = 0x1f; | ||
1091 | dev->mii.reg_num_mask = 0x1f; | ||
1092 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
1093 | |||
1094 | dev->net->netdev_ops = &ax88772_netdev_ops; | ||
1095 | dev->net->ethtool_ops = &ax88772_ethtool_ops; | ||
1096 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
1097 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
1098 | |||
1099 | embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); | ||
1100 | |||
1101 | /* Reset the PHY to normal operation mode */ | ||
1102 | ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | ||
1103 | if (ret < 0) { | ||
1104 | dbg("Select PHY #1 failed: %d", ret); | ||
1105 | return ret; | ||
1106 | } | ||
1107 | |||
1108 | ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); | ||
1109 | if (ret < 0) | ||
1110 | return ret; | ||
1111 | |||
1112 | msleep(150); | ||
1113 | |||
1114 | ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); | ||
1115 | if (ret < 0) | ||
1116 | return ret; | ||
1117 | |||
1118 | msleep(150); | ||
1119 | |||
1120 | ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); | ||
1121 | |||
1122 | /* Read PHYID register *AFTER* the PHY was reset properly */ | ||
1123 | phyid = asix_get_phyid(dev); | ||
1124 | dbg("PHYID=0x%08x", phyid); | ||
1125 | |||
1126 | /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | ||
1127 | if (dev->driver_info->flags & FLAG_FRAMING_AX) { | ||
1128 | /* hard_mtu is still the default - the device does not support | ||
1129 | jumbo eth frames */ | ||
1130 | dev->rx_urb_size = 2048; | ||
1131 | } | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static const struct ethtool_ops ax88178_ethtool_ops = { | ||
1137 | .get_drvinfo = asix_get_drvinfo, | ||
1138 | .get_link = asix_get_link, | ||
1139 | .get_msglevel = usbnet_get_msglevel, | ||
1140 | .set_msglevel = usbnet_set_msglevel, | ||
1141 | .get_wol = asix_get_wol, | ||
1142 | .set_wol = asix_set_wol, | ||
1143 | .get_eeprom_len = asix_get_eeprom_len, | ||
1144 | .get_eeprom = asix_get_eeprom, | ||
1145 | .get_settings = usbnet_get_settings, | ||
1146 | .set_settings = usbnet_set_settings, | ||
1147 | .nway_reset = usbnet_nway_reset, | ||
1148 | }; | ||
1149 | |||
1150 | static int marvell_phy_init(struct usbnet *dev) | ||
1151 | { | ||
1152 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1153 | u16 reg; | ||
1154 | |||
1155 | netdev_dbg(dev->net, "marvell_phy_init()\n"); | ||
1156 | |||
1157 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); | ||
1158 | netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); | ||
1159 | |||
1160 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, | ||
1161 | MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); | ||
1162 | |||
1163 | if (data->ledmode) { | ||
1164 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, | ||
1165 | MII_MARVELL_LED_CTRL); | ||
1166 | netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); | ||
1167 | |||
1168 | reg &= 0xf8ff; | ||
1169 | reg |= (1 + 0x0100); | ||
1170 | asix_mdio_write(dev->net, dev->mii.phy_id, | ||
1171 | MII_MARVELL_LED_CTRL, reg); | ||
1172 | |||
1173 | reg = asix_mdio_read(dev->net, dev->mii.phy_id, | ||
1174 | MII_MARVELL_LED_CTRL); | ||
1175 | netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); | ||
1176 | reg &= 0xfc0f; | ||
1177 | } | ||
1178 | |||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1182 | static int rtl8211cl_phy_init(struct usbnet *dev) | ||
1183 | { | ||
1184 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1185 | |||
1186 | netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); | ||
1187 | |||
1188 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); | ||
1189 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); | ||
1190 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, | ||
1191 | asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); | ||
1192 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); | ||
1193 | |||
1194 | if (data->ledmode == 12) { | ||
1195 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); | ||
1196 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); | ||
1197 | asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); | ||
1198 | } | ||
1199 | |||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | static int marvell_led_status(struct usbnet *dev, u16 speed) | ||
1204 | { | ||
1205 | u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); | ||
1206 | |||
1207 | netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); | ||
1208 | |||
1209 | /* Clear out the center LED bits - 0x03F0 */ | ||
1210 | reg &= 0xfc0f; | ||
1211 | |||
1212 | switch (speed) { | ||
1213 | case SPEED_1000: | ||
1214 | reg |= 0x03e0; | ||
1215 | break; | ||
1216 | case SPEED_100: | ||
1217 | reg |= 0x03b0; | ||
1218 | break; | ||
1219 | default: | ||
1220 | reg |= 0x02f0; | ||
1221 | } | ||
1222 | |||
1223 | netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); | ||
1224 | asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); | ||
1225 | |||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static int ax88178_reset(struct usbnet *dev) | ||
1230 | { | ||
1231 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1232 | int ret; | ||
1233 | __le16 eeprom; | ||
1234 | u8 status; | ||
1235 | int gpio0 = 0; | ||
1236 | u32 phyid; | ||
1237 | |||
1238 | asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); | ||
1239 | dbg("GPIO Status: 0x%04x", status); | ||
1240 | |||
1241 | asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); | ||
1242 | asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); | ||
1243 | asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); | ||
1244 | |||
1245 | dbg("EEPROM index 0x17 is 0x%04x", eeprom); | ||
1246 | |||
1247 | if (eeprom == cpu_to_le16(0xffff)) { | ||
1248 | data->phymode = PHY_MODE_MARVELL; | ||
1249 | data->ledmode = 0; | ||
1250 | gpio0 = 1; | ||
1251 | } else { | ||
1252 | data->phymode = le16_to_cpu(eeprom) & 0x7F; | ||
1253 | data->ledmode = le16_to_cpu(eeprom) >> 8; | ||
1254 | gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; | ||
1255 | } | ||
1256 | dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); | ||
1257 | |||
1258 | /* Power up external GigaPHY through AX88178 GPIO pin */ | ||
1259 | asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); | ||
1260 | if ((le16_to_cpu(eeprom) >> 8) != 1) { | ||
1261 | asix_write_gpio(dev, 0x003c, 30); | ||
1262 | asix_write_gpio(dev, 0x001c, 300); | ||
1263 | asix_write_gpio(dev, 0x003c, 30); | ||
1264 | } else { | ||
1265 | dbg("gpio phymode == 1 path"); | ||
1266 | asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); | ||
1267 | asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); | ||
1268 | } | ||
1269 | |||
1270 | /* Read PHYID register *AFTER* powering up PHY */ | ||
1271 | phyid = asix_get_phyid(dev); | ||
1272 | dbg("PHYID=0x%08x", phyid); | ||
1273 | |||
1274 | /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ | ||
1275 | asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); | ||
1276 | |||
1277 | asix_sw_reset(dev, 0); | ||
1278 | msleep(150); | ||
1279 | |||
1280 | asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); | ||
1281 | msleep(150); | ||
1282 | |||
1283 | asix_write_rx_ctl(dev, 0); | ||
1284 | |||
1285 | if (data->phymode == PHY_MODE_MARVELL) { | ||
1286 | marvell_phy_init(dev); | ||
1287 | msleep(60); | ||
1288 | } else if (data->phymode == PHY_MODE_RTL8211CL) | ||
1289 | rtl8211cl_phy_init(dev); | ||
1290 | |||
1291 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, | ||
1292 | BMCR_RESET | BMCR_ANENABLE); | ||
1293 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | ||
1294 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | ||
1295 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, | ||
1296 | ADVERTISE_1000FULL); | ||
1297 | |||
1298 | mii_nway_restart(&dev->mii); | ||
1299 | |||
1300 | ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); | ||
1301 | if (ret < 0) | ||
1302 | return ret; | ||
1303 | |||
1304 | /* Rewrite MAC address */ | ||
1305 | memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | ||
1306 | ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
1307 | data->mac_addr); | ||
1308 | if (ret < 0) | ||
1309 | return ret; | ||
1310 | |||
1311 | ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | ||
1312 | if (ret < 0) | ||
1313 | return ret; | ||
1314 | |||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1318 | static int ax88178_link_reset(struct usbnet *dev) | ||
1319 | { | ||
1320 | u16 mode; | ||
1321 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | ||
1322 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1323 | u32 speed; | ||
1324 | |||
1325 | netdev_dbg(dev->net, "ax88178_link_reset()\n"); | ||
1326 | |||
1327 | mii_check_media(&dev->mii, 1, 1); | ||
1328 | mii_ethtool_gset(&dev->mii, &ecmd); | ||
1329 | mode = AX88178_MEDIUM_DEFAULT; | ||
1330 | speed = ethtool_cmd_speed(&ecmd); | ||
1331 | |||
1332 | if (speed == SPEED_1000) | ||
1333 | mode |= AX_MEDIUM_GM; | ||
1334 | else if (speed == SPEED_100) | ||
1335 | mode |= AX_MEDIUM_PS; | ||
1336 | else | ||
1337 | mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); | ||
1338 | |||
1339 | mode |= AX_MEDIUM_ENCK; | ||
1340 | |||
1341 | if (ecmd.duplex == DUPLEX_FULL) | ||
1342 | mode |= AX_MEDIUM_FD; | ||
1343 | else | ||
1344 | mode &= ~AX_MEDIUM_FD; | ||
1345 | |||
1346 | netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | ||
1347 | speed, ecmd.duplex, mode); | ||
1348 | |||
1349 | asix_write_medium_mode(dev, mode); | ||
1350 | |||
1351 | if (data->phymode == PHY_MODE_MARVELL && data->ledmode) | ||
1352 | marvell_led_status(dev, speed); | ||
1353 | |||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
1357 | static void ax88178_set_mfb(struct usbnet *dev) | ||
1358 | { | ||
1359 | u16 mfb = AX_RX_CTL_MFB_16384; | ||
1360 | u16 rxctl; | ||
1361 | u16 medium; | ||
1362 | int old_rx_urb_size = dev->rx_urb_size; | ||
1363 | |||
1364 | if (dev->hard_mtu < 2048) { | ||
1365 | dev->rx_urb_size = 2048; | ||
1366 | mfb = AX_RX_CTL_MFB_2048; | ||
1367 | } else if (dev->hard_mtu < 4096) { | ||
1368 | dev->rx_urb_size = 4096; | ||
1369 | mfb = AX_RX_CTL_MFB_4096; | ||
1370 | } else if (dev->hard_mtu < 8192) { | ||
1371 | dev->rx_urb_size = 8192; | ||
1372 | mfb = AX_RX_CTL_MFB_8192; | ||
1373 | } else if (dev->hard_mtu < 16384) { | ||
1374 | dev->rx_urb_size = 16384; | ||
1375 | mfb = AX_RX_CTL_MFB_16384; | ||
1376 | } | ||
1377 | |||
1378 | rxctl = asix_read_rx_ctl(dev); | ||
1379 | asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); | ||
1380 | |||
1381 | medium = asix_read_medium_status(dev); | ||
1382 | if (dev->net->mtu > 1500) | ||
1383 | medium |= AX_MEDIUM_JFE; | ||
1384 | else | ||
1385 | medium &= ~AX_MEDIUM_JFE; | ||
1386 | asix_write_medium_mode(dev, medium); | ||
1387 | |||
1388 | if (dev->rx_urb_size > old_rx_urb_size) | ||
1389 | usbnet_unlink_rx_urbs(dev); | ||
1390 | } | ||
1391 | |||
1392 | static int ax88178_change_mtu(struct net_device *net, int new_mtu) | ||
1393 | { | ||
1394 | struct usbnet *dev = netdev_priv(net); | ||
1395 | int ll_mtu = new_mtu + net->hard_header_len + 4; | ||
1396 | |||
1397 | netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); | ||
1398 | |||
1399 | if (new_mtu <= 0 || ll_mtu > 16384) | ||
1400 | return -EINVAL; | ||
1401 | |||
1402 | if ((ll_mtu % dev->maxpacket) == 0) | ||
1403 | return -EDOM; | ||
1404 | |||
1405 | net->mtu = new_mtu; | ||
1406 | dev->hard_mtu = net->mtu + net->hard_header_len; | ||
1407 | ax88178_set_mfb(dev); | ||
1408 | |||
1409 | return 0; | ||
1410 | } | ||
1411 | |||
1412 | static const struct net_device_ops ax88178_netdev_ops = { | ||
1413 | .ndo_open = usbnet_open, | ||
1414 | .ndo_stop = usbnet_stop, | ||
1415 | .ndo_start_xmit = usbnet_start_xmit, | ||
1416 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
1417 | .ndo_set_mac_address = asix_set_mac_address, | ||
1418 | .ndo_validate_addr = eth_validate_addr, | ||
1419 | .ndo_set_rx_mode = asix_set_multicast, | ||
1420 | .ndo_do_ioctl = asix_ioctl, | ||
1421 | .ndo_change_mtu = ax88178_change_mtu, | ||
1422 | }; | ||
1423 | |||
1424 | static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) | ||
1425 | { | ||
1426 | int ret; | ||
1427 | u8 buf[ETH_ALEN]; | ||
1428 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1429 | |||
1430 | data->eeprom_len = AX88772_EEPROM_LEN; | ||
1431 | |||
1432 | usbnet_get_endpoints(dev,intf); | ||
1433 | |||
1434 | /* Get the MAC address */ | ||
1435 | ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | ||
1436 | if (ret < 0) { | ||
1437 | dbg("Failed to read MAC address: %d", ret); | ||
1438 | return ret; | ||
1439 | } | ||
1440 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
1441 | |||
1442 | /* Initialize MII structure */ | ||
1443 | dev->mii.dev = dev->net; | ||
1444 | dev->mii.mdio_read = asix_mdio_read; | ||
1445 | dev->mii.mdio_write = asix_mdio_write; | ||
1446 | dev->mii.phy_id_mask = 0x1f; | ||
1447 | dev->mii.reg_num_mask = 0xff; | ||
1448 | dev->mii.supports_gmii = 1; | ||
1449 | dev->mii.phy_id = asix_get_phy_addr(dev); | ||
1450 | |||
1451 | dev->net->netdev_ops = &ax88178_netdev_ops; | ||
1452 | dev->net->ethtool_ops = &ax88178_ethtool_ops; | ||
1453 | |||
1454 | /* Blink LEDS so users know driver saw dongle */ | ||
1455 | asix_sw_reset(dev, 0); | ||
1456 | msleep(150); | ||
1457 | |||
1458 | asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); | ||
1459 | msleep(150); | ||
1460 | |||
1461 | /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | ||
1462 | if (dev->driver_info->flags & FLAG_FRAMING_AX) { | ||
1463 | /* hard_mtu is still the default - the device does not support | ||
1464 | jumbo eth frames */ | ||
1465 | dev->rx_urb_size = 2048; | ||
1466 | } | ||
1467 | |||
1468 | return 0; | ||
1469 | } | ||
1470 | |||
1471 | static const struct driver_info ax8817x_info = { | ||
1472 | .description = "ASIX AX8817x USB 2.0 Ethernet", | ||
1473 | .bind = ax88172_bind, | ||
1474 | .status = asix_status, | ||
1475 | .link_reset = ax88172_link_reset, | ||
1476 | .reset = ax88172_link_reset, | ||
1477 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1478 | .data = 0x00130103, | ||
1479 | }; | ||
1480 | |||
1481 | static const struct driver_info dlink_dub_e100_info = { | ||
1482 | .description = "DLink DUB-E100 USB Ethernet", | ||
1483 | .bind = ax88172_bind, | ||
1484 | .status = asix_status, | ||
1485 | .link_reset = ax88172_link_reset, | ||
1486 | .reset = ax88172_link_reset, | ||
1487 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1488 | .data = 0x009f9d9f, | ||
1489 | }; | ||
1490 | |||
1491 | static const struct driver_info netgear_fa120_info = { | ||
1492 | .description = "Netgear FA-120 USB Ethernet", | ||
1493 | .bind = ax88172_bind, | ||
1494 | .status = asix_status, | ||
1495 | .link_reset = ax88172_link_reset, | ||
1496 | .reset = ax88172_link_reset, | ||
1497 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1498 | .data = 0x00130103, | ||
1499 | }; | ||
1500 | |||
1501 | static const struct driver_info hawking_uf200_info = { | ||
1502 | .description = "Hawking UF200 USB Ethernet", | ||
1503 | .bind = ax88172_bind, | ||
1504 | .status = asix_status, | ||
1505 | .link_reset = ax88172_link_reset, | ||
1506 | .reset = ax88172_link_reset, | ||
1507 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | ||
1508 | .data = 0x001f1d1f, | ||
1509 | }; | ||
1510 | |||
1511 | static const struct driver_info ax88772_info = { | ||
1512 | .description = "ASIX AX88772 USB 2.0 Ethernet", | ||
1513 | .bind = ax88772_bind, | ||
1514 | .status = asix_status, | ||
1515 | .link_reset = ax88772_link_reset, | ||
1516 | .reset = ax88772_reset, | ||
1517 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, | ||
1518 | .rx_fixup = asix_rx_fixup, | ||
1519 | .tx_fixup = asix_tx_fixup, | ||
1520 | }; | ||
1521 | |||
1522 | static const struct driver_info ax88178_info = { | ||
1523 | .description = "ASIX AX88178 USB 2.0 Ethernet", | ||
1524 | .bind = ax88178_bind, | ||
1525 | .status = asix_status, | ||
1526 | .link_reset = ax88178_link_reset, | ||
1527 | .reset = ax88178_reset, | ||
1528 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, | ||
1529 | .rx_fixup = asix_rx_fixup, | ||
1530 | .tx_fixup = asix_tx_fixup, | ||
1531 | }; | ||
1532 | |||
1533 | static const struct usb_device_id products [] = { | ||
1534 | { | ||
1535 | // Linksys USB200M | ||
1536 | USB_DEVICE (0x077b, 0x2226), | ||
1537 | .driver_info = (unsigned long) &ax8817x_info, | ||
1538 | }, { | ||
1539 | // Netgear FA120 | ||
1540 | USB_DEVICE (0x0846, 0x1040), | ||
1541 | .driver_info = (unsigned long) &netgear_fa120_info, | ||
1542 | }, { | ||
1543 | // DLink DUB-E100 | ||
1544 | USB_DEVICE (0x2001, 0x1a00), | ||
1545 | .driver_info = (unsigned long) &dlink_dub_e100_info, | ||
1546 | }, { | ||
1547 | // Intellinet, ST Lab USB Ethernet | ||
1548 | USB_DEVICE (0x0b95, 0x1720), | ||
1549 | .driver_info = (unsigned long) &ax8817x_info, | ||
1550 | }, { | ||
1551 | // Hawking UF200, TrendNet TU2-ET100 | ||
1552 | USB_DEVICE (0x07b8, 0x420a), | ||
1553 | .driver_info = (unsigned long) &hawking_uf200_info, | ||
1554 | }, { | ||
1555 | // Billionton Systems, USB2AR | ||
1556 | USB_DEVICE (0x08dd, 0x90ff), | ||
1557 | .driver_info = (unsigned long) &ax8817x_info, | ||
1558 | }, { | ||
1559 | // ATEN UC210T | ||
1560 | USB_DEVICE (0x0557, 0x2009), | ||
1561 | .driver_info = (unsigned long) &ax8817x_info, | ||
1562 | }, { | ||
1563 | // Buffalo LUA-U2-KTX | ||
1564 | USB_DEVICE (0x0411, 0x003d), | ||
1565 | .driver_info = (unsigned long) &ax8817x_info, | ||
1566 | }, { | ||
1567 | // Buffalo LUA-U2-GT 10/100/1000 | ||
1568 | USB_DEVICE (0x0411, 0x006e), | ||
1569 | .driver_info = (unsigned long) &ax88178_info, | ||
1570 | }, { | ||
1571 | // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" | ||
1572 | USB_DEVICE (0x6189, 0x182d), | ||
1573 | .driver_info = (unsigned long) &ax8817x_info, | ||
1574 | }, { | ||
1575 | // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" | ||
1576 | USB_DEVICE (0x0df6, 0x0056), | ||
1577 | .driver_info = (unsigned long) &ax88178_info, | ||
1578 | }, { | ||
1579 | // corega FEther USB2-TX | ||
1580 | USB_DEVICE (0x07aa, 0x0017), | ||
1581 | .driver_info = (unsigned long) &ax8817x_info, | ||
1582 | }, { | ||
1583 | // Surecom EP-1427X-2 | ||
1584 | USB_DEVICE (0x1189, 0x0893), | ||
1585 | .driver_info = (unsigned long) &ax8817x_info, | ||
1586 | }, { | ||
1587 | // goodway corp usb gwusb2e | ||
1588 | USB_DEVICE (0x1631, 0x6200), | ||
1589 | .driver_info = (unsigned long) &ax8817x_info, | ||
1590 | }, { | ||
1591 | // JVC MP-PRX1 Port Replicator | ||
1592 | USB_DEVICE (0x04f1, 0x3008), | ||
1593 | .driver_info = (unsigned long) &ax8817x_info, | ||
1594 | }, { | ||
1595 | // ASIX AX88772B 10/100 | ||
1596 | USB_DEVICE (0x0b95, 0x772b), | ||
1597 | .driver_info = (unsigned long) &ax88772_info, | ||
1598 | }, { | ||
1599 | // ASIX AX88772 10/100 | ||
1600 | USB_DEVICE (0x0b95, 0x7720), | ||
1601 | .driver_info = (unsigned long) &ax88772_info, | ||
1602 | }, { | ||
1603 | // ASIX AX88178 10/100/1000 | ||
1604 | USB_DEVICE (0x0b95, 0x1780), | ||
1605 | .driver_info = (unsigned long) &ax88178_info, | ||
1606 | }, { | ||
1607 | // Logitec LAN-GTJ/U2A | ||
1608 | USB_DEVICE (0x0789, 0x0160), | ||
1609 | .driver_info = (unsigned long) &ax88178_info, | ||
1610 | }, { | ||
1611 | // Linksys USB200M Rev 2 | ||
1612 | USB_DEVICE (0x13b1, 0x0018), | ||
1613 | .driver_info = (unsigned long) &ax88772_info, | ||
1614 | }, { | ||
1615 | // 0Q0 cable ethernet | ||
1616 | USB_DEVICE (0x1557, 0x7720), | ||
1617 | .driver_info = (unsigned long) &ax88772_info, | ||
1618 | }, { | ||
1619 | // DLink DUB-E100 H/W Ver B1 | ||
1620 | USB_DEVICE (0x07d1, 0x3c05), | ||
1621 | .driver_info = (unsigned long) &ax88772_info, | ||
1622 | }, { | ||
1623 | // DLink DUB-E100 H/W Ver B1 Alternate | ||
1624 | USB_DEVICE (0x2001, 0x3c05), | ||
1625 | .driver_info = (unsigned long) &ax88772_info, | ||
1626 | }, { | ||
1627 | // Linksys USB1000 | ||
1628 | USB_DEVICE (0x1737, 0x0039), | ||
1629 | .driver_info = (unsigned long) &ax88178_info, | ||
1630 | }, { | ||
1631 | // IO-DATA ETG-US2 | ||
1632 | USB_DEVICE (0x04bb, 0x0930), | ||
1633 | .driver_info = (unsigned long) &ax88178_info, | ||
1634 | }, { | ||
1635 | // Belkin F5D5055 | ||
1636 | USB_DEVICE(0x050d, 0x5055), | ||
1637 | .driver_info = (unsigned long) &ax88178_info, | ||
1638 | }, { | ||
1639 | // Apple USB Ethernet Adapter | ||
1640 | USB_DEVICE(0x05ac, 0x1402), | ||
1641 | .driver_info = (unsigned long) &ax88772_info, | ||
1642 | }, { | ||
1643 | // Cables-to-Go USB Ethernet Adapter | ||
1644 | USB_DEVICE(0x0b95, 0x772a), | ||
1645 | .driver_info = (unsigned long) &ax88772_info, | ||
1646 | }, { | ||
1647 | // ABOCOM for pci | ||
1648 | USB_DEVICE(0x14ea, 0xab11), | ||
1649 | .driver_info = (unsigned long) &ax88178_info, | ||
1650 | }, { | ||
1651 | // ASIX 88772a | ||
1652 | USB_DEVICE(0x0db0, 0xa877), | ||
1653 | .driver_info = (unsigned long) &ax88772_info, | ||
1654 | }, { | ||
1655 | // Asus USB Ethernet Adapter | ||
1656 | USB_DEVICE (0x0b95, 0x7e2b), | ||
1657 | .driver_info = (unsigned long) &ax88772_info, | ||
1658 | }, | ||
1659 | { }, // END | ||
1660 | }; | ||
1661 | MODULE_DEVICE_TABLE(usb, products); | ||
1662 | |||
1663 | static struct usb_driver asix_driver = { | ||
1664 | .name = DRIVER_NAME, | ||
1665 | .id_table = products, | ||
1666 | .probe = usbnet_probe, | ||
1667 | .suspend = usbnet_suspend, | ||
1668 | .resume = usbnet_resume, | ||
1669 | .disconnect = usbnet_disconnect, | ||
1670 | .supports_autosuspend = 1, | ||
1671 | .disable_hub_initiated_lpm = 1, | ||
1672 | }; | ||
1673 | |||
1674 | module_usb_driver(asix_driver); | ||
1675 | |||
1676 | MODULE_AUTHOR("David Hollis"); | ||
1677 | MODULE_VERSION(DRIVER_VERSION); | ||
1678 | MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); | ||
1679 | MODULE_LICENSE("GPL"); | ||
1680 | |||
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 6564c32d3af..8c513f7921f 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c | |||
@@ -20,137 +20,7 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | // #define DEBUG // error path messages, extra info | 23 | #include "asix.h" |
24 | // #define VERBOSE // more; success messages | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/kmod.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/usb.h> | ||
35 | #include <linux/crc32.h> | ||
36 | #include <linux/usb/usbnet.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/if_vlan.h> | ||
39 | |||
40 | #define DRIVER_VERSION "22-Dec-2011" | ||
41 | #define DRIVER_NAME "asix" | ||
42 | |||
43 | /* ASIX AX8817X based USB 2.0 Ethernet Devices */ | ||
44 | |||
45 | #define AX_CMD_SET_SW_MII 0x06 | ||
46 | #define AX_CMD_READ_MII_REG 0x07 | ||
47 | #define AX_CMD_WRITE_MII_REG 0x08 | ||
48 | #define AX_CMD_SET_HW_MII 0x0a | ||
49 | #define AX_CMD_READ_EEPROM 0x0b | ||
50 | #define AX_CMD_WRITE_EEPROM 0x0c | ||
51 | #define AX_CMD_WRITE_ENABLE 0x0d | ||
52 | #define AX_CMD_WRITE_DISABLE 0x0e | ||
53 | #define AX_CMD_READ_RX_CTL 0x0f | ||
54 | #define AX_CMD_WRITE_RX_CTL 0x10 | ||
55 | #define AX_CMD_READ_IPG012 0x11 | ||
56 | #define AX_CMD_WRITE_IPG0 0x12 | ||
57 | #define AX_CMD_WRITE_IPG1 0x13 | ||
58 | #define AX_CMD_READ_NODE_ID 0x13 | ||
59 | #define AX_CMD_WRITE_NODE_ID 0x14 | ||
60 | #define AX_CMD_WRITE_IPG2 0x14 | ||
61 | #define AX_CMD_WRITE_MULTI_FILTER 0x16 | ||
62 | #define AX88172_CMD_READ_NODE_ID 0x17 | ||
63 | #define AX_CMD_READ_PHY_ID 0x19 | ||
64 | #define AX_CMD_READ_MEDIUM_STATUS 0x1a | ||
65 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b | ||
66 | #define AX_CMD_READ_MONITOR_MODE 0x1c | ||
67 | #define AX_CMD_WRITE_MONITOR_MODE 0x1d | ||
68 | #define AX_CMD_READ_GPIOS 0x1e | ||
69 | #define AX_CMD_WRITE_GPIOS 0x1f | ||
70 | #define AX_CMD_SW_RESET 0x20 | ||
71 | #define AX_CMD_SW_PHY_STATUS 0x21 | ||
72 | #define AX_CMD_SW_PHY_SELECT 0x22 | ||
73 | |||
74 | #define AX_MONITOR_MODE 0x01 | ||
75 | #define AX_MONITOR_LINK 0x02 | ||
76 | #define AX_MONITOR_MAGIC 0x04 | ||
77 | #define AX_MONITOR_HSFS 0x10 | ||
78 | |||
79 | /* AX88172 Medium Status Register values */ | ||
80 | #define AX88172_MEDIUM_FD 0x02 | ||
81 | #define AX88172_MEDIUM_TX 0x04 | ||
82 | #define AX88172_MEDIUM_FC 0x10 | ||
83 | #define AX88172_MEDIUM_DEFAULT \ | ||
84 | ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) | ||
85 | |||
86 | #define AX_MCAST_FILTER_SIZE 8 | ||
87 | #define AX_MAX_MCAST 64 | ||
88 | |||
89 | #define AX_SWRESET_CLEAR 0x00 | ||
90 | #define AX_SWRESET_RR 0x01 | ||
91 | #define AX_SWRESET_RT 0x02 | ||
92 | #define AX_SWRESET_PRTE 0x04 | ||
93 | #define AX_SWRESET_PRL 0x08 | ||
94 | #define AX_SWRESET_BZ 0x10 | ||
95 | #define AX_SWRESET_IPRL 0x20 | ||
96 | #define AX_SWRESET_IPPD 0x40 | ||
97 | |||
98 | #define AX88772_IPG0_DEFAULT 0x15 | ||
99 | #define AX88772_IPG1_DEFAULT 0x0c | ||
100 | #define AX88772_IPG2_DEFAULT 0x12 | ||
101 | |||
102 | /* AX88772 & AX88178 Medium Mode Register */ | ||
103 | #define AX_MEDIUM_PF 0x0080 | ||
104 | #define AX_MEDIUM_JFE 0x0040 | ||
105 | #define AX_MEDIUM_TFC 0x0020 | ||
106 | #define AX_MEDIUM_RFC 0x0010 | ||
107 | #define AX_MEDIUM_ENCK 0x0008 | ||
108 | #define AX_MEDIUM_AC 0x0004 | ||
109 | #define AX_MEDIUM_FD 0x0002 | ||
110 | #define AX_MEDIUM_GM 0x0001 | ||
111 | #define AX_MEDIUM_SM 0x1000 | ||
112 | #define AX_MEDIUM_SBP 0x0800 | ||
113 | #define AX_MEDIUM_PS 0x0200 | ||
114 | #define AX_MEDIUM_RE 0x0100 | ||
115 | |||
116 | #define AX88178_MEDIUM_DEFAULT \ | ||
117 | (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ | ||
118 | AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ | ||
119 | AX_MEDIUM_RE) | ||
120 | |||
121 | #define AX88772_MEDIUM_DEFAULT \ | ||
122 | (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ | ||
123 | AX_MEDIUM_TFC | AX_MEDIUM_PS | \ | ||
124 | AX_MEDIUM_AC | AX_MEDIUM_RE) | ||
125 | |||
126 | /* AX88772 & AX88178 RX_CTL values */ | ||
127 | #define AX_RX_CTL_SO 0x0080 | ||
128 | #define AX_RX_CTL_AP 0x0020 | ||
129 | #define AX_RX_CTL_AM 0x0010 | ||
130 | #define AX_RX_CTL_AB 0x0008 | ||
131 | #define AX_RX_CTL_SEP 0x0004 | ||
132 | #define AX_RX_CTL_AMALL 0x0002 | ||
133 | #define AX_RX_CTL_PRO 0x0001 | ||
134 | #define AX_RX_CTL_MFB_2048 0x0000 | ||
135 | #define AX_RX_CTL_MFB_4096 0x0100 | ||
136 | #define AX_RX_CTL_MFB_8192 0x0200 | ||
137 | #define AX_RX_CTL_MFB_16384 0x0300 | ||
138 | |||
139 | #define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) | ||
140 | |||
141 | /* GPIO 0 .. 2 toggles */ | ||
142 | #define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ | ||
143 | #define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ | ||
144 | #define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ | ||
145 | #define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ | ||
146 | #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ | ||
147 | #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ | ||
148 | #define AX_GPIO_RESERVED 0x40 /* Reserved */ | ||
149 | #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ | ||
150 | |||
151 | #define AX_EEPROM_MAGIC 0xdeadbeef | ||
152 | #define AX88172_EEPROM_LEN 0x40 | ||
153 | #define AX88772_EEPROM_LEN 0xff | ||
154 | 24 | ||
155 | #define PHY_MODE_MARVELL 0x0000 | 25 | #define PHY_MODE_MARVELL 0x0000 |
156 | #define MII_MARVELL_LED_CTRL 0x0018 | 26 | #define MII_MARVELL_LED_CTRL 0x0018 |
@@ -166,15 +36,6 @@ | |||
166 | 36 | ||
167 | #define PHY_MODE_RTL8211CL 0x000C | 37 | #define PHY_MODE_RTL8211CL 0x000C |
168 | 38 | ||
169 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | ||
170 | struct asix_data { | ||
171 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; | ||
172 | u8 mac_addr[ETH_ALEN]; | ||
173 | u8 phymode; | ||
174 | u8 ledmode; | ||
175 | u8 eeprom_len; | ||
176 | }; | ||
177 | |||
178 | struct ax88172_int_data { | 39 | struct ax88172_int_data { |
179 | __le16 res1; | 40 | __le16 res1; |
180 | u8 link; | 41 | u8 link; |
@@ -183,225 +44,6 @@ struct ax88172_int_data { | |||
183 | __le16 res3; | 44 | __le16 res3; |
184 | } __packed; | 45 | } __packed; |
185 | 46 | ||
186 | static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
187 | u16 size, void *data) | ||
188 | { | ||
189 | void *buf; | ||
190 | int err = -ENOMEM; | ||
191 | |||
192 | netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
193 | cmd, value, index, size); | ||
194 | |||
195 | buf = kmalloc(size, GFP_KERNEL); | ||
196 | if (!buf) | ||
197 | goto out; | ||
198 | |||
199 | err = usb_control_msg( | ||
200 | dev->udev, | ||
201 | usb_rcvctrlpipe(dev->udev, 0), | ||
202 | cmd, | ||
203 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
204 | value, | ||
205 | index, | ||
206 | buf, | ||
207 | size, | ||
208 | USB_CTRL_GET_TIMEOUT); | ||
209 | if (err == size) | ||
210 | memcpy(data, buf, size); | ||
211 | else if (err >= 0) | ||
212 | err = -EINVAL; | ||
213 | kfree(buf); | ||
214 | |||
215 | out: | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
220 | u16 size, void *data) | ||
221 | { | ||
222 | void *buf = NULL; | ||
223 | int err = -ENOMEM; | ||
224 | |||
225 | netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
226 | cmd, value, index, size); | ||
227 | |||
228 | if (data) { | ||
229 | buf = kmemdup(data, size, GFP_KERNEL); | ||
230 | if (!buf) | ||
231 | goto out; | ||
232 | } | ||
233 | |||
234 | err = usb_control_msg( | ||
235 | dev->udev, | ||
236 | usb_sndctrlpipe(dev->udev, 0), | ||
237 | cmd, | ||
238 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
239 | value, | ||
240 | index, | ||
241 | buf, | ||
242 | size, | ||
243 | USB_CTRL_SET_TIMEOUT); | ||
244 | kfree(buf); | ||
245 | |||
246 | out: | ||
247 | return err; | ||
248 | } | ||
249 | |||
250 | static void asix_async_cmd_callback(struct urb *urb) | ||
251 | { | ||
252 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
253 | int status = urb->status; | ||
254 | |||
255 | if (status < 0) | ||
256 | printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", | ||
257 | status); | ||
258 | |||
259 | kfree(req); | ||
260 | usb_free_urb(urb); | ||
261 | } | ||
262 | |||
263 | static void | ||
264 | asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
265 | u16 size, void *data) | ||
266 | { | ||
267 | struct usb_ctrlrequest *req; | ||
268 | int status; | ||
269 | struct urb *urb; | ||
270 | |||
271 | netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
272 | cmd, value, index, size); | ||
273 | |||
274 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
275 | if (!urb) { | ||
276 | netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
281 | if (!req) { | ||
282 | netdev_err(dev->net, "Failed to allocate memory for control request\n"); | ||
283 | usb_free_urb(urb); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | ||
288 | req->bRequest = cmd; | ||
289 | req->wValue = cpu_to_le16(value); | ||
290 | req->wIndex = cpu_to_le16(index); | ||
291 | req->wLength = cpu_to_le16(size); | ||
292 | |||
293 | usb_fill_control_urb(urb, dev->udev, | ||
294 | usb_sndctrlpipe(dev->udev, 0), | ||
295 | (void *)req, data, size, | ||
296 | asix_async_cmd_callback, req); | ||
297 | |||
298 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
299 | if (status < 0) { | ||
300 | netdev_err(dev->net, "Error submitting the control message: status=%d\n", | ||
301 | status); | ||
302 | kfree(req); | ||
303 | usb_free_urb(urb); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
308 | { | ||
309 | int offset = 0; | ||
310 | |||
311 | while (offset + sizeof(u32) < skb->len) { | ||
312 | struct sk_buff *ax_skb; | ||
313 | u16 size; | ||
314 | u32 header = get_unaligned_le32(skb->data + offset); | ||
315 | |||
316 | offset += sizeof(u32); | ||
317 | |||
318 | /* get the packet length */ | ||
319 | size = (u16) (header & 0x7ff); | ||
320 | if (size != ((~header >> 16) & 0x07ff)) { | ||
321 | netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || | ||
326 | (size + offset > skb->len)) { | ||
327 | netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", | ||
328 | size); | ||
329 | return 0; | ||
330 | } | ||
331 | ax_skb = netdev_alloc_skb_ip_align(dev->net, size); | ||
332 | if (!ax_skb) | ||
333 | return 0; | ||
334 | |||
335 | skb_put(ax_skb, size); | ||
336 | memcpy(ax_skb->data, skb->data + offset, size); | ||
337 | usbnet_skb_return(dev, ax_skb); | ||
338 | |||
339 | offset += (size + 1) & 0xfffe; | ||
340 | } | ||
341 | |||
342 | if (skb->len != offset) { | ||
343 | netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", | ||
344 | skb->len); | ||
345 | return 0; | ||
346 | } | ||
347 | return 1; | ||
348 | } | ||
349 | |||
350 | static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
351 | gfp_t flags) | ||
352 | { | ||
353 | int padlen; | ||
354 | int headroom = skb_headroom(skb); | ||
355 | int tailroom = skb_tailroom(skb); | ||
356 | u32 packet_len; | ||
357 | u32 padbytes = 0xffff0000; | ||
358 | |||
359 | padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; | ||
360 | |||
361 | /* We need to push 4 bytes in front of frame (packet_len) | ||
362 | * and maybe add 4 bytes after the end (if padlen is 4) | ||
363 | * | ||
364 | * Avoid skb_copy_expand() expensive call, using following rules : | ||
365 | * - We are allowed to push 4 bytes in headroom if skb_header_cloned() | ||
366 | * is false (and if we have 4 bytes of headroom) | ||
367 | * - We are allowed to put 4 bytes at tail if skb_cloned() | ||
368 | * is false (and if we have 4 bytes of tailroom) | ||
369 | * | ||
370 | * TCP packets for example are cloned, but skb_header_release() | ||
371 | * was called in tcp stack, allowing us to use headroom for our needs. | ||
372 | */ | ||
373 | if (!skb_header_cloned(skb) && | ||
374 | !(padlen && skb_cloned(skb)) && | ||
375 | headroom + tailroom >= 4 + padlen) { | ||
376 | /* following should not happen, but better be safe */ | ||
377 | if (headroom < 4 || | ||
378 | tailroom < padlen) { | ||
379 | skb->data = memmove(skb->head + 4, skb->data, skb->len); | ||
380 | skb_set_tail_pointer(skb, skb->len); | ||
381 | } | ||
382 | } else { | ||
383 | struct sk_buff *skb2; | ||
384 | |||
385 | skb2 = skb_copy_expand(skb, 4, padlen, flags); | ||
386 | dev_kfree_skb_any(skb); | ||
387 | skb = skb2; | ||
388 | if (!skb) | ||
389 | return NULL; | ||
390 | } | ||
391 | |||
392 | packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; | ||
393 | skb_push(skb, 4); | ||
394 | cpu_to_le32s(&packet_len); | ||
395 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | ||
396 | |||
397 | if (padlen) { | ||
398 | cpu_to_le32s(&padbytes); | ||
399 | memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | ||
400 | skb_put(skb, sizeof(padbytes)); | ||
401 | } | ||
402 | return skb; | ||
403 | } | ||
404 | |||
405 | static void asix_status(struct usbnet *dev, struct urb *urb) | 47 | static void asix_status(struct usbnet *dev, struct urb *urb) |
406 | { | 48 | { |
407 | struct ax88172_int_data *event; | 49 | struct ax88172_int_data *event; |
@@ -422,200 +64,6 @@ static void asix_status(struct usbnet *dev, struct urb *urb) | |||
422 | } | 64 | } |
423 | } | 65 | } |
424 | 66 | ||
425 | static inline int asix_set_sw_mii(struct usbnet *dev) | ||
426 | { | ||
427 | int ret; | ||
428 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | ||
429 | if (ret < 0) | ||
430 | netdev_err(dev->net, "Failed to enable software MII access\n"); | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | static inline int asix_set_hw_mii(struct usbnet *dev) | ||
435 | { | ||
436 | int ret; | ||
437 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | ||
438 | if (ret < 0) | ||
439 | netdev_err(dev->net, "Failed to enable hardware MII access\n"); | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | static inline int asix_get_phy_addr(struct usbnet *dev) | ||
444 | { | ||
445 | u8 buf[2]; | ||
446 | int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); | ||
447 | |||
448 | netdev_dbg(dev->net, "asix_get_phy_addr()\n"); | ||
449 | |||
450 | if (ret < 0) { | ||
451 | netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); | ||
452 | goto out; | ||
453 | } | ||
454 | netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", | ||
455 | *((__le16 *)buf)); | ||
456 | ret = buf[1]; | ||
457 | |||
458 | out: | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | static int asix_sw_reset(struct usbnet *dev, u8 flags) | ||
463 | { | ||
464 | int ret; | ||
465 | |||
466 | ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); | ||
467 | if (ret < 0) | ||
468 | netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); | ||
469 | |||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | static u16 asix_read_rx_ctl(struct usbnet *dev) | ||
474 | { | ||
475 | __le16 v; | ||
476 | int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); | ||
477 | |||
478 | if (ret < 0) { | ||
479 | netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); | ||
480 | goto out; | ||
481 | } | ||
482 | ret = le16_to_cpu(v); | ||
483 | out: | ||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | ||
488 | { | ||
489 | int ret; | ||
490 | |||
491 | netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); | ||
492 | ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | ||
493 | if (ret < 0) | ||
494 | netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", | ||
495 | mode, ret); | ||
496 | |||
497 | return ret; | ||
498 | } | ||
499 | |||
500 | static u16 asix_read_medium_status(struct usbnet *dev) | ||
501 | { | ||
502 | __le16 v; | ||
503 | int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | ||
504 | |||
505 | if (ret < 0) { | ||
506 | netdev_err(dev->net, "Error reading Medium Status register: %02x\n", | ||
507 | ret); | ||
508 | return ret; /* TODO: callers not checking for error ret */ | ||
509 | } | ||
510 | |||
511 | return le16_to_cpu(v); | ||
512 | |||
513 | } | ||
514 | |||
515 | static int asix_write_medium_mode(struct usbnet *dev, u16 mode) | ||
516 | { | ||
517 | int ret; | ||
518 | |||
519 | netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); | ||
520 | ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
521 | if (ret < 0) | ||
522 | netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", | ||
523 | mode, ret); | ||
524 | |||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | ||
529 | { | ||
530 | int ret; | ||
531 | |||
532 | netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); | ||
533 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); | ||
534 | if (ret < 0) | ||
535 | netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", | ||
536 | value, ret); | ||
537 | |||
538 | if (sleep) | ||
539 | msleep(sleep); | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * AX88772 & AX88178 have a 16-bit RX_CTL value | ||
546 | */ | ||
547 | static void asix_set_multicast(struct net_device *net) | ||
548 | { | ||
549 | struct usbnet *dev = netdev_priv(net); | ||
550 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
551 | u16 rx_ctl = AX_DEFAULT_RX_CTL; | ||
552 | |||
553 | if (net->flags & IFF_PROMISC) { | ||
554 | rx_ctl |= AX_RX_CTL_PRO; | ||
555 | } else if (net->flags & IFF_ALLMULTI || | ||
556 | netdev_mc_count(net) > AX_MAX_MCAST) { | ||
557 | rx_ctl |= AX_RX_CTL_AMALL; | ||
558 | } else if (netdev_mc_empty(net)) { | ||
559 | /* just broadcast and directed */ | ||
560 | } else { | ||
561 | /* We use the 20 byte dev->data | ||
562 | * for our 8 byte filter buffer | ||
563 | * to avoid allocating memory that | ||
564 | * is tricky to free later */ | ||
565 | struct netdev_hw_addr *ha; | ||
566 | u32 crc_bits; | ||
567 | |||
568 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
569 | |||
570 | /* Build the multicast hash filter. */ | ||
571 | netdev_for_each_mc_addr(ha, net) { | ||
572 | crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | ||
573 | data->multi_filter[crc_bits >> 3] |= | ||
574 | 1 << (crc_bits & 7); | ||
575 | } | ||
576 | |||
577 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
578 | AX_MCAST_FILTER_SIZE, data->multi_filter); | ||
579 | |||
580 | rx_ctl |= AX_RX_CTL_AM; | ||
581 | } | ||
582 | |||
583 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
584 | } | ||
585 | |||
586 | static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | ||
587 | { | ||
588 | struct usbnet *dev = netdev_priv(netdev); | ||
589 | __le16 res; | ||
590 | |||
591 | mutex_lock(&dev->phy_mutex); | ||
592 | asix_set_sw_mii(dev); | ||
593 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, | ||
594 | (__u16)loc, 2, &res); | ||
595 | asix_set_hw_mii(dev); | ||
596 | mutex_unlock(&dev->phy_mutex); | ||
597 | |||
598 | netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | ||
599 | phy_id, loc, le16_to_cpu(res)); | ||
600 | |||
601 | return le16_to_cpu(res); | ||
602 | } | ||
603 | |||
604 | static void | ||
605 | asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | ||
606 | { | ||
607 | struct usbnet *dev = netdev_priv(netdev); | ||
608 | __le16 res = cpu_to_le16(val); | ||
609 | |||
610 | netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | ||
611 | phy_id, loc, val); | ||
612 | mutex_lock(&dev->phy_mutex); | ||
613 | asix_set_sw_mii(dev); | ||
614 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); | ||
615 | asix_set_hw_mii(dev); | ||
616 | mutex_unlock(&dev->phy_mutex); | ||
617 | } | ||
618 | |||
619 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | 67 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ |
620 | static u32 asix_get_phyid(struct usbnet *dev) | 68 | static u32 asix_get_phyid(struct usbnet *dev) |
621 | { | 69 | { |
@@ -645,88 +93,6 @@ static u32 asix_get_phyid(struct usbnet *dev) | |||
645 | return phy_id; | 93 | return phy_id; |
646 | } | 94 | } |
647 | 95 | ||
648 | static void | ||
649 | asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
650 | { | ||
651 | struct usbnet *dev = netdev_priv(net); | ||
652 | u8 opt; | ||
653 | |||
654 | if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | ||
655 | wolinfo->supported = 0; | ||
656 | wolinfo->wolopts = 0; | ||
657 | return; | ||
658 | } | ||
659 | wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | ||
660 | wolinfo->wolopts = 0; | ||
661 | if (opt & AX_MONITOR_LINK) | ||
662 | wolinfo->wolopts |= WAKE_PHY; | ||
663 | if (opt & AX_MONITOR_MAGIC) | ||
664 | wolinfo->wolopts |= WAKE_MAGIC; | ||
665 | } | ||
666 | |||
667 | static int | ||
668 | asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
669 | { | ||
670 | struct usbnet *dev = netdev_priv(net); | ||
671 | u8 opt = 0; | ||
672 | |||
673 | if (wolinfo->wolopts & WAKE_PHY) | ||
674 | opt |= AX_MONITOR_LINK; | ||
675 | if (wolinfo->wolopts & WAKE_MAGIC) | ||
676 | opt |= AX_MONITOR_MAGIC; | ||
677 | |||
678 | if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, | ||
679 | opt, 0, 0, NULL) < 0) | ||
680 | return -EINVAL; | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static int asix_get_eeprom_len(struct net_device *net) | ||
686 | { | ||
687 | struct usbnet *dev = netdev_priv(net); | ||
688 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
689 | |||
690 | return data->eeprom_len; | ||
691 | } | ||
692 | |||
693 | static int asix_get_eeprom(struct net_device *net, | ||
694 | struct ethtool_eeprom *eeprom, u8 *data) | ||
695 | { | ||
696 | struct usbnet *dev = netdev_priv(net); | ||
697 | __le16 *ebuf = (__le16 *)data; | ||
698 | int i; | ||
699 | |||
700 | /* Crude hack to ensure that we don't overwrite memory | ||
701 | * if an odd length is supplied | ||
702 | */ | ||
703 | if (eeprom->len % 2) | ||
704 | return -EINVAL; | ||
705 | |||
706 | eeprom->magic = AX_EEPROM_MAGIC; | ||
707 | |||
708 | /* ax8817x returns 2 bytes from eeprom on read */ | ||
709 | for (i=0; i < eeprom->len / 2; i++) { | ||
710 | if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, | ||
711 | eeprom->offset + i, 0, 2, &ebuf[i]) < 0) | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static void asix_get_drvinfo (struct net_device *net, | ||
718 | struct ethtool_drvinfo *info) | ||
719 | { | ||
720 | struct usbnet *dev = netdev_priv(net); | ||
721 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
722 | |||
723 | /* Inherit standard device info */ | ||
724 | usbnet_get_drvinfo(net, info); | ||
725 | strncpy (info->driver, DRIVER_NAME, sizeof info->driver); | ||
726 | strncpy (info->version, DRIVER_VERSION, sizeof info->version); | ||
727 | info->eedump_len = data->eeprom_len; | ||
728 | } | ||
729 | |||
730 | static u32 asix_get_link(struct net_device *net) | 96 | static u32 asix_get_link(struct net_device *net) |
731 | { | 97 | { |
732 | struct usbnet *dev = netdev_priv(net); | 98 | struct usbnet *dev = netdev_priv(net); |
@@ -741,30 +107,6 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) | |||
741 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | 107 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); |
742 | } | 108 | } |
743 | 109 | ||
744 | static int asix_set_mac_address(struct net_device *net, void *p) | ||
745 | { | ||
746 | struct usbnet *dev = netdev_priv(net); | ||
747 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
748 | struct sockaddr *addr = p; | ||
749 | |||
750 | if (netif_running(net)) | ||
751 | return -EBUSY; | ||
752 | if (!is_valid_ether_addr(addr->sa_data)) | ||
753 | return -EADDRNOTAVAIL; | ||
754 | |||
755 | memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | ||
756 | |||
757 | /* We use the 20 byte dev->data | ||
758 | * for our 6 byte mac buffer | ||
759 | * to avoid allocating memory that | ||
760 | * is tricky to free later */ | ||
761 | memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); | ||
762 | asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
763 | data->mac_addr); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | /* We need to override some ethtool_ops so we require our | 110 | /* We need to override some ethtool_ops so we require our |
769 | own structure so we don't interfere with other usbnet | 111 | own structure so we don't interfere with other usbnet |
770 | devices that may be connected at the same time. */ | 112 | devices that may be connected at the same time. */ |