OSDN Git Service

net: aquantia: optimize rx path using larger preallocated skb len
authorIgor Russkikh <Igor.Russkikh@aquantia.com>
Sat, 23 Mar 2019 15:23:31 +0000 (15:23 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sun, 24 Mar 2019 02:16:53 +0000 (22:16 -0400)
Atlantic driver used 14 bytes preallocated skb size. That made L3 protocol
processing inefficient because pskb_pull had to fetch all the L3/L4 headers
from extra fragments.

Specially on UDP flows that caused extra packet drops because CPU was
overloaded with pskb_pull.

This patch uses eth_get_headlen for skb preallocation.

Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
drivers/net/ethernet/aquantia/atlantic/aq_ring.c

index 3944ce7..aba5507 100644 (file)
@@ -38,6 +38,8 @@
 
 #define AQ_CFG_TX_CLEAN_BUDGET 256U
 
+#define AQ_CFG_RX_HDR_SIZE 256U
+
 /* LRO */
 #define AQ_CFG_IS_LRO_DEF           1U
 
index e2ffb15..4558f16 100644 (file)
@@ -201,17 +201,18 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
                     int budget)
 {
        struct net_device *ndev = aq_nic_get_ndev(self->aq_nic);
-       int err = 0;
        bool is_rsc_completed = true;
+       int err = 0;
 
        for (; (self->sw_head != self->hw_head) && budget;
                self->sw_head = aq_ring_next_dx(self, self->sw_head),
                --budget, ++(*work_done)) {
                struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+               struct aq_ring_buff_s *buff_ = NULL;
                struct sk_buff *skb = NULL;
                unsigned int next_ = 0U;
                unsigned int i = 0U;
-               struct aq_ring_buff_s *buff_ = NULL;
+               u16 hdr_len;
 
                if (buff->is_error) {
                        __free_pages(buff->page, 0);
@@ -255,20 +256,28 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
                                err = -ENOMEM;
                                goto err_exit;
                        }
-
                        skb_put(skb, buff->len);
                } else {
-                       skb = netdev_alloc_skb(ndev, ETH_HLEN);
+                       skb = napi_alloc_skb(napi, AQ_CFG_RX_HDR_SIZE);
                        if (unlikely(!skb)) {
                                err = -ENOMEM;
                                goto err_exit;
                        }
-                       skb_put(skb, ETH_HLEN);
-                       memcpy(skb->data, page_address(buff->page), ETH_HLEN);
 
-                       skb_add_rx_frag(skb, 0, buff->page, ETH_HLEN,
-                                       buff->len - ETH_HLEN,
-                                       SKB_TRUESIZE(buff->len - ETH_HLEN));
+                       hdr_len = buff->len;
+                       if (hdr_len > AQ_CFG_RX_HDR_SIZE)
+                               hdr_len = eth_get_headlen(page_address(buff->page),
+                                                         AQ_CFG_RX_HDR_SIZE);
+
+                       memcpy(__skb_put(skb, hdr_len), page_address(buff->page),
+                              ALIGN(hdr_len, sizeof(long)));
+
+                       if (buff->len - hdr_len > 0) {
+                               skb_add_rx_frag(skb, 0, buff->page,
+                                               hdr_len,
+                                               buff->len - hdr_len,
+                                               SKB_TRUESIZE(buff->len - hdr_len));
+                       }
 
                        if (!buff->is_eop) {
                                for (i = 1U, next_ = buff->next,