From: Dmitry Bezrukov <dmitry.bezru...@aquantia.com> Signed-off-by: Dmitry Bezrukov <dmitry.bezru...@aquantia.com> Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com> --- drivers/net/usb/aqc111.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/aqc111.h | 39 ++++++++++++++++++ 2 files changed, 139 insertions(+)
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c index 46832fd56f0a..fc068e731335 100644 --- a/drivers/net/usb/aqc111.c +++ b/drivers/net/usb/aqc111.c @@ -362,6 +362,9 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) if (ret) goto out; + /* Set Rx urb size */ + dev->rx_urb_size = URB_SIZE; + /* Set TX needed headroom & tailroom */ dev->net->needed_headroom += AQ_TX_HEADER_SIZE; dev->net->needed_tailroom += AQ_TX_HEADER_SIZE; @@ -621,6 +624,8 @@ static int aqc111_reset(struct usbnet *dev) usb_speed = dev->udev->speed; + dev->rx_urb_size = URB_SIZE; + if (usb_device_no_sg_constraint(dev->udev)) dev->can_dma_sg = 1; @@ -708,6 +713,100 @@ static int aqc111_stop(struct usbnet *dev) return 0; } +static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct sk_buff *new_skb = NULL; + u32 skb_len = 0; + u32 desc_offset = 0; /*RX Header Offset*/ + u32 start_of_descs = 0; + u16 pkt_count = 0; + u32 pkt_total_offset = 0; + struct aq_rx_packet_desc *pkt_desc = NULL; + struct aq_rx_desc_header desc_hdr; + + if (!skb) + goto err; + + if (skb->len == 0) + goto err; + + skb_len = skb->len; + /* RX Offset Header */ + skb_trim(skb, skb->len - sizeof(struct aq_rx_desc_header)); + memcpy(&desc_hdr, skb_tail_pointer(skb), + sizeof(struct aq_rx_desc_header)); + le64_to_cpus(&desc_hdr); + + /* Check these packets */ + desc_offset = (u32)desc_hdr.desc_offset; + pkt_count = desc_hdr.pkt_count; + start_of_descs = skb_len - ((pkt_count + 1) * + sizeof(struct aq_rx_desc_header)); + + /* self check descs position */ + if (start_of_descs != desc_offset) + goto err; + + /* self check desc_offset from header*/ + if (desc_offset >= skb_len) + goto err; + + if (pkt_count == 0) + goto err; + + /* Get the first RX packet header */ + pkt_desc = (struct aq_rx_packet_desc *)(skb->data + desc_offset); + + while (pkt_count--) { + u32 pkt_len = (u32)(pkt_desc->length & 0x7FFF); + u32 pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8); + + le64_to_cpus(pkt_desc); + + pkt_total_offset += pkt_len_with_padd; + if (pkt_total_offset > desc_offset || + (pkt_count == 0 && pkt_total_offset != desc_offset)) { + goto err; + } + + if (pkt_desc->drop || !pkt_desc->rx_ok || + pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) { + skb_pull(skb, pkt_len_with_padd); + /* Next RX Packet Header */ + pkt_desc++; + continue; + } + + /* Clone SKB */ + new_skb = skb_clone(skb, GFP_ATOMIC); + + if (!new_skb) + goto err; + + new_skb->len = pkt_len; + skb_pull(new_skb, AQ_RX_HW_PAD); + skb_set_tail_pointer(new_skb, new_skb->len); + + new_skb->truesize = new_skb->len + sizeof(struct sk_buff); + + usbnet_skb_return(dev, new_skb); + if (pkt_count == 0) + break; + + skb_pull(skb, pkt_len_with_padd); + + /* Next RX Packet Header */ + pkt_desc++; + + new_skb = NULL; + } + + return 1; + +err: + return 0; +} + static struct sk_buff *aqc111_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { @@ -769,6 +868,7 @@ static const struct driver_info aqc111_info = { .stop = aqc111_stop, .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, + .rx_fixup = aqc111_rx_fixup, .tx_fixup = aqc111_tx_fixup, }; diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h index 049012e26b26..679ca9f992f7 100644 --- a/drivers/net/usb/aqc111.h +++ b/drivers/net/usb/aqc111.h @@ -10,6 +10,8 @@ #ifndef __LINUX_USBNET_AQC111_H #define __LINUX_USBNET_AQC111_H +#define URB_SIZE (1024 * 62) + #define AQ_ACCESS_MAC 0x01 #define AQ_FLASH_PARAMETERS 0x20 #define AQ_PHY_POWER 0x31 @@ -228,6 +230,8 @@ struct aqc111_int_data { #define AQ_INT_SPEED_1G 0x11 #define AQ_INT_SPEED_100M 0x13 +#define AQ_RX_HW_PAD 0x02 + struct aq_tx_packet_desc { struct { u32 length:21; @@ -246,6 +250,41 @@ struct aq_tx_packet_desc { #define AQ_TX_HEADER_SIZE sizeof(struct aq_tx_packet_desc) +struct aq_rx_packet_desc { + struct { + u16 l4_err:1; + u16 l3_err:1; + u16 l4_pkt_type:3; + u16 l3_pkt_type:2; + u16 ce:1; + u16 tco_match:1; + u16 node_id_match:1; + u16 vlan_ind : 1; + u16 rx_ok:1; + u16 reserved1 : 3; + u16 bmc:1; + }; + struct { + u16 length:15; + u16 drop:1; + }; + u16 vlan_tag; + struct { + u8 wuf_detect:1; + u8 wuf_wake:1; + u8 wuf_ind:6; + u8 reserved2:8; + }; +}; + +struct aq_rx_desc_header { + struct { + u32 pkt_count:13; + u32 desc_offset:19; + }; + u32 rx_throughput; +}; + static struct { unsigned char ctrl; unsigned char timer_l; -- 2.7.4