diff options
-rw-r--r-- | drivers/usb/net/usbnet.c | 261 |
1 files changed, 135 insertions, 126 deletions
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index bbaef047d532..0eefc14449aa 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c | |||
@@ -210,6 +210,7 @@ struct usbnet { | |||
210 | # define EVENT_RX_HALT 1 | 210 | # define EVENT_RX_HALT 1 |
211 | # define EVENT_RX_MEMORY 2 | 211 | # define EVENT_RX_MEMORY 2 |
212 | # define EVENT_STS_SPLIT 3 | 212 | # define EVENT_STS_SPLIT 3 |
213 | # define EVENT_LINK_RESET 4 | ||
213 | }; | 214 | }; |
214 | 215 | ||
215 | // device-specific info used by the driver | 216 | // device-specific info used by the driver |
@@ -243,6 +244,9 @@ struct driver_info { | |||
243 | /* for status polling */ | 244 | /* for status polling */ |
244 | void (*status)(struct usbnet *, struct urb *); | 245 | void (*status)(struct usbnet *, struct urb *); |
245 | 246 | ||
247 | /* link reset handling, called from defer_kevent */ | ||
248 | int (*link_reset)(struct usbnet *); | ||
249 | |||
246 | /* fixup rx packet (strip framing) */ | 250 | /* fixup rx packet (strip framing) */ |
247 | int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); | 251 | int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); |
248 | 252 | ||
@@ -304,6 +308,7 @@ static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); | |||
304 | static u32 usbnet_get_link (struct net_device *); | 308 | static u32 usbnet_get_link (struct net_device *); |
305 | static u32 usbnet_get_msglevel (struct net_device *); | 309 | static u32 usbnet_get_msglevel (struct net_device *); |
306 | static void usbnet_set_msglevel (struct net_device *, u32); | 310 | static void usbnet_set_msglevel (struct net_device *, u32); |
311 | static void defer_kevent (struct usbnet *, int); | ||
307 | 312 | ||
308 | /* mostly for PDA style devices, which are always connected if present */ | 313 | /* mostly for PDA style devices, which are always connected if present */ |
309 | static int always_connected (struct usbnet *dev) | 314 | static int always_connected (struct usbnet *dev) |
@@ -501,6 +506,7 @@ static const struct driver_info an2720_info = { | |||
501 | #define AX_CMD_WRITE_MULTI_FILTER 0x16 | 506 | #define AX_CMD_WRITE_MULTI_FILTER 0x16 |
502 | #define AX_CMD_READ_NODE_ID 0x17 | 507 | #define AX_CMD_READ_NODE_ID 0x17 |
503 | #define AX_CMD_READ_PHY_ID 0x19 | 508 | #define AX_CMD_READ_PHY_ID 0x19 |
509 | #define AX_CMD_READ_MEDIUM_STATUS 0x1a | ||
504 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b | 510 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b |
505 | #define AX_CMD_READ_MONITOR_MODE 0x1c | 511 | #define AX_CMD_READ_MONITOR_MODE 0x1c |
506 | #define AX_CMD_WRITE_MONITOR_MODE 0x1d | 512 | #define AX_CMD_WRITE_MONITOR_MODE 0x1d |
@@ -515,11 +521,14 @@ static const struct driver_info an2720_info = { | |||
515 | #define AX_MONITOR_MAGIC 0x04 | 521 | #define AX_MONITOR_MAGIC 0x04 |
516 | #define AX_MONITOR_HSFS 0x10 | 522 | #define AX_MONITOR_HSFS 0x10 |
517 | 523 | ||
524 | /* AX88172 Medium Status Register values */ | ||
525 | #define AX_MEDIUM_FULL_DUPLEX 0x02 | ||
526 | #define AX_MEDIUM_TX_ABORT_ALLOW 0x04 | ||
527 | #define AX_MEDIUM_FLOW_CONTROL_EN 0x10 | ||
528 | |||
518 | #define AX_MCAST_FILTER_SIZE 8 | 529 | #define AX_MCAST_FILTER_SIZE 8 |
519 | #define AX_MAX_MCAST 64 | 530 | #define AX_MAX_MCAST 64 |
520 | 531 | ||
521 | #define AX_INTERRUPT_BUFSIZE 8 | ||
522 | |||
523 | #define AX_EEPROM_LEN 0x40 | 532 | #define AX_EEPROM_LEN 0x40 |
524 | 533 | ||
525 | #define AX_SWRESET_CLEAR 0x00 | 534 | #define AX_SWRESET_CLEAR 0x00 |
@@ -535,15 +544,33 @@ static const struct driver_info an2720_info = { | |||
535 | #define AX88772_IPG1_DEFAULT 0x0c | 544 | #define AX88772_IPG1_DEFAULT 0x0c |
536 | #define AX88772_IPG2_DEFAULT 0x12 | 545 | #define AX88772_IPG2_DEFAULT 0x12 |
537 | 546 | ||
547 | #define AX88772_MEDIUM_FULL_DUPLEX 0x0002 | ||
548 | #define AX88772_MEDIUM_RESERVED 0x0004 | ||
549 | #define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 | ||
550 | #define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 | ||
551 | #define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 | ||
552 | #define AX88772_MEDIUM_RX_ENABLE 0x0100 | ||
553 | #define AX88772_MEDIUM_100MB 0x0200 | ||
554 | #define AX88772_MEDIUM_DEFAULT \ | ||
555 | (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ | ||
556 | AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ | ||
557 | AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE ) | ||
558 | |||
538 | #define AX_EEPROM_MAGIC 0xdeadbeef | 559 | #define AX_EEPROM_MAGIC 0xdeadbeef |
539 | 560 | ||
540 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | 561 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ |
541 | struct ax8817x_data { | 562 | struct ax8817x_data { |
542 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; | 563 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; |
543 | struct urb *int_urb; | ||
544 | u8 *int_buf; | ||
545 | }; | 564 | }; |
546 | 565 | ||
566 | struct ax88172_int_data { | ||
567 | u16 res1; | ||
568 | u8 link; | ||
569 | u16 res2; | ||
570 | u8 status; | ||
571 | u16 res3; | ||
572 | } __attribute__ ((packed)); | ||
573 | |||
547 | static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | 574 | static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
548 | u16 size, void *data) | 575 | u16 size, void *data) |
549 | { | 576 | { |
@@ -586,25 +613,23 @@ static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) | |||
586 | usb_free_urb(urb); | 613 | usb_free_urb(urb); |
587 | } | 614 | } |
588 | 615 | ||
589 | static void ax8817x_interrupt_complete(struct urb *urb, struct pt_regs *regs) | 616 | static void ax8817x_status(struct usbnet *dev, struct urb *urb) |
590 | { | 617 | { |
591 | struct usbnet *dev = (struct usbnet *)urb->context; | 618 | struct ax88172_int_data *event; |
592 | struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; | ||
593 | int link; | 619 | int link; |
594 | 620 | ||
595 | if (urb->status < 0) { | 621 | if (urb->actual_length < 8) |
596 | devdbg(dev,"ax8817x_interrupt_complete() failed with %d", | 622 | return; |
597 | urb->status); | 623 | |
598 | } else { | 624 | event = urb->transfer_buffer; |
599 | link = data->int_buf[2] & 0x01; | 625 | link = event->link & 0x01; |
600 | if (netif_carrier_ok(dev->net) != link) { | 626 | if (netif_carrier_ok(dev->net) != link) { |
601 | if (link) | 627 | if (link) { |
602 | netif_carrier_on(dev->net); | 628 | netif_carrier_on(dev->net); |
603 | else | 629 | defer_kevent (dev, EVENT_LINK_RESET ); |
604 | netif_carrier_off(dev->net); | 630 | } else |
605 | devdbg(dev, "ax8817x - Link Status is: %d", link); | 631 | netif_carrier_off(dev->net); |
606 | } | 632 | devdbg(dev, "ax8817x - Link Status is: %d", link); |
607 | usb_submit_urb(data->int_urb, GFP_ATOMIC); | ||
608 | } | 633 | } |
609 | } | 634 | } |
610 | 635 | ||
@@ -711,6 +736,20 @@ static void ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, i | |||
711 | ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); | 736 | ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); |
712 | } | 737 | } |
713 | 738 | ||
739 | static int ax88172_link_reset(struct usbnet *dev) | ||
740 | { | ||
741 | u16 lpa; | ||
742 | u8 mode; | ||
743 | |||
744 | mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; | ||
745 | lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); | ||
746 | if (lpa & LPA_DUPLEX) | ||
747 | mode |= AX_MEDIUM_FULL_DUPLEX; | ||
748 | ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
714 | static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | 753 | static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) |
715 | { | 754 | { |
716 | struct usbnet *dev = netdev_priv(net); | 755 | struct usbnet *dev = netdev_priv(net); |
@@ -824,35 +863,13 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) | |||
824 | void *buf; | 863 | void *buf; |
825 | int i; | 864 | int i; |
826 | unsigned long gpio_bits = dev->driver_info->data; | 865 | unsigned long gpio_bits = dev->driver_info->data; |
827 | struct ax8817x_data *data = (struct ax8817x_data *)dev->data; | ||
828 | 866 | ||
829 | get_endpoints(dev,intf); | 867 | get_endpoints(dev,intf); |
830 | 868 | ||
831 | if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == NULL) { | ||
832 | dbg ("%s: cannot allocate interrupt URB", | ||
833 | dev->net->name); | ||
834 | ret = -ENOMEM; | ||
835 | goto out1; | ||
836 | } | ||
837 | |||
838 | if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) { | ||
839 | dbg ("%s: cannot allocate memory for interrupt buffer", | ||
840 | dev->net->name); | ||
841 | ret = -ENOMEM; | ||
842 | goto out1; | ||
843 | } | ||
844 | memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE); | ||
845 | |||
846 | usb_fill_int_urb (data->int_urb, dev->udev, | ||
847 | usb_rcvintpipe (dev->udev, 1), | ||
848 | data->int_buf, AX_INTERRUPT_BUFSIZE, | ||
849 | ax8817x_interrupt_complete, dev, | ||
850 | dev->udev->speed == USB_SPEED_HIGH ? 8 : 100); | ||
851 | |||
852 | buf = kmalloc(ETH_ALEN, GFP_KERNEL); | 869 | buf = kmalloc(ETH_ALEN, GFP_KERNEL); |
853 | if(!buf) { | 870 | if(!buf) { |
854 | ret = -ENOMEM; | 871 | ret = -ENOMEM; |
855 | goto out2; | 872 | goto out1; |
856 | } | 873 | } |
857 | 874 | ||
858 | /* Toggle the GPIOs in a manufacturer/model specific way */ | 875 | /* Toggle the GPIOs in a manufacturer/model specific way */ |
@@ -860,32 +877,32 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) | |||
860 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, | 877 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
861 | (gpio_bits >> (i * 8)) & 0xff, 0, 0, | 878 | (gpio_bits >> (i * 8)) & 0xff, 0, 0, |
862 | buf)) < 0) | 879 | buf)) < 0) |
863 | goto out3; | 880 | goto out2; |
864 | msleep(5); | 881 | msleep(5); |
865 | } | 882 | } |
866 | 883 | ||
867 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) { | 884 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) { |
868 | dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); | 885 | dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); |
869 | goto out3; | 886 | goto out2; |
870 | } | 887 | } |
871 | 888 | ||
872 | /* Get the MAC address */ | 889 | /* Get the MAC address */ |
873 | memset(buf, 0, ETH_ALEN); | 890 | memset(buf, 0, ETH_ALEN); |
874 | if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { | 891 | if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { |
875 | dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); | 892 | dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); |
876 | goto out3; | 893 | goto out2; |
877 | } | 894 | } |
878 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | 895 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); |
879 | 896 | ||
880 | /* Get the PHY id */ | 897 | /* Get the PHY id */ |
881 | if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { | 898 | if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { |
882 | dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); | 899 | dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); |
883 | goto out3; | 900 | goto out2; |
884 | } else if (ret < 2) { | 901 | } else if (ret < 2) { |
885 | /* this should always return 2 bytes */ | 902 | /* this should always return 2 bytes */ |
886 | dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); | 903 | dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); |
887 | ret = -EIO; | 904 | ret = -EIO; |
888 | goto out3; | 905 | goto out2; |
889 | } | 906 | } |
890 | 907 | ||
891 | /* Initialize MII structure */ | 908 | /* Initialize MII structure */ |
@@ -899,36 +916,18 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) | |||
899 | dev->net->set_multicast_list = ax8817x_set_multicast; | 916 | dev->net->set_multicast_list = ax8817x_set_multicast; |
900 | dev->net->ethtool_ops = &ax8817x_ethtool_ops; | 917 | dev->net->ethtool_ops = &ax8817x_ethtool_ops; |
901 | 918 | ||
902 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, | 919 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
903 | cpu_to_le16(BMCR_RESET)); | ||
904 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | 920 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
905 | cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400)); | 921 | ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
906 | mii_nway_restart(&dev->mii); | 922 | mii_nway_restart(&dev->mii); |
907 | 923 | ||
908 | if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) { | ||
909 | dbg("Failed to submit interrupt URB: %02x", ret); | ||
910 | goto out2; | ||
911 | } | ||
912 | |||
913 | return 0; | 924 | return 0; |
914 | out3: | ||
915 | kfree(buf); | ||
916 | out2: | 925 | out2: |
917 | kfree(data->int_buf); | 926 | kfree(buf); |
918 | out1: | 927 | out1: |
919 | usb_free_urb(data->int_urb); | ||
920 | return ret; | 928 | return ret; |
921 | } | 929 | } |
922 | 930 | ||
923 | static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
924 | { | ||
925 | struct ax8817x_data *data = (struct ax8817x_data *)dev->data; | ||
926 | |||
927 | usb_kill_urb(data->int_urb); | ||
928 | usb_free_urb(data->int_urb); | ||
929 | kfree(data->int_buf); | ||
930 | } | ||
931 | |||
932 | static struct ethtool_ops ax88772_ethtool_ops = { | 931 | static struct ethtool_ops ax88772_ethtool_ops = { |
933 | .get_drvinfo = ax8817x_get_drvinfo, | 932 | .get_drvinfo = ax8817x_get_drvinfo, |
934 | .get_link = ethtool_op_get_link, | 933 | .get_link = ethtool_op_get_link, |
@@ -946,64 +945,44 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
946 | { | 945 | { |
947 | int ret; | 946 | int ret; |
948 | void *buf; | 947 | void *buf; |
949 | struct ax8817x_data *data = (struct ax8817x_data *)dev->data; | ||
950 | 948 | ||
951 | get_endpoints(dev,intf); | 949 | get_endpoints(dev,intf); |
952 | 950 | ||
953 | if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) { | ||
954 | dbg ("Cannot allocate interrupt URB"); | ||
955 | ret = -ENOMEM; | ||
956 | goto out1; | ||
957 | } | ||
958 | |||
959 | if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) { | ||
960 | dbg ("Cannot allocate memory for interrupt buffer"); | ||
961 | ret = -ENOMEM; | ||
962 | goto out1; | ||
963 | } | ||
964 | memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE); | ||
965 | |||
966 | usb_fill_int_urb (data->int_urb, dev->udev, | ||
967 | usb_rcvintpipe (dev->udev, 1), | ||
968 | data->int_buf, AX_INTERRUPT_BUFSIZE, | ||
969 | ax8817x_interrupt_complete, dev, | ||
970 | dev->udev->speed == USB_SPEED_HIGH ? 8 : 100); | ||
971 | |||
972 | buf = kmalloc(6, GFP_KERNEL); | 951 | buf = kmalloc(6, GFP_KERNEL); |
973 | if(!buf) { | 952 | if(!buf) { |
974 | dbg ("Cannot allocate memory for buffer"); | 953 | dbg ("Cannot allocate memory for buffer"); |
975 | ret = -ENOMEM; | 954 | ret = -ENOMEM; |
976 | goto out2; | 955 | goto out1; |
977 | } | 956 | } |
978 | 957 | ||
979 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, | 958 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
980 | 0x00B0, 0, 0, buf)) < 0) | 959 | 0x00B0, 0, 0, buf)) < 0) |
981 | goto out3; | 960 | goto out2; |
982 | 961 | ||
983 | msleep(5); | 962 | msleep(5); |
984 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { | 963 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { |
985 | dbg("Select PHY #1 failed: %d", ret); | 964 | dbg("Select PHY #1 failed: %d", ret); |
986 | goto out3; | 965 | goto out2; |
987 | } | 966 | } |
988 | 967 | ||
989 | if ((ret = | 968 | if ((ret = |
990 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) { | 969 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) { |
991 | dbg("Failed to power down internal PHY: %d", ret); | 970 | dbg("Failed to power down internal PHY: %d", ret); |
992 | goto out3; | 971 | goto out2; |
993 | } | 972 | } |
994 | 973 | ||
995 | msleep(150); | 974 | msleep(150); |
996 | if ((ret = | 975 | if ((ret = |
997 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) { | 976 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) { |
998 | dbg("Failed to perform software reset: %d", ret); | 977 | dbg("Failed to perform software reset: %d", ret); |
999 | goto out3; | 978 | goto out2; |
1000 | } | 979 | } |
1001 | 980 | ||
1002 | msleep(150); | 981 | msleep(150); |
1003 | if ((ret = | 982 | if ((ret = |
1004 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { | 983 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { |
1005 | dbg("Failed to set Internal/External PHY reset control: %d", ret); | 984 | dbg("Failed to set Internal/External PHY reset control: %d", ret); |
1006 | goto out3; | 985 | goto out2; |
1007 | } | 986 | } |
1008 | 987 | ||
1009 | msleep(150); | 988 | msleep(150); |
@@ -1011,27 +990,27 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1011 | ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0, | 990 | ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0, |
1012 | buf)) < 0) { | 991 | buf)) < 0) { |
1013 | dbg("Failed to reset RX_CTL: %d", ret); | 992 | dbg("Failed to reset RX_CTL: %d", ret); |
1014 | goto out3; | 993 | goto out2; |
1015 | } | 994 | } |
1016 | 995 | ||
1017 | /* Get the MAC address */ | 996 | /* Get the MAC address */ |
1018 | memset(buf, 0, ETH_ALEN); | 997 | memset(buf, 0, ETH_ALEN); |
1019 | if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { | 998 | if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { |
1020 | dbg("Failed to read MAC address: %d", ret); | 999 | dbg("Failed to read MAC address: %d", ret); |
1021 | goto out3; | 1000 | goto out2; |
1022 | } | 1001 | } |
1023 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | 1002 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); |
1024 | 1003 | ||
1025 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) { | 1004 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) { |
1026 | dbg("Enabling software MII failed: %d", ret); | 1005 | dbg("Enabling software MII failed: %d", ret); |
1027 | goto out3; | 1006 | goto out2; |
1028 | } | 1007 | } |
1029 | 1008 | ||
1030 | if (((ret = | 1009 | if (((ret = |
1031 | ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) | 1010 | ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) |
1032 | || (*((u16 *)buf) != 0x003b)) { | 1011 | || (*((u16 *)buf) != 0x003b)) { |
1033 | dbg("Read PHY register 2 must be 0x3b00: %d", ret); | 1012 | dbg("Read PHY register 2 must be 0x3b00: %d", ret); |
1034 | goto out3; | 1013 | goto out2; |
1035 | } | 1014 | } |
1036 | 1015 | ||
1037 | /* Initialize MII structure */ | 1016 | /* Initialize MII structure */ |
@@ -1044,26 +1023,26 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1044 | /* Get the PHY id */ | 1023 | /* Get the PHY id */ |
1045 | if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { | 1024 | if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { |
1046 | dbg("Error reading PHY ID: %02x", ret); | 1025 | dbg("Error reading PHY ID: %02x", ret); |
1047 | goto out3; | 1026 | goto out2; |
1048 | } else if (ret < 2) { | 1027 | } else if (ret < 2) { |
1049 | /* this should always return 2 bytes */ | 1028 | /* this should always return 2 bytes */ |
1050 | dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", | 1029 | dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", |
1051 | ret); | 1030 | ret); |
1052 | ret = -EIO; | 1031 | ret = -EIO; |
1053 | goto out3; | 1032 | goto out2; |
1054 | } | 1033 | } |
1055 | dev->mii.phy_id = *((u8 *)buf + 1); | 1034 | dev->mii.phy_id = *((u8 *)buf + 1); |
1056 | 1035 | ||
1057 | if ((ret = | 1036 | if ((ret = |
1058 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) { | 1037 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) { |
1059 | dbg("Set external PHY reset pin level: %d", ret); | 1038 | dbg("Set external PHY reset pin level: %d", ret); |
1060 | goto out3; | 1039 | goto out2; |
1061 | } | 1040 | } |
1062 | msleep(150); | 1041 | msleep(150); |
1063 | if ((ret = | 1042 | if ((ret = |
1064 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { | 1043 | ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { |
1065 | dbg("Set Internal/External PHY reset control: %d", ret); | 1044 | dbg("Set Internal/External PHY reset control: %d", ret); |
1066 | goto out3; | 1045 | goto out2; |
1067 | } | 1046 | } |
1068 | msleep(150); | 1047 | msleep(150); |
1069 | 1048 | ||
@@ -1071,25 +1050,24 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1071 | dev->net->set_multicast_list = ax8817x_set_multicast; | 1050 | dev->net->set_multicast_list = ax8817x_set_multicast; |
1072 | dev->net->ethtool_ops = &ax88772_ethtool_ops; | 1051 | dev->net->ethtool_ops = &ax88772_ethtool_ops; |
1073 | 1052 | ||
1074 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, | 1053 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
1075 | cpu_to_le16(BMCR_RESET)); | ||
1076 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | 1054 | ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
1077 | cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA)); | 1055 | ADVERTISE_ALL | ADVERTISE_CSMA); |
1078 | mii_nway_restart(&dev->mii); | 1056 | mii_nway_restart(&dev->mii); |
1079 | 1057 | ||
1080 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, 0x0336, 0, 0, buf)) < 0) { | 1058 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { |
1081 | dbg("Write medium mode register: %d", ret); | 1059 | dbg("Write medium mode register: %d", ret); |
1082 | goto out3; | 1060 | goto out2; |
1083 | } | 1061 | } |
1084 | 1062 | ||
1085 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) { | 1063 | if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) { |
1086 | dbg("Write IPG,IPG1,IPG2 failed: %d", ret); | 1064 | dbg("Write IPG,IPG1,IPG2 failed: %d", ret); |
1087 | goto out3; | 1065 | goto out2; |
1088 | } | 1066 | } |
1089 | if ((ret = | 1067 | if ((ret = |
1090 | ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { | 1068 | ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { |
1091 | dbg("Failed to set hardware MII: %02x", ret); | 1069 | dbg("Failed to set hardware MII: %02x", ret); |
1092 | goto out3; | 1070 | goto out2; |
1093 | } | 1071 | } |
1094 | 1072 | ||
1095 | /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | 1073 | /* Set RX_CTL to default values with 2k buffer, and enable cactus */ |
@@ -1097,25 +1075,16 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1097 | ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, | 1075 | ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, |
1098 | buf)) < 0) { | 1076 | buf)) < 0) { |
1099 | dbg("Reset RX_CTL failed: %d", ret); | 1077 | dbg("Reset RX_CTL failed: %d", ret); |
1100 | goto out3; | 1078 | goto out2; |
1101 | } | ||
1102 | |||
1103 | if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) { | ||
1104 | dbg("Failed to submit interrupt URB: %02x", ret); | ||
1105 | goto out3; | ||
1106 | } | 1079 | } |
1107 | 1080 | ||
1108 | kfree(buf); | 1081 | kfree(buf); |
1109 | 1082 | ||
1110 | return 0; | 1083 | return 0; |
1111 | 1084 | ||
1112 | out3: | ||
1113 | kfree(buf); | ||
1114 | out2: | 1085 | out2: |
1115 | kfree(data->int_buf); | 1086 | kfree(buf); |
1116 | out1: | 1087 | out1: |
1117 | usb_free_urb(data->int_urb); | ||
1118 | |||
1119 | return ret; | 1088 | return ret; |
1120 | } | 1089 | } |
1121 | 1090 | ||
@@ -1213,10 +1182,29 @@ static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |||
1213 | return skb; | 1182 | return skb; |
1214 | } | 1183 | } |
1215 | 1184 | ||
1185 | static int ax88772_link_reset(struct usbnet *dev) | ||
1186 | { | ||
1187 | u16 lpa; | ||
1188 | u16 mode; | ||
1189 | |||
1190 | mode = AX88772_MEDIUM_DEFAULT; | ||
1191 | lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA); | ||
1192 | |||
1193 | if ((lpa & LPA_DUPLEX) == 0) | ||
1194 | mode &= ~AX88772_MEDIUM_FULL_DUPLEX; | ||
1195 | if ((lpa & LPA_100) == 0) | ||
1196 | mode &= ~AX88772_MEDIUM_100MB; | ||
1197 | ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
1198 | |||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1216 | static const struct driver_info ax8817x_info = { | 1202 | static const struct driver_info ax8817x_info = { |
1217 | .description = "ASIX AX8817x USB 2.0 Ethernet", | 1203 | .description = "ASIX AX8817x USB 2.0 Ethernet", |
1218 | .bind = ax8817x_bind, | 1204 | .bind = ax8817x_bind, |
1219 | .unbind = ax8817x_unbind, | 1205 | .status = ax8817x_status, |
1206 | .link_reset = ax88172_link_reset, | ||
1207 | .reset = ax88172_link_reset, | ||
1220 | .flags = FLAG_ETHER, | 1208 | .flags = FLAG_ETHER, |
1221 | .data = 0x00130103, | 1209 | .data = 0x00130103, |
1222 | }; | 1210 | }; |
@@ -1224,7 +1212,9 @@ static const struct driver_info ax8817x_info = { | |||
1224 | static const struct driver_info dlink_dub_e100_info = { | 1212 | static const struct driver_info dlink_dub_e100_info = { |
1225 | .description = "DLink DUB-E100 USB Ethernet", | 1213 | .description = "DLink DUB-E100 USB Ethernet", |
1226 | .bind = ax8817x_bind, | 1214 | .bind = ax8817x_bind, |
1227 | .unbind = ax8817x_unbind, | 1215 | .status = ax8817x_status, |
1216 | .link_reset = ax88172_link_reset, | ||
1217 | .reset = ax88172_link_reset, | ||
1228 | .flags = FLAG_ETHER, | 1218 | .flags = FLAG_ETHER, |
1229 | .data = 0x009f9d9f, | 1219 | .data = 0x009f9d9f, |
1230 | }; | 1220 | }; |
@@ -1232,7 +1222,9 @@ static const struct driver_info dlink_dub_e100_info = { | |||
1232 | static const struct driver_info netgear_fa120_info = { | 1222 | static const struct driver_info netgear_fa120_info = { |
1233 | .description = "Netgear FA-120 USB Ethernet", | 1223 | .description = "Netgear FA-120 USB Ethernet", |
1234 | .bind = ax8817x_bind, | 1224 | .bind = ax8817x_bind, |
1235 | .unbind = ax8817x_unbind, | 1225 | .status = ax8817x_status, |
1226 | .link_reset = ax88172_link_reset, | ||
1227 | .reset = ax88172_link_reset, | ||
1236 | .flags = FLAG_ETHER, | 1228 | .flags = FLAG_ETHER, |
1237 | .data = 0x00130103, | 1229 | .data = 0x00130103, |
1238 | }; | 1230 | }; |
@@ -1240,7 +1232,9 @@ static const struct driver_info netgear_fa120_info = { | |||
1240 | static const struct driver_info hawking_uf200_info = { | 1232 | static const struct driver_info hawking_uf200_info = { |
1241 | .description = "Hawking UF200 USB Ethernet", | 1233 | .description = "Hawking UF200 USB Ethernet", |
1242 | .bind = ax8817x_bind, | 1234 | .bind = ax8817x_bind, |
1243 | .unbind = ax8817x_unbind, | 1235 | .status = ax8817x_status, |
1236 | .link_reset = ax88172_link_reset, | ||
1237 | .reset = ax88172_link_reset, | ||
1244 | .flags = FLAG_ETHER, | 1238 | .flags = FLAG_ETHER, |
1245 | .data = 0x001f1d1f, | 1239 | .data = 0x001f1d1f, |
1246 | }; | 1240 | }; |
@@ -1248,7 +1242,9 @@ static const struct driver_info hawking_uf200_info = { | |||
1248 | static const struct driver_info ax88772_info = { | 1242 | static const struct driver_info ax88772_info = { |
1249 | .description = "ASIX AX88772 USB 2.0 Ethernet", | 1243 | .description = "ASIX AX88772 USB 2.0 Ethernet", |
1250 | .bind = ax88772_bind, | 1244 | .bind = ax88772_bind, |
1251 | .unbind = ax8817x_unbind, | 1245 | .status = ax8817x_status, |
1246 | .link_reset = ax88772_link_reset, | ||
1247 | .reset = ax88772_link_reset, | ||
1252 | .flags = FLAG_ETHER | FLAG_FRAMING_AX, | 1248 | .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
1253 | .rx_fixup = ax88772_rx_fixup, | 1249 | .rx_fixup = ax88772_rx_fixup, |
1254 | .tx_fixup = ax88772_tx_fixup, | 1250 | .tx_fixup = ax88772_tx_fixup, |
@@ -3307,6 +3303,19 @@ kevent (void *data) | |||
3307 | } | 3303 | } |
3308 | } | 3304 | } |
3309 | 3305 | ||
3306 | if (test_bit (EVENT_LINK_RESET, &dev->flags)) { | ||
3307 | struct driver_info *info = dev->driver_info; | ||
3308 | int retval = 0; | ||
3309 | |||
3310 | clear_bit (EVENT_LINK_RESET, &dev->flags); | ||
3311 | if(info->link_reset && (retval = info->link_reset(dev)) < 0) { | ||
3312 | devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", | ||
3313 | retval, | ||
3314 | dev->udev->bus->bus_name, dev->udev->devpath, | ||
3315 | info->description); | ||
3316 | } | ||
3317 | } | ||
3318 | |||
3310 | if (dev->flags) | 3319 | if (dev->flags) |
3311 | devdbg (dev, "kevent done, flags = 0x%lx", | 3320 | devdbg (dev, "kevent done, flags = 0x%lx", |
3312 | dev->flags); | 3321 | dev->flags); |