net: hns3: add hns3_gro_complete for HW GRO process
authorYunsheng Lin <linyunsheng@huawei.com>
Sun, 14 Apr 2019 01:47:40 +0000 (09:47 +0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 14 Apr 2019 20:47:35 +0000 (13:47 -0700)
When a GRO packet is received by driver, the cwr field in the
struct tcphdr needs to be checked to decide whether to set the
SKB_GSO_TCP_ECN for skb_shinfo(skb)->gso_type.

So this patch adds hns3_gro_complete to do that, and adds the
hns3_handle_bdinfo to handle the hns3_gro_complete and
hns3_rx_checksum.

Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c

index 60afa15..a67dfdd 100644 (file)
@@ -2331,6 +2331,44 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
        }
 }
 
+static int hns3_gro_complete(struct sk_buff *skb)
+{
+       __be16 type = skb->protocol;
+       struct tcphdr *th;
+       int depth = 0;
+
+       while (type == htons(ETH_P_8021Q)) {
+               struct vlan_hdr *vh;
+
+               if ((depth + VLAN_HLEN) > skb_headlen(skb))
+                       return -EFAULT;
+
+               vh = (struct vlan_hdr *)(skb->data + depth);
+               type = vh->h_vlan_encapsulated_proto;
+               depth += VLAN_HLEN;
+       }
+
+       if (type == htons(ETH_P_IP)) {
+               depth += sizeof(struct iphdr);
+       } else if (type == htons(ETH_P_IPV6)) {
+               depth += sizeof(struct ipv6hdr);
+       } else {
+               netdev_err(skb->dev,
+                          "Error: FW GRO supports only IPv4/IPv6, not 0x%04x, depth: %d\n",
+                          be16_to_cpu(type), depth);
+               return -EFAULT;
+       }
+
+       th = (struct tcphdr *)(skb->data + depth);
+       skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
+       if (th->cwr)
+               skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
+
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       return 0;
+}
+
 static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
                             u32 l234info, u32 bd_base_info)
 {
@@ -2345,12 +2383,6 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
        if (!(netdev->features & NETIF_F_RXCSUM))
                return;
 
-       /* We MUST enable hardware checksum before enabling hardware GRO */
-       if (skb_shinfo(skb)->gso_size) {
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-               return;
-       }
-
        /* check if hardware has done checksum */
        if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B)))
                return;
@@ -2567,8 +2599,9 @@ static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc,
        return 0;
 }
 
-static void hns3_set_gro_param(struct sk_buff *skb, u32 l234info,
-                              u32 bd_base_info)
+static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
+                                    struct sk_buff *skb, u32 l234info,
+                                    u32 bd_base_info)
 {
        u16 gro_count;
        u32 l3_type;
@@ -2576,12 +2609,11 @@ static void hns3_set_gro_param(struct sk_buff *skb, u32 l234info,
        gro_count = hnae3_get_field(l234info, HNS3_RXD_GRO_COUNT_M,
                                    HNS3_RXD_GRO_COUNT_S);
        /* if there is no HW GRO, do not set gro params */
-       if (!gro_count)
-               return;
+       if (!gro_count) {
+               hns3_rx_checksum(ring, skb, l234info, bd_base_info);
+               return 0;
+       }
 
-       /* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count
-        * to skb_shinfo(skb)->gso_segs
-        */
        NAPI_GRO_CB(skb)->count = gro_count;
 
        l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M,
@@ -2591,13 +2623,13 @@ static void hns3_set_gro_param(struct sk_buff *skb, u32 l234info,
        else if (l3_type == HNS3_L3_TYPE_IPV6)
                skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
        else
-               return;
+               return -EFAULT;
 
        skb_shinfo(skb)->gso_size = hnae3_get_field(bd_base_info,
                                                    HNS3_RXD_GRO_SIZE_M,
                                                    HNS3_RXD_GRO_SIZE_S);
-       if (skb_shinfo(skb)->gso_size)
-               tcp_gro_complete(skb);
+
+       return  hns3_gro_complete(skb);
 }
 
 static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring,
@@ -2622,16 +2654,85 @@ static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring,
        skb_set_hash(skb, le32_to_cpu(desc->rx.rss_hash), rss_type);
 }
 
-static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
-                            struct sk_buff **out_skb)
+static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb,
+                             struct hns3_desc *desc)
 {
        struct net_device *netdev = ring->tqp->handle->kinfo.netdev;
+       u32 bd_base_info = le32_to_cpu(desc->rx.bd_base_info);
+       u32 l234info = le32_to_cpu(desc->rx.l234_info);
        enum hns3_pkt_l2t_type l2_frame_type;
+       unsigned int len;
+       int ret;
+
+       /* Based on hw strategy, the tag offloaded will be stored at
+        * ot_vlan_tag in two layer tag case, and stored at vlan_tag
+        * in one layer tag case.
+        */
+       if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+               u16 vlan_tag;
+
+               if (hns3_parse_vlan_tag(ring, desc, l234info, &vlan_tag))
+                       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+                                              vlan_tag);
+       }
+
+       if (unlikely(!(bd_base_info & BIT(HNS3_RXD_VLD_B)))) {
+               u64_stats_update_begin(&ring->syncp);
+               ring->stats.non_vld_descs++;
+               u64_stats_update_end(&ring->syncp);
+
+               return -EINVAL;
+       }
+
+       if (unlikely(!desc->rx.pkt_len || (l234info & (BIT(HNS3_RXD_TRUNCAT_B) |
+                                 BIT(HNS3_RXD_L2E_B))))) {
+               u64_stats_update_begin(&ring->syncp);
+               if (l234info & BIT(HNS3_RXD_L2E_B))
+                       ring->stats.l2_err++;
+               else
+                       ring->stats.err_pkt_len++;
+               u64_stats_update_end(&ring->syncp);
+
+               return -EFAULT;
+       }
+
+       len = skb->len;
+
+       /* Do update ip stack process */
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       /* This is needed in order to enable forwarding support */
+       ret = hns3_set_gro_and_checksum(ring, skb, l234info, bd_base_info);
+       if (unlikely(ret)) {
+               u64_stats_update_begin(&ring->syncp);
+               ring->stats.rx_err_cnt++;
+               u64_stats_update_end(&ring->syncp);
+               return ret;
+       }
+
+       l2_frame_type = hnae3_get_field(l234info, HNS3_RXD_DMAC_M,
+                                       HNS3_RXD_DMAC_S);
+
+       u64_stats_update_begin(&ring->syncp);
+       ring->stats.rx_pkts++;
+       ring->stats.rx_bytes += len;
+
+       if (l2_frame_type == HNS3_L2_TYPE_MULTICAST)
+               ring->stats.rx_multicast++;
+
+       u64_stats_update_end(&ring->syncp);
+
+       ring->tqp_vector->rx_group.total_bytes += len;
+       return 0;
+}
+
+static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
+                            struct sk_buff **out_skb)
+{
        struct sk_buff *skb = ring->skb;
        struct hns3_desc_cb *desc_cb;
        struct hns3_desc *desc;
        u32 bd_base_info;
-       u32 l234info;
        int length;
        int ret;
 
@@ -2691,62 +2792,12 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
                       ALIGN(ring->pull_len, sizeof(long)));
        }
 
