]> www.infradead.org Git - users/willy/linux.git/commitdiff
net: wangxun: support to use adaptive RX/TX coalescing
authorJiawen Wu <jiawenwu@trustnetic.com>
Thu, 21 Aug 2025 02:34:08 +0000 (10:34 +0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 23 Aug 2025 00:07:49 +0000 (17:07 -0700)
Support to turn on/off adaptive RX/TX coalesce. When adaptive coalesce
is on, use DIM algorithm for a dynamic interrupt moderation.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Link: https://patch.msgid.link/20250821023408.53472-5-jiawenwu@trustnetic.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 files changed:
drivers/net/ethernet/wangxun/Kconfig
drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
drivers/net/ethernet/wangxun/libwx/wx_lib.c
drivers/net/ethernet/wangxun/libwx/wx_type.h
drivers/net/ethernet/wangxun/libwx/wx_vf_lib.c
drivers/net/ethernet/wangxun/libwx/wx_vf_lib.h
drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c
drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c

index 424ec321212814aeb5ce606a3ff1f283b17cf139..d138dea7d208d72146811b7ea6720ca5844ee41f 100644 (file)
@@ -20,6 +20,7 @@ config LIBWX
        tristate
        depends on PTP_1588_CLOCK_OPTIONAL
        select PAGE_POOL
+       select DIMLIB
        help
        Common library for Wangxun(R) Ethernet drivers.
 
index c7b3f5087b6697e587c582482c2ab368b8b24f65..9572b9f28e599e2f0ecf78811f25dbee14015a9c 100644 (file)
@@ -303,6 +303,11 @@ int wx_get_coalesce(struct net_device *netdev,
        else
                ec->rx_coalesce_usecs = wx->rx_itr_setting >> 2;
 
+       if (wx->adaptive_itr) {
+               ec->use_adaptive_rx_coalesce = 1;
+               ec->use_adaptive_tx_coalesce = 1;
+       }
+
        /* if in mixed tx/rx queues per vector mode, report only rx settings */
        if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count)
                return 0;
@@ -363,19 +368,34 @@ int wx_set_coalesce(struct net_device *netdev,
            (ec->tx_coalesce_usecs > (max_eitr >> 2)))
                return -EINVAL;
 
+       if (ec->use_adaptive_rx_coalesce) {
+               wx->adaptive_itr = true;
+               wx->rx_itr_setting = 1;
+               wx->tx_itr_setting = 1;
+               return 0;
+       }
+
        if (ec->rx_coalesce_usecs > 1)
                wx->rx_itr_setting = ec->rx_coalesce_usecs << 2;
        else
                wx->rx_itr_setting = ec->rx_coalesce_usecs;
 
-       if (wx->rx_itr_setting != 1)
-               rx_itr_param = wx->rx_itr_setting;
-
        if (ec->tx_coalesce_usecs > 1)
                wx->tx_itr_setting = ec->tx_coalesce_usecs << 2;
        else
                wx->tx_itr_setting = ec->tx_coalesce_usecs;
 
+       if (wx->adaptive_itr) {
+               wx->adaptive_itr = false;
+               wx->rx_itr_setting = rx_itr_param;
+               wx->tx_itr_setting = tx_itr_param;
+       } else if (wx->rx_itr_setting == 1 || wx->tx_itr_setting == 1) {
+               wx->adaptive_itr = true;
+       }
+
+       if (wx->rx_itr_setting != 1)
+               rx_itr_param = wx->rx_itr_setting;
+
        if (wx->tx_itr_setting != 1)
                tx_itr_param = wx->tx_itr_setting;
 
index 723785ef87bb098603a1e5852fd07ec6efe9655e..5086db060c61c7bbd7c70100c9a266d62743c1cb 100644 (file)
@@ -16,6 +16,7 @@
 #include "wx_lib.h"
 #include "wx_ptp.h"
 #include "wx_hw.h"
+#include "wx_vf_lib.h"
 
 /* Lookup table mapping the HW PTYPE to the bit field for decoding */
 static struct wx_dec_ptype wx_ptype_lookup[256] = {
@@ -832,6 +833,36 @@ static bool wx_clean_tx_irq(struct wx_q_vector *q_vector,
        return !!budget;
 }
 
+static void wx_update_rx_dim_sample(struct wx_q_vector *q_vector)
+{
+       struct dim_sample sample = {};
+
+       dim_update_sample(q_vector->total_events,
+                         q_vector->rx.total_packets,
+                         q_vector->rx.total_bytes,
+                         &sample);
+
+       net_dim(&q_vector->rx.dim, &sample);
+}
+
+static void wx_update_tx_dim_sample(struct wx_q_vector *q_vector)
+{
+       struct dim_sample sample = {};
+
+       dim_update_sample(q_vector->total_events,
+                         q_vector->tx.total_packets,
+                         q_vector->tx.total_bytes,
+                         &sample);
+
+       net_dim(&q_vector->tx.dim, &sample);
+}
+
+static void wx_update_dim_sample(struct wx_q_vector *q_vector)
+{
+       wx_update_rx_dim_sample(q_vector);
+       wx_update_tx_dim_sample(q_vector);
+}
+
 /**
  * wx_poll - NAPI polling RX/TX cleanup routine
  * @napi: napi struct with our devices info in it
@@ -878,6 +909,8 @@ static int wx_poll(struct napi_struct *napi, int budget)
 
        /* all work done, exit the polling mode */
        if (likely(napi_complete_done(napi, work_done))) {
+               if (wx->adaptive_itr)
+                       wx_update_dim_sample(q_vector);
                if (netif_running(wx->netdev))
                        wx_intr_enable(wx, WX_INTR_Q(q_vector->v_idx));
        }
@@ -1591,6 +1624,65 @@ netdev_tx_t wx_xmit_frame(struct sk_buff *skb,
 }
 EXPORT_SYMBOL(wx_xmit_frame);
 
+static void wx_set_itr(struct wx_q_vector *q_vector)
+{
+       struct wx *wx = q_vector->wx;
+       u32 new_itr;
+
+       if (!wx->adaptive_itr)
+               return;
+
+       /* use the smallest value of new ITR delay calculations */
+       new_itr = min(q_vector->rx.itr, q_vector->tx.itr);
+       new_itr <<= 2;
+
+       if (new_itr != q_vector->itr) {
+               /* save the algorithm value here */
+               q_vector->itr = new_itr;
+
+               if (wx->pdev->is_virtfn)
+                       wx_write_eitr_vf(q_vector);
+               else
+                       wx_write_eitr(q_vector);
+       }
+}
+
+static void wx_rx_dim_work(struct work_struct *work)
+{
+       struct dim *dim = container_of(work, struct dim, work);
+       struct dim_cq_moder rx_moder;
+       struct wx_ring_container *rx;
+       struct wx_q_vector *q_vector;
+
+       rx = container_of(dim, struct wx_ring_container, dim);
+
+       rx_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
+       rx->itr = rx_moder.usec;
+
+       q_vector = container_of(rx, struct wx_q_vector, rx);
+       wx_set_itr(q_vector);
+
+       dim->state = DIM_START_MEASURE;
+}
+
+static void wx_tx_dim_work(struct work_struct *work)
+{
+       struct dim *dim = container_of(work, struct dim, work);
+       struct dim_cq_moder tx_moder;
+       struct wx_ring_container *tx;
+       struct wx_q_vector *q_vector;
+
+       tx = container_of(dim, struct wx_ring_container, dim);
+
+       tx_moder = net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
+       tx->itr = tx_moder.usec;
+
+       q_vector = container_of(tx, struct wx_q_vector, tx);
+       wx_set_itr(q_vector);
+
+       dim->state = DIM_START_MEASURE;
+}
+
 void wx_napi_enable_all(struct wx *wx)
 {
        struct wx_q_vector *q_vector;
@@ -1598,6 +1690,11 @@ void wx_napi_enable_all(struct wx *wx)
 
        for (q_idx = 0; q_idx < wx->num_q_vectors; q_idx++) {
                q_vector = wx->q_vector[q_idx];
+
+               INIT_WORK(&q_vector->rx.dim.work, wx_rx_dim_work);
+               INIT_WORK(&q_vector->tx.dim.work, wx_tx_dim_work);
+               q_vector->rx.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE;
+               q_vector->tx.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE;
                napi_enable(&q_vector->napi);
        }
 }
@@ -1611,6 +1708,8 @@ void wx_napi_disable_all(struct wx *wx)
        for (q_idx = 0; q_idx < wx->num_q_vectors; q_idx++) {
                q_vector = wx->q_vector[q_idx];
                napi_disable(&q_vector->napi);
+               disable_work_sync(&q_vector->rx.dim.work);
+               disable_work_sync(&q_vector->tx.dim.work);
        }
 }
 EXPORT_SYMBOL(wx_napi_disable_all);
@@ -2197,8 +2296,10 @@ irqreturn_t wx_msix_clean_rings(int __always_unused irq, void *data)
        struct wx_q_vector *q_vector = data;
 
        /* EIAM disabled interrupts (on this vector) for us */
-       if (q_vector->rx.ring || q_vector->tx.ring)
+       if (q_vector->rx.ring || q_vector->tx.ring) {
                napi_schedule_irqoff(&q_vector->napi);
+               q_vector->total_events++;
+       }
 
        return IRQ_HANDLED;
 }
index 9d5d10f9e41079cceb2c1db7eae670e641f793f5..ec63e7ec8b2421aa7f4d7c43c7f562fa1f1cd545 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
 #include <linux/phylink.h>
+#include <linux/dim.h>
 #include <net/ip.h>
 
 #define WX_NCSI_SUP                             0x8000
@@ -1033,6 +1034,7 @@ struct wx_ring_container {
        unsigned int total_packets;     /* total packets processed this int */
        u8 count;                       /* total number of rings in vector */
        u8 itr;                         /* current ITR setting for ring */
+       struct dim dim;                 /* data for net_dim algorithm */
 };
 struct wx_ring {
        struct wx_ring *next;           /* pointer to next ring in q_vector */
@@ -1089,6 +1091,8 @@ struct wx_q_vector {
        struct napi_struct napi;
        struct rcu_head rcu;    /* to avoid race with update stats on free */
 
+       u16 total_events;       /* number of interrupts processed */
+
        char name[IFNAMSIZ + 17];
 
        /* for dynamic allocation of rings associated with this q_vector */
@@ -1268,6 +1272,7 @@ struct wx {
        int num_rx_queues;
        u16 rx_itr_setting;
        u16 rx_work_limit;
+       bool adaptive_itr;
 
        int num_q_vectors;      /* current number of q_vectors for device */
        int max_q_vectors;      /* upper limit of q_vectors for device */
index 3023ea2732ef2d79a803e3d07ec24e4700f979a5..a87887b9f8ee345e326d298fa203719cf2c46410 100644 (file)
@@ -10,7 +10,7 @@
 #include "wx_vf.h"
 #include "wx_vf_lib.h"
 
-static void wx_write_eitr_vf(struct wx_q_vector *q_vector)
+void wx_write_eitr_vf(struct wx_q_vector *q_vector)
 {
        struct wx *wx = q_vector->wx;
        int v_idx = q_vector->v_idx;
index 43ea126b79eb7961f7921a301e402102332c97ff..a4bd23c9280012b5f0948082f717b38c3afced2b 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef _WX_VF_LIB_H_
 #define _WX_VF_LIB_H_
 
+void wx_write_eitr_vf(struct wx_q_vector *q_vector);
 void wx_configure_msix_vf(struct wx *wx);
 int wx_write_uc_addr_list_vf(struct net_device *netdev);
 void wx_setup_psrtype_vf(struct wx *wx);
index 7e2d9ec38a3062447e45fe75e7a55be602aa2523..4363bab3349687e83675b9ffdabab85c27083f86 100644 (file)
@@ -115,7 +115,8 @@ static int ngbe_set_channels(struct net_device *dev,
 
 static const struct ethtool_ops ngbe_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
-                                    ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
+                                    ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ |
+                                    ETHTOOL_COALESCE_USE_ADAPTIVE,
        .get_drvinfo            = wx_get_drvinfo,
        .get_link               = ethtool_op_get_link,
        .get_link_ksettings     = wx_get_link_ksettings,
index 3fff73ae44af539603fc4b57fe3e36b222676025..58488e138beb4321f49fdf773f481abf6310192a 100644 (file)
@@ -119,6 +119,7 @@ static int ngbe_sw_init(struct wx *wx)
                                                   num_online_cpus());
        wx->rss_enabled = true;
 
+       wx->adaptive_itr = false;
        wx->rx_itr_setting = WX_7K_ITR;
        wx->tx_itr_setting = WX_7K_ITR;
 
index c1246ab5239c9b0f4e17c0c99b6b9992cf49f20c..5f9ddb5e5403c25c15c749ceb8e4c5b475f53e03 100644 (file)
@@ -100,6 +100,7 @@ static int ngbevf_sw_init(struct wx *wx)
        wx->mac.max_tx_queues = NGBEVF_MAX_TX_QUEUES;
        wx->mac.max_rx_queues = NGBEVF_MAX_RX_QUEUES;
        /* Enable dynamic interrupt throttling rates */
+       wx->adaptive_itr = true;
        wx->rx_itr_setting = 1;
        wx->tx_itr_setting = 1;
        /* set default ring sizes */
index a4753402660e18f0aaa85165e3ec064b9ae4f3af..b496ec502feda7f8f07328de7bbe1fc593531d58 100644 (file)
@@ -538,7 +538,8 @@ static int txgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
 
 static const struct ethtool_ops txgbe_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
-                                    ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
+                                    ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ |
+                                    ETHTOOL_COALESCE_USE_ADAPTIVE,
        .get_drvinfo            = wx_get_drvinfo,
        .nway_reset             = wx_nway_reset,
        .get_link               = ethtool_op_get_link,
index a5867f3c93fc313d33ee47d1763e76956864a883..c4c4d70d8466a8ada27c35a4235deb2d1b6cbbc8 100644 (file)
@@ -401,6 +401,7 @@ static int txgbe_sw_init(struct wx *wx)
        set_bit(WX_FLAG_MULTI_64_FUNC, wx->flags);
 
        /* enable itr by default in dynamic mode */
+       wx->adaptive_itr = true;
        wx->rx_itr_setting = 1;
        wx->tx_itr_setting = 1;
 
index ebfce3cf753edb4a76ee7a2979e3131e9bf04865..3755bb399f71906e261ebb6ddffb4e29a9f1b58f 100644 (file)
@@ -144,6 +144,7 @@ static int txgbevf_sw_init(struct wx *wx)
        wx->mac.max_tx_queues = TXGBEVF_MAX_TX_QUEUES;
        wx->mac.max_rx_queues = TXGBEVF_MAX_RX_QUEUES;
        /* Enable dynamic interrupt throttling rates */
+       wx->adaptive_itr = true;
        wx->rx_itr_setting = 1;
        wx->tx_itr_setting = 1;
        /* set default ring sizes */