]> git.itanic.dy.fi Git - linux-stable/commitdiff
net: hns3: use bounce buffer when rx page can not be reused
authorYunsheng Lin <linyunsheng@huawei.com>
Wed, 16 Jun 2021 06:36:17 +0000 (14:36 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Jun 2021 07:36:06 +0000 (00:36 -0700)
Currently rx page will be reused to receive future packet when
the stack releases the previous skb quickly. If the old page
can not be reused, a new page will be allocated and mapped,
which comsumes a lot of cpu when IOMMU is in the strict mode,
especially when the application and irq/NAPI happens to run on
the same cpu.

So allocate a new frag to memcpy the data to avoid the costly
IOMMU unmapping/mapping operation, and add "frag_alloc_err"
and "frag_alloc" stats in "ethtool -S ethX" cmd.

The throughput improves above 50% when running single thread of
iperf using TCP when IOMMU is in strict mode and iperf shares the
same cpu with irq/NAPI(rx_copybreak = 2048 and mtu = 1500).

Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: Guangbin Huang <huangguangbin2@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c

index a24a75c47cadb1eaa249ea56c90e3ca4db44cb66..34b6cd904a1ad34b8e43a8e1c55ca6aed77f2696 100644 (file)
@@ -450,6 +450,7 @@ static const struct hns3_dbg_item rx_queue_info_items[] = {
        { "HEAD", 2 },
        { "FBDNUM", 2 },
        { "PKTNUM", 2 },
+       { "COPYBREAK", 2 },
        { "RING_EN", 2 },
        { "RX_RING_EN", 2 },
        { "BASE_ADDR", 10 },
@@ -481,6 +482,7 @@ static void hns3_dump_rx_queue_info(struct hns3_enet_ring *ring,
 
        sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
                HNS3_RING_RX_RING_PKTNUM_RECORD_REG));
+       sprintf(result[j++], "%9u", ring->rx_copybreak);
 
        sprintf(result[j++], "%7s", readl_relaxed(ring->tqp->io_base +
                HNS3_RING_EN_REG) ? "on" : "off");
index 98e8a548edb8b8ddcf082773086dc942d98302d5..51bbf5f760c55bd7331a9ad8bf92805ef27379de 100644 (file)
@@ -3552,6 +3552,28 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
                   hns3_page_size(ring)) {
                desc_cb->page_offset += truesize;
                desc_cb->reuse_flag = 1;
+       } else if (frag_size <= ring->rx_copybreak) {
+               void *frag = napi_alloc_frag(frag_size);
+
+               if (unlikely(!frag)) {
+                       u64_stats_update_begin(&ring->syncp);
+                       ring->stats.frag_alloc_err++;
+                       u64_stats_update_end(&ring->syncp);
+
+                       hns3_rl_err(ring_to_netdev(ring),
+                                   "failed to allocate rx frag\n");
+                       goto out;
+               }
+
+               desc_cb->reuse_flag = 1;
+               memcpy(frag, desc_cb->buf + frag_offset, frag_size);
+               skb_add_rx_frag(skb, i, virt_to_page(frag),
+                               offset_in_page(frag), frag_size, frag_size);
+
+               u64_stats_update_begin(&ring->syncp);
+               ring->stats.frag_alloc++;
+               u64_stats_update_end(&ring->syncp);
+               return;
        }
 
 out:
@@ -4620,6 +4642,7 @@ static void hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv,
                ring = &priv->ring[q->tqp_index + queue_num];
                desc_num = priv->ae_handle->kinfo.num_rx_desc;
                ring->queue_index = q->tqp_index;
+               ring->rx_copybreak = priv->rx_copybreak;
        }
 
        hnae3_set_bit(ring->flag, HNAE3_RING_TYPE_B, ring_type);
index 22ae291471aa0258ecb30d955cdb2c83dac11926..15af3d93857b69ad076bfde338d0115fc195d5e4 100644 (file)
@@ -427,6 +427,8 @@ struct ring_stats {
                        u64 csum_complete;
                        u64 rx_multicast;
                        u64 non_reuse_pg;
+                       u64 frag_alloc_err;
+                       u64 frag_alloc;
                };
                __le16 csum;
        };
@@ -478,6 +480,7 @@ struct hns3_enet_ring {
                /* for Rx ring */
                struct {
                        u32 pull_len;   /* memcpy len for current rx packet */
+                       u32 rx_copybreak;
                        u32 frag_num;
                        /* first buffer address for current packet */
                        unsigned char *va;
@@ -569,6 +572,7 @@ struct hns3_nic_priv {
        struct hns3_enet_coalesce tx_coal;
        struct hns3_enet_coalesce rx_coal;
        u32 tx_copybreak;
+       u32 rx_copybreak;
 };
 
 union l3_hdr_info {
index d7852716aaadc469c71115257debf07cd2e39535..82061ab6930fba727c6835c0d520f29af689805a 100644 (file)
@@ -71,6 +71,8 @@ static const struct hns3_stats hns3_rxq_stats[] = {
        HNS3_TQP_STAT("csum_complete", csum_complete),
        HNS3_TQP_STAT("multicast", rx_multicast),
        HNS3_TQP_STAT("non_reuse_pg", non_reuse_pg),
+       HNS3_TQP_STAT("frag_alloc_err", frag_alloc_err),
+       HNS3_TQP_STAT("frag_alloc", frag_alloc),
 };
 
 #define HNS3_PRIV_FLAGS_LEN ARRAY_SIZE(hns3_priv_flags)
@@ -1610,6 +1612,9 @@ static int hns3_get_tunable(struct net_device *netdev,
                /* all the tx rings have the same tx_copybreak */
                *(u32 *)data = priv->tx_copybreak;
                break;
+       case ETHTOOL_RX_COPYBREAK:
+               *(u32 *)data = priv->rx_copybreak;
+               break;
        default:
                ret = -EOPNOTSUPP;
                break;
@@ -1633,6 +1638,13 @@ static int hns3_set_tunable(struct net_device *netdev,
                for (i = 0; i < h->kinfo.num_tqps; i++)
                        priv->ring[i].tx_copybreak = priv->tx_copybreak;
 
+               break;
+       case ETHTOOL_RX_COPYBREAK:
+               priv->rx_copybreak = *(u32 *)data;
+
+               for (i = h->kinfo.num_tqps; i < h->kinfo.num_tqps * 2; i++)
+                       priv->ring[i].rx_copybreak = priv->rx_copybreak;
+
                break;
        default:
                ret = -EOPNOTSUPP;