-       l234info = le32_to_cpu(desc->rx.l234_info);
-       bd_base_info = le32_to_cpu(desc->rx.bd_base_info);
-
-       /* Based on hw strategy, the tag offloaded will be stored at
-        * ot_vlan_tag in two layer tag case, and stored at vlan_tag
-        * in one layer tag case.
-        */
-       if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
-               u16 vlan_tag;
-
-               if (hns3_parse_vlan_tag(ring, desc, l234info, &vlan_tag))
-                       __vlan_hwaccel_put_tag(skb,
-                                              htons(ETH_P_8021Q),
-                                              vlan_tag);
-       }
-
-       if (unlikely(!(bd_base_info & BIT(HNS3_RXD_VLD_B)))) {
-               u64_stats_update_begin(&ring->syncp);
-               ring->stats.non_vld_descs++;
-               u64_stats_update_end(&ring->syncp);
-
-               dev_kfree_skb_any(skb);
-               return -EINVAL;
-       }
-
-       if (unlikely((!desc->rx.pkt_len) ||
-                    (l234info & (BIT(HNS3_RXD_TRUNCAT_B) |
-                                 BIT(HNS3_RXD_L2E_B))))) {
-               u64_stats_update_begin(&ring->syncp);
-               if (l234info & BIT(HNS3_RXD_L2E_B))
-                       ring->stats.l2_err++;
-               else
-                       ring->stats.err_pkt_len++;
-               u64_stats_update_end(&ring->syncp);
-
+       ret = hns3_handle_bdinfo(ring, skb, desc);
+       if (unlikely(ret)) {
                dev_kfree_skb_any(skb);
-               return -EFAULT;
+               return ret;
        }
 
-
-       l2_frame_type = hnae3_get_field(l234info, HNS3_RXD_DMAC_M,
-                                       HNS3_RXD_DMAC_S);
-       u64_stats_update_begin(&ring->syncp);
-       if (l2_frame_type == HNS3_L2_TYPE_MULTICAST)
-               ring->stats.rx_multicast++;
-
-       ring->stats.rx_pkts++;
-       ring->stats.rx_bytes += skb->len;
-       u64_stats_update_end(&ring->syncp);
-
-       ring->tqp_vector->rx_group.total_bytes += skb->len;
-
-       /* This is needed in order to enable forwarding support */
-       hns3_set_gro_param(skb, l234info, bd_base_info);
-
-       hns3_rx_checksum(ring, skb, l234info, bd_base_info);
        *out_skb = skb;
        hns3_set_rx_skb_rss_type(ring, skb);
 
@@ -2758,7 +2809,6 @@ int hns3_clean_rx_ring(
                void (*rx_fn)(struct hns3_enet_ring *, struct sk_buff *))
 {
 #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16
-       struct net_device *netdev = ring->tqp->handle->kinfo.netdev;
        int recv_pkts, recv_bds, clean_count, err;
        int unused_count = hns3_desc_unused(ring) - ring->pending_buf;
        struct sk_buff *skb = ring->skb;
@@ -2795,8 +2845,6 @@ int hns3_clean_rx_ring(
                        continue;
                }
 
-               /* Do update ip stack process */
-               skb->protocol = eth_type_trans(skb, netdev);
                rx_fn(ring, skb);
                recv_bds += ring->pending_buf;
                clean_count += ring->pending_buf;