summaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorDmitry Bezrukov <dmitry.bezrukov@aquantia.com>2018-11-26 10:33:19 +0100
committerDavid S. Miller <davem@davemloft.net>2018-11-28 00:46:06 +0100
commit361459cd9642631f048719169da9ef14cbf4a932 (patch)
tree5c8987af7a979f008859c7ba008e0eb775d757b7 /drivers/net/usb
parentnet: usb: aqc111: Implement TX data path (diff)
downloadlinux-361459cd9642631f048719169da9ef14cbf4a932.tar.xz
linux-361459cd9642631f048719169da9ef14cbf4a932.zip
net: usb: aqc111: Implement RX data path
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>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/aqc111.c102
-rw-r--r--drivers/net/usb/aqc111.h15
2 files changed, 117 insertions, 0 deletions
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 32a2de74ef3f..7a1976ecf294 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -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,
};
diff --git a/drivers/net/usb/aqc111.h b/drivers/net/usb/aqc111.h
index c09f188b9f3d..c5785f890022 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
@@ -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;