From: Haiyang Zhang <[email protected]>

Our NIC can have up to 4 RX packets on 1 CQE. To support this feature,
check and process the type CQE_RX_COALESCED_4. The default setting is
disabled, to avoid possible regression on latency.

And add ethtool handler to switch this feature. To turn it on, run:
  ethtool -C <nic> rx-frames 4
To turn it off:
  ethtool -C <nic> rx-frames 1

Signed-off-by: Haiyang Zhang <[email protected]>
---
 drivers/net/ethernet/microsoft/mana/mana_en.c | 32 ++++++-----
 .../ethernet/microsoft/mana/mana_ethtool.c    | 55 +++++++++++++++++++
 include/net/mana/mana.h                       |  2 +
 3 files changed, 74 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c 
b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 1ad154f9db1a..a46a1adf83bc 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1330,7 +1330,7 @@ static int mana_cfg_vport_steering(struct 
mana_port_context *apc,
        req->update_hashkey = update_key;
        req->update_indir_tab = update_tab;
        req->default_rxobj = apc->default_rxobj;
-       req->cqe_coalescing_enable = 0;
+       req->cqe_coalescing_enable = apc->cqe_coalescing_enable;
 
        if (update_key)
                memcpy(&req->hashkey, apc->hashkey, MANA_HASH_KEY_SIZE);
@@ -1864,11 +1864,12 @@ static struct sk_buff *mana_build_skb(struct mana_rxq 
*rxq, void *buf_va,
 }
 
 static void mana_rx_skb(void *buf_va, bool from_pool,
-                       struct mana_rxcomp_oob *cqe, struct mana_rxq *rxq)
+                       struct mana_rxcomp_oob *cqe, struct mana_rxq *rxq,
+                       int i)
 {
        struct mana_stats_rx *rx_stats = &rxq->stats;
        struct net_device *ndev = rxq->ndev;
-       uint pkt_len = cqe->ppi[0].pkt_len;
+       uint pkt_len = cqe->ppi[i].pkt_len;
        u16 rxq_idx = rxq->rxq_idx;
        struct napi_struct *napi;
        struct xdp_buff xdp = {};
@@ -1912,7 +1913,7 @@ static void mana_rx_skb(void *buf_va, bool from_pool,
        }
 
        if (cqe->rx_hashtype != 0 && (ndev->features & NETIF_F_RXHASH)) {
-               hash_value = cqe->ppi[0].pkt_hash;
+               hash_value = cqe->ppi[i].pkt_hash;
 
                if (cqe->rx_hashtype & MANA_HASH_L4)
                        skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L4);
@@ -2047,9 +2048,11 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, 
struct mana_cq *cq,
        struct mana_recv_buf_oob *rxbuf_oob;
        struct mana_port_context *apc;
        struct device *dev = gc->dev;
+       bool coalesced = false;
        void *old_buf = NULL;
        u32 curr, pktlen;
        bool old_fp;
+       int i = 0;
 
        apc = netdev_priv(ndev);
 
@@ -2064,9 +2067,8 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, 
struct mana_cq *cq,
                goto drop;
 
        case CQE_RX_COALESCED_4:
-               netdev_err(ndev, "RX coalescing is unsupported\n");
-               apc->eth_stats.rx_coalesced_err++;
-               return;
+               coalesced = true;
+               break;
 
        case CQE_RX_OBJECT_FENCE:
                complete(&rxq->fence_event);
@@ -2079,14 +2081,10 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, 
struct mana_cq *cq,
                return;
        }
 
-       pktlen = oob->ppi[0].pkt_len;
-
-       if (pktlen == 0) {
-               /* data packets should never have packetlength of zero */
-               netdev_err(ndev, "RX pkt len=0, rq=%u, cq=%u, rxobj=0x%llx\n",
-                          rxq->gdma_id, cq->gdma_id, rxq->rxobj);
+nextpkt:
+       pktlen = oob->ppi[i].pkt_len;
+       if (pktlen == 0)
                return;
-       }
 
        curr = rxq->buf_index;
        rxbuf_oob = &rxq->rx_oobs[curr];
@@ -2097,12 +2095,15 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, 
struct mana_cq *cq,
        /* Unsuccessful refill will have old_buf == NULL.
         * In this case, mana_rx_skb() will drop the packet.
         */
-       mana_rx_skb(old_buf, old_fp, oob, rxq);
+       mana_rx_skb(old_buf, old_fp, oob, rxq, i);
 
 drop:
        mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu);
 
        mana_post_pkt_rxq(rxq);
+
+       if (coalesced && (++i < MANA_RXCOMP_OOB_NUM_PPI))
+               goto nextpkt;
 }
 
 static void mana_poll_rx_cq(struct mana_cq *cq)
@@ -3276,6 +3277,7 @@ static int mana_probe_port(struct mana_context *ac, int 
port_idx,
        apc->port_handle = INVALID_MANA_HANDLE;
        apc->pf_filter_handle = INVALID_MANA_HANDLE;
        apc->port_idx = port_idx;
+       apc->cqe_coalescing_enable = 0;
 
        mutex_init(&apc->vport_mutex);
        apc->vport_use_count = 0;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c 
b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 0e2f4343ac67..1b9ed5c9bbff 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -397,6 +397,58 @@ static void mana_get_channels(struct net_device *ndev,
        channel->combined_count = apc->num_queues;
 }
 
+static int mana_get_coalesce(struct net_device *ndev,
+                            struct ethtool_coalesce *ec,
+                            struct kernel_ethtool_coalesce *kernel_coal,
+                            struct netlink_ext_ack *extack)
+{
+       struct mana_port_context *apc = netdev_priv(ndev);
+
+       ec->rx_max_coalesced_frames =
+               apc->cqe_coalescing_enable ? MANA_RXCOMP_OOB_NUM_PPI : 1;
+
+       return 0;
+}
+
+static int mana_set_coalesce(struct net_device *ndev,
+                            struct ethtool_coalesce *ec,
+                            struct kernel_ethtool_coalesce *kernel_coal,
+                            struct netlink_ext_ack *extack)
+{
+       struct mana_port_context *apc = netdev_priv(ndev);
+       u8 saved_cqe_coalescing_enable;
+       int err;
+
+       if (ec->rx_max_coalesced_frames != 1 &&
+           ec->rx_max_coalesced_frames != MANA_RXCOMP_OOB_NUM_PPI) {
+               NL_SET_ERR_MSG_FMT(extack,
+                                  "rx-frames must be 1 or %u, got %u",
+                                  MANA_RXCOMP_OOB_NUM_PPI,
+                                  ec->rx_max_coalesced_frames);
+               return -EINVAL;
+       }
+
+       saved_cqe_coalescing_enable = apc->cqe_coalescing_enable;
+       apc->cqe_coalescing_enable =
+               ec->rx_max_coalesced_frames == MANA_RXCOMP_OOB_NUM_PPI;
+
+       if (!apc->port_is_up)
+               return 0;
+
+       err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
+
+       if (err) {
+               netdev_err(ndev, "Set rx-frames to %u failed:%d\n",
+                          ec->rx_max_coalesced_frames, err);
+               NL_SET_ERR_MSG_FMT(extack, "Set rx-frames to %u failed:%d\n",
+                                  ec->rx_max_coalesced_frames, err);
+
+               apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
+       }
+
+       return err;
+}
+
 static int mana_set_channels(struct net_device *ndev,
                             struct ethtool_channels *channels)
 {
@@ -517,6 +569,7 @@ static int mana_get_link_ksettings(struct net_device *ndev,
 }
 
 const struct ethtool_ops mana_ethtool_ops = {
+       .supported_coalesce_params = ETHTOOL_COALESCE_RX_MAX_FRAMES,
        .get_ethtool_stats      = mana_get_ethtool_stats,
        .get_sset_count         = mana_get_sset_count,
        .get_strings            = mana_get_strings,
@@ -527,6 +580,8 @@ const struct ethtool_ops mana_ethtool_ops = {
        .set_rxfh               = mana_set_rxfh,
        .get_channels           = mana_get_channels,
        .set_channels           = mana_set_channels,
+       .get_coalesce           = mana_get_coalesce,
+       .set_coalesce           = mana_set_coalesce,
        .get_ringparam          = mana_get_ringparam,
        .set_ringparam          = mana_set_ringparam,
        .get_link_ksettings     = mana_get_link_ksettings,
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index d7e089c6b694..51d26ebeff6c 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -556,6 +556,8 @@ struct mana_port_context {
        bool port_is_up;
        bool port_st_save; /* Saved port state */
 
+       u8 cqe_coalescing_enable;
+
        struct mana_ethtool_stats eth_stats;
 
        struct mana_ethtool_phy_stats phy_stats;
-- 
2.34.1


Reply via email to