diff options
-rw-r--r-- | drivers/net/usb/asix.h | 15 | ||||
-rw-r--r-- | drivers/net/usb/asix_common.c | 90 | ||||
-rw-r--r-- | drivers/net/usb/asix_devices.c | 23 | ||||
-rw-r--r-- | drivers/net/usb/ax88172a.c | 11 |
4 files changed, 109 insertions, 30 deletions
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index 7afe8ac078e8..346c032aa795 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h | |||
@@ -167,6 +167,17 @@ struct asix_data { | |||
167 | u8 res; | 167 | u8 res; |
168 | }; | 168 | }; |
169 | 169 | ||
170 | struct asix_rx_fixup_info { | ||
171 | struct sk_buff *ax_skb; | ||
172 | u32 header; | ||
173 | u16 size; | ||
174 | bool split_head; | ||
175 | }; | ||
176 | |||
177 | struct asix_common_private { | ||
178 | struct asix_rx_fixup_info rx_fixup_info; | ||
179 | }; | ||
180 | |||
170 | /* ASIX specific flags */ | 181 | /* ASIX specific flags */ |
171 | #define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */ | 182 | #define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */ |
172 | 183 | ||
@@ -179,7 +190,9 @@ int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |||
179 | void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, | 190 | void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, |
180 | u16 index, u16 size, void *data); | 191 | u16 index, u16 size, void *data); |
181 | 192 | ||
182 | int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb); | 193 | int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, |
194 | struct asix_rx_fixup_info *rx); | ||
195 | int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb); | ||
183 | 196 | ||
184 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | 197 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
185 | gfp_t flags); | 198 | gfp_t flags); |
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 19bc23f20526..f7f623a5390e 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c | |||
@@ -51,49 +51,89 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |||
51 | value, index, data, size); | 51 | value, index, data, size); |
52 | } | 52 | } |
53 | 53 | ||
54 | int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 54 | int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, |
55 | struct asix_rx_fixup_info *rx) | ||
55 | { | 56 | { |
56 | int offset = 0; | 57 | int offset = 0; |
57 | 58 | ||
58 | while (offset + sizeof(u32) < skb->len) { | 59 | while (offset + sizeof(u16) <= skb->len) { |
59 | struct sk_buff *ax_skb; | 60 | u16 remaining = 0; |
60 | u16 size; | 61 | unsigned char *data; |
61 | u32 header = get_unaligned_le32(skb->data + offset); | 62 | |
62 | 63 | if (!rx->size) { | |
63 | offset += sizeof(u32); | 64 | if ((skb->len - offset == sizeof(u16)) || |
64 | 65 | rx->split_head) { | |
65 | /* get the packet length */ | 66 | if(!rx->split_head) { |
66 | size = (u16) (header & 0x7ff); | 67 | rx->header = get_unaligned_le16( |
67 | if (size != ((~header >> 16) & 0x07ff)) { | 68 | skb->data + offset); |
68 | netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); | 69 | rx->split_head = true; |
69 | return 0; | 70 | offset += sizeof(u16); |
71 | break; | ||
72 | } else { | ||
73 | rx->header |= (get_unaligned_le16( | ||
74 | skb->data + offset) | ||
75 | << 16); | ||
76 | rx->split_head = false; | ||
77 | offset += sizeof(u16); | ||
78 | } | ||
79 | } else { | ||
80 | rx->header = get_unaligned_le32(skb->data + | ||
81 | offset); | ||
82 | offset += sizeof(u32); | ||
83 | } | ||
84 | |||
85 | /* get the packet length */ | ||
86 | rx->size = (u16) (rx->header & 0x7ff); | ||
87 | if (rx->size != ((~rx->header >> 16) & 0x7ff)) { | ||
88 | netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n", | ||
89 | rx->header, offset); | ||
90 | rx->size = 0; | ||
91 | return 0; | ||
92 | } | ||
93 | rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, | ||
94 | rx->size); | ||
95 | if (!rx->ax_skb) | ||
96 | return 0; | ||
70 | } | 97 | } |
71 | 98 | ||
72 | if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || | 99 | if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) { |
73 | (size + offset > skb->len)) { | ||
74 | netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", | 100 | netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", |
75 | size); | 101 | rx->size); |
102 | kfree_skb(rx->ax_skb); | ||
76 | return 0; | 103 | return 0; |
77 | } | 104 | } |
78 | ax_skb = netdev_alloc_skb_ip_align(dev->net, size); | ||
79 | if (!ax_skb) | ||
80 | return 0; | ||
81 | 105 | ||
82 | skb_put(ax_skb, size); | 106 | if (rx->size > skb->len - offset) { |
83 | memcpy(ax_skb->data, skb->data + offset, size); | 107 | remaining = rx->size - (skb->len - offset); |
84 | usbnet_skb_return(dev, ax_skb); | 108 | rx->size = skb->len - offset; |
109 | } | ||
110 | |||
111 | data = skb_put(rx->ax_skb, rx->size); | ||
112 | memcpy(data, skb->data + offset, rx->size); | ||
113 | if (!remaining) | ||
114 | usbnet_skb_return(dev, rx->ax_skb); | ||
85 | 115 | ||
86 | offset += (size + 1) & 0xfffe; | 116 | offset += (rx->size + 1) & 0xfffe; |
117 | rx->size = remaining; | ||
87 | } | 118 | } |
88 | 119 | ||
89 | if (skb->len != offset) { | 120 | if (skb->len != offset) { |
90 | netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", | 121 | netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n", |
91 | skb->len); | 122 | skb->len, offset); |
92 | return 0; | 123 | return 0; |
93 | } | 124 | } |
125 | |||
94 | return 1; | 126 | return 1; |
95 | } | 127 | } |
96 | 128 | ||
129 | int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb) | ||
130 | { | ||
131 | struct asix_common_private *dp = dev->driver_priv; | ||
132 | struct asix_rx_fixup_info *rx = &dp->rx_fixup_info; | ||
133 | |||
134 | return asix_rx_fixup_internal(dev, skb, rx); | ||
135 | } | ||
136 | |||
97 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | 137 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
98 | gfp_t flags) | 138 | gfp_t flags) |
99 | { | 139 | { |
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 0ecc3bc6c3d7..37de7db56d63 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c | |||
@@ -495,9 +495,19 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
495 | dev->rx_urb_size = 2048; | 495 | dev->rx_urb_size = 2048; |
496 | } | 496 | } |
497 | 497 | ||
498 | dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); | ||
499 | if (!dev->driver_priv) | ||
500 | return -ENOMEM; | ||
501 | |||
498 | return 0; | 502 | return 0; |
499 | } | 503 | } |
500 | 504 | ||
505 | void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
506 | { | ||
507 | if (dev->driver_priv) | ||
508 | kfree(dev->driver_priv); | ||
509 | } | ||
510 | |||
501 | static const struct ethtool_ops ax88178_ethtool_ops = { | 511 | static const struct ethtool_ops ax88178_ethtool_ops = { |
502 | .get_drvinfo = asix_get_drvinfo, | 512 | .get_drvinfo = asix_get_drvinfo, |
503 | .get_link = asix_get_link, | 513 | .get_link = asix_get_link, |
@@ -829,6 +839,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) | |||
829 | dev->rx_urb_size = 2048; | 839 | dev->rx_urb_size = 2048; |
830 | } | 840 | } |
831 | 841 | ||
842 | dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); | ||
843 | if (!dev->driver_priv) | ||
844 | return -ENOMEM; | ||
845 | |||
832 | return 0; | 846 | return 0; |
833 | } | 847 | } |
834 | 848 | ||
@@ -875,23 +889,25 @@ static const struct driver_info hawking_uf200_info = { | |||
875 | static const struct driver_info ax88772_info = { | 889 | static const struct driver_info ax88772_info = { |
876 | .description = "ASIX AX88772 USB 2.0 Ethernet", | 890 | .description = "ASIX AX88772 USB 2.0 Ethernet", |
877 | .bind = ax88772_bind, | 891 | .bind = ax88772_bind, |
892 | .unbind = ax88772_unbind, | ||
878 | .status = asix_status, | 893 | .status = asix_status, |
879 | .link_reset = ax88772_link_reset, | 894 | .link_reset = ax88772_link_reset, |
880 | .reset = ax88772_reset, | 895 | .reset = ax88772_reset, |
881 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, | 896 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, |
882 | .rx_fixup = asix_rx_fixup, | 897 | .rx_fixup = asix_rx_fixup_common, |
883 | .tx_fixup = asix_tx_fixup, | 898 | .tx_fixup = asix_tx_fixup, |
884 | }; | 899 | }; |
885 | 900 | ||
886 | static const struct driver_info ax88772b_info = { | 901 | static const struct driver_info ax88772b_info = { |
887 | .description = "ASIX AX88772B USB 2.0 Ethernet", | 902 | .description = "ASIX AX88772B USB 2.0 Ethernet", |
888 | .bind = ax88772_bind, | 903 | .bind = ax88772_bind, |
904 | .unbind = ax88772_unbind, | ||
889 | .status = asix_status, | 905 | .status = asix_status, |
890 | .link_reset = ax88772_link_reset, | 906 | .link_reset = ax88772_link_reset, |
891 | .reset = ax88772_reset, | 907 | .reset = ax88772_reset, |
892 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | | 908 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | |
893 | FLAG_MULTI_PACKET, | 909 | FLAG_MULTI_PACKET, |
894 | .rx_fixup = asix_rx_fixup, | 910 | .rx_fixup = asix_rx_fixup_common, |
895 | .tx_fixup = asix_tx_fixup, | 911 | .tx_fixup = asix_tx_fixup, |
896 | .data = FLAG_EEPROM_MAC, | 912 | .data = FLAG_EEPROM_MAC, |
897 | }; | 913 | }; |
@@ -899,11 +915,12 @@ static const struct driver_info ax88772b_info = { | |||
899 | static const struct driver_info ax88178_info = { | 915 | static const struct driver_info ax88178_info = { |
900 | .description = "ASIX AX88178 USB 2.0 Ethernet", | 916 | .description = "ASIX AX88178 USB 2.0 Ethernet", |
901 | .bind = ax88178_bind, | 917 | .bind = ax88178_bind, |
918 | .unbind = ax88772_unbind, | ||
902 | .status = asix_status, | 919 | .status = asix_status, |
903 | .link_reset = ax88178_link_reset, | 920 | .link_reset = ax88178_link_reset, |
904 | .reset = ax88178_reset, | 921 | .reset = ax88178_reset, |
905 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, | 922 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, |
906 | .rx_fixup = asix_rx_fixup, | 923 | .rx_fixup = asix_rx_fixup_common, |
907 | .tx_fixup = asix_tx_fixup, | 924 | .tx_fixup = asix_tx_fixup, |
908 | }; | 925 | }; |
909 | 926 | ||
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index fdbab72926bd..76ee5410d69e 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c | |||
@@ -35,6 +35,7 @@ struct ax88172a_private { | |||
35 | u16 phy_addr; | 35 | u16 phy_addr; |
36 | u16 oldmode; | 36 | u16 oldmode; |
37 | int use_embdphy; | 37 | int use_embdphy; |
38 | struct asix_rx_fixup_info rx_fixup_info; | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | /* MDIO read and write wrappers for phylib */ | 41 | /* MDIO read and write wrappers for phylib */ |
@@ -400,6 +401,14 @@ out: | |||
400 | 401 | ||
401 | } | 402 | } |
402 | 403 | ||
404 | static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
405 | { | ||
406 | struct ax88172a_private *dp = dev->driver_priv; | ||
407 | struct asix_rx_fixup_info *rx = &dp->rx_fixup_info; | ||
408 | |||
409 | return asix_rx_fixup_internal(dev, skb, rx); | ||
410 | } | ||
411 | |||
403 | const struct driver_info ax88172a_info = { | 412 | const struct driver_info ax88172a_info = { |
404 | .description = "ASIX AX88172A USB 2.0 Ethernet", | 413 | .description = "ASIX AX88172A USB 2.0 Ethernet", |
405 | .bind = ax88172a_bind, | 414 | .bind = ax88172a_bind, |
@@ -409,6 +418,6 @@ const struct driver_info ax88172a_info = { | |||
409 | .status = ax88172a_status, | 418 | .status = ax88172a_status, |
410 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | | 419 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | |
411 | FLAG_MULTI_PACKET, | 420 | FLAG_MULTI_PACKET, |
412 | .rx_fixup = asix_rx_fixup, | 421 | .rx_fixup = ax88172a_rx_fixup, |
413 | .tx_fixup = asix_tx_fixup, | 422 | .tx_fixup = asix_tx_fixup, |
414 | }; | 423 | }; |