]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
net: usb: aqc111: Implement RX data path
authorDmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Mon, 26 Nov 2018 09:33:19 +0000 (09:33 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 27 Nov 2018 23:46:06 +0000 (15:46 -0800)
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/aqc111.c
drivers/net/usb/aqc111.h

index 32a2de74ef3fdf31390e264e5c2a515bcaecade6..7a1976ecf29482bcf110be494403c4710b823ce1 100644 (file)
@@ -294,6 +294,9 @@ static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf)
 
        ether_addr_copy(dev->net->dev_addr, dev->net->perm_addr);
 
+       /* Set Rx urb size */
+       dev->rx_urb_size = URB_SIZE;
+
        /* Set TX needed headroom & tailroom */
        dev->net->needed_headroom += sizeof(u64);
        dev->net->needed_tailroom += sizeof(u64);
@@ -519,6 +522,8 @@ static int aqc111_reset(struct usbnet *dev)
        struct aqc111_data *aqc111_data = dev->driver_priv;
        u8 reg8 = 0;
 
+       dev->rx_urb_size = URB_SIZE;
+
        if (usb_device_no_sg_constraint(dev->udev))
                dev->can_dma_sg = 1;
 
@@ -578,6 +583,102 @@ 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 pkt_total_offset = 0;
+       u64 *pkt_desc_ptr = NULL;
+       u32 start_of_descs = 0;
+       u32 desc_offset = 0; /*RX Header Offset*/
+       u16 pkt_count = 0;
+       u64 desc_hdr = 0;
+       u32 skb_len = 0;
+
+       if (!skb)
+               goto err;
+
+       if (skb->len == 0)
+               goto err;
+
+       skb_len = skb->len;
+       /* RX Descriptor Header */
+       skb_trim(skb, skb->len - sizeof(desc_hdr));
+       desc_hdr = le64_to_cpup((u64 *)skb_tail_pointer(skb));
+
+       /* Check these packets */
+       desc_offset = (desc_hdr & AQ_RX_DH_DESC_OFFSET_MASK) >>
+                     AQ_RX_DH_DESC_OFFSET_SHIFT;
+       pkt_count = desc_hdr & AQ_RX_DH_PKT_CNT_MASK;
+       start_of_descs = skb_len - ((pkt_count + 1) *  sizeof(desc_hdr));
+
+       /* 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 descriptor */
+       pkt_desc_ptr = (u64 *)(skb->data + desc_offset);
+
+       while (pkt_count--) {
+               u64 pkt_desc = le64_to_cpup(pkt_desc_ptr);
+               u32 pkt_len_with_padd = 0;
+               u32 pkt_len = 0;
+
+               pkt_len = (u32)((pkt_desc & AQ_RX_PD_LEN_MASK) >>
+                         AQ_RX_PD_LEN_SHIFT);
+               pkt_len_with_padd = ((pkt_len + 7) & 0x7FFF8);
+
+               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 & AQ_RX_PD_DROP ||
+                   !(pkt_desc & AQ_RX_PD_RX_OK) ||
+                   pkt_len > (dev->hard_mtu + AQ_RX_HW_PAD)) {
+                       skb_pull(skb, pkt_len_with_padd);
+                       /* Next RX Packet Descriptor */
+                       pkt_desc_ptr++;
+                       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 = SKB_TRUESIZE(new_skb->len);
+
+               usbnet_skb_return(dev, new_skb);
+               if (pkt_count == 0)
+                       break;
+
+               skb_pull(skb, pkt_len_with_padd);
+
+               /* Next RX Packet Header */
+               pkt_desc_ptr++;
+
+               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)
 {
@@ -637,6 +738,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,
 };
 
index c09f188b9f3dbabdbe6522bd278faed6933cd60b..c5785f890022836662ec09bc1db950101f0ce993 100644 (file)
@@ -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
@@ -157,6 +159,19 @@ struct aqc111_data {
 #define AQ_TX_DESC_LEN_MASK    0x1FFFFF
 #define AQ_TX_DESC_DROP_PADD   BIT(28)
 
+#define AQ_RX_HW_PAD                   0x02
+
+/* RX Packet Descriptor */
+#define AQ_RX_PD_RX_OK         BIT(11)
+#define AQ_RX_PD_DROP          BIT(31)
+#define AQ_RX_PD_LEN_MASK      0x7FFF0000
+#define AQ_RX_PD_LEN_SHIFT     0x10
+
+/* RX Descriptor header */
+#define AQ_RX_DH_PKT_CNT_MASK          0x1FFF
+#define AQ_RX_DH_DESC_OFFSET_MASK      0xFFFFE000
+#define AQ_RX_DH_DESC_OFFSET_SHIFT     0x0D
+
 static struct {
        unsigned char ctrl;
        unsigned char timer_l;