net: wangxun: support to use adaptive RX/TX coalescing

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>
This commit is contained in:
Jiawen Wu
2025-08-21 10:34:08 +08:00
committed by Jakub Kicinski
parent 5f43f2171a
commit 40477b8bb0
12 changed files with 141 additions and 7 deletions

View 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.

View 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;

View 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;
}

View 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 */

View 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;

View 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);

View 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,

View 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;

View 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 */

View 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,

View 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;

View 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 */