> -----Original Message-----
> From: Jagielski, Jedrzej <[email protected]>
> Sent: Monday, June 1, 2026 5:39 AM
> To: Haiyang Zhang <[email protected]>; linux-
> [email protected]; [email protected]; KY Srinivasan
> <[email protected]>; Haiyang Zhang <[email protected]>; Wei Liu
> <[email protected]>; Dexuan Cui <[email protected]>; Long Li
> <[email protected]>; Andrew Lunn <[email protected]>; David S.
> Miller <[email protected]>; Eric Dumazet <[email protected]>; Jakub
> Kicinski <[email protected]>; Paolo Abeni <[email protected]>; Konstantin
> Taranov <[email protected]>; Simon Horman <[email protected]>;
> Shradha Gupta <[email protected]>; Erni Sri Satya Vennela
> <[email protected]>; Dipayaan Roy
> <[email protected]>; Aditya Garg
> <[email protected]>; Kees Cook <[email protected]>; Breno
> Leitao <[email protected]>; [email protected]; linux-
> [email protected]
> Cc: Paul Rosswurm <[email protected]>
> Subject: [EXTERNAL] RE: [PATCH net-next] net: mana: Add Interrupt
> Moderation support
>
> [Niekt?re osoby, kt?re odebra?y t? wiadomo??, nie otrzymuj? cz?sto
> wiadomo?ci e-mail z [email protected]. Dowiedz si?, dlaczego
> jest to wa?ne, na stronie https://aka.ms/LearnAboutSenderIdentification ]
>
> From: Haiyang Zhang <[email protected]>
> Sent: Saturday, May 30, 2026 9:50 PM
>
> >From: Haiyang Zhang <[email protected]>
> >
> >Add Static and Dynamic Interrupt Moderation (DIM) support for
> >Rx and Tx.
> >Update queue creation procedure with new data struct with the related
> >settings.
> >Add functions to collect stat for DIM, and workers to update DIM data
> >and settings.
> >Update ethtool handler to get/set the moderation settings from a user.
> >By default, adaptive-rx/tx (DIM) are enabled.
> >
> >Signed-off-by: Haiyang Zhang <[email protected]>
> >---
> > drivers/net/ethernet/microsoft/Kconfig | 1 +
> > .../net/ethernet/microsoft/mana/gdma_main.c | 27 ++++
> > drivers/net/ethernet/microsoft/mana/mana_en.c | 101 ++++++++++++++-
> > .../ethernet/microsoft/mana/mana_ethtool.c | 120 +++++++++++++++++-
> > include/net/mana/gdma.h | 24 +++-
> > include/net/mana/mana.h | 42 ++++++
> > 6 files changed, 309 insertions(+), 6 deletions(-)
> >
> >diff --git a/drivers/net/ethernet/microsoft/Kconfig
> b/drivers/net/ethernet/microsoft/Kconfig
> >index 3f36ee6a8ece..e9be18c92ca5 100644
> >--- a/drivers/net/ethernet/microsoft/Kconfig
> >+++ b/drivers/net/ethernet/microsoft/Kconfig
> >@@ -21,6 +21,7 @@ config MICROSOFT_MANA
> > depends on X86_64 || (ARM64 && !CPU_BIG_ENDIAN)
> > depends on PCI_HYPERV
> > select AUXILIARY_BUS
> >+ select DIMLIB
> > select PAGE_POOL
> > select NET_SHAPER
> > help
> >diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> >index 712a0881d720..5aa0ea794a00 100644
> >--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> >+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> >@@ -405,6 +405,7 @@ static int mana_gd_disable_queue(struct gdma_queue
> *queue)
> > #define DOORBELL_OFFSET_RQ 0x400
> > #define DOORBELL_OFFSET_CQ 0x800
> > #define DOORBELL_OFFSET_EQ 0xFF8
> >+#define DOORBELL_OFFSET_DIM 0x820
> >
> > static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
> > enum gdma_queue_type q_type, u32 qid,
> >@@ -445,6 +446,16 @@ static void mana_gd_ring_doorbell(struct
> gdma_context *gc, u32 db_index,
> > addr += DOORBELL_OFFSET_SQ;
> > break;
> >
> >+ case GDMA_DIM:
> >+ e.dim.id = qid;
> >+ e.dim.mod_usec = tail_ptr;
> >+ e.dim.mod_usec_vld = tail_ptr >> 15;
> >+ e.dim.mod_comps = tail_ptr >> 16;
>
> please use defines instead of magic
Will do.
>
> >+ e.dim.mod_comps_vld = num_req;
> >+
> >+ addr += DOORBELL_OFFSET_DIM;
> >+ break;
> >+
> > default:
> > WARN_ON(1);
> > return;
> >@@ -479,6 +490,22 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8
> arm_bit)
> > }
> > EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA");
> >
> >+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool
> mod_usec_vld,
> >+ u32 mod_comps, bool mod_comps_vld)
> >+{
> >+ struct gdma_context *gc = cq->gdma_dev->gdma_context;
> >+ u32 dim_val;
> >+
> >+ /* Convert the DIM values to doorbell parameters */
> >+ dim_val = (mod_usec & MANA_INTR_MODR_USEC_MAX) |
> >+ (((u32)mod_usec_vld & 1) << 15) |
> >+ ((mod_comps & MANA_INTR_MODR_COMP_MAX) << 16);
>
> i believe FIELD_PREP if preferrable in such cases
Will do.
>
> >+
> >+ mana_gd_ring_doorbell(gc, cq->gdma_dev->doorbell, GDMA_DIM, cq-
> >id,
> >+ dim_val, (u8)mod_comps_vld & 1);
> >+}
> >+EXPORT_SYMBOL_NS(mana_gd_ring_dim, "NET_MANA");
> >+
> > #define MANA_SERVICE_PERIOD 10
> >
> > static void mana_serv_rescan(struct pci_dev *pdev)
> >diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c
> b/drivers/net/ethernet/microsoft/mana/mana_en.c
> >index 82f1461a48e9..f1a16f8aca66 100644
> >--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
> >+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> >@@ -1551,6 +1551,9 @@ int mana_create_wq_obj(struct mana_port_context
> *apc,
> >
> > mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ,
> > sizeof(req), sizeof(resp));
> >+
> >+ req.hdr.req.msg_version = GDMA_MESSAGE_V3;
> >+ req.hdr.resp.msg_version = GDMA_MESSAGE_V2;
> > req.vport = vport;
> > req.wq_type = wq_type;
> > req.wq_gdma_region = wq_spec->gdma_region;
> >@@ -1559,6 +1562,9 @@ int mana_create_wq_obj(struct mana_port_context
> *apc,
> > req.cq_size = cq_spec->queue_size;
> > req.cq_moderation_ctx_id = cq_spec->modr_ctx_id;
> > req.cq_parent_qid = cq_spec->attached_eq;
> >+ req.req_cq_moderation = cq_spec->req_cq_moderation;
> >+ req.cq_moderation_comp = cq_spec->cq_moderation_comp;
> >+ req.cq_moderation_usec = cq_spec->cq_moderation_usec;
> >
> > err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
> > sizeof(resp));
> >@@ -2253,6 +2259,66 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
> > xdp_do_flush();
> > }
> >
> >+static void mana_rx_dim_work(struct work_struct *work)
> >+{
> >+ struct dim *dim = container_of(work, struct dim, work);
> >+ struct mana_cq *cq = container_of(dim, struct mana_cq, dim);
> >+ struct dim_cq_moder cur_moder =
> >+ net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
>
> RCT; here and for following
Will update this and below.
>
> >+
> >+ cur_moder.usec = min_t(u16, cur_moder.usec,
> MANA_INTR_MODR_USEC_MAX);
> >+ cur_moder.pkts = min_t(u16, cur_moder.pkts,
> MANA_INTR_MODR_COMP_MAX);
> >+
> >+ mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
> >+ cur_moder.pkts, true);
> >+
> >+ dim->state = DIM_START_MEASURE;
> >+}
> >+
> >+static void mana_tx_dim_work(struct work_struct *work)
> >+{
> >+ struct dim *dim = container_of(work, struct dim, work);
> >+ struct mana_cq *cq = container_of(dim, struct mana_cq, dim);
> >+ struct dim_cq_moder cur_moder =
> >+ net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
> >+
> >+ cur_moder.usec = min_t(u16, cur_moder.usec,
> MANA_INTR_MODR_USEC_MAX);
> >+ cur_moder.pkts = min_t(u16, cur_moder.pkts,
> MANA_INTR_MODR_COMP_MAX);
> >+
> >+ mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
> >+ cur_moder.pkts, true);
> >+
> >+ dim->state = DIM_START_MEASURE;
> >+}
> >+
> >+static void mana_update_rx_dim(struct mana_cq *cq)
> >+{
> >+ struct mana_rxq *rxq = cq->rxq;
> >+ struct mana_port_context *apc = netdev_priv(rxq->ndev);
> >+ struct dim_sample dim_sample = {};
> >+
> >+ if (!apc->rx_dim_enabled)
> >+ return;
> >+
> >+ dim_update_sample(READ_ONCE(cq->dim_event_ctr), rxq-
> >stats.packets,
> >+ rxq->stats.bytes, &dim_sample);
> >+ net_dim(&cq->dim, &dim_sample);
> >+}
> >+
> >+static void mana_update_tx_dim(struct mana_cq *cq)
> >+{
> >+ struct mana_txq *txq = cq->txq;
> >+ struct mana_port_context *apc = netdev_priv(txq->ndev);
> >+ struct dim_sample dim_sample = {};
> >+
> >+ if (!apc->tx_dim_enabled)
> >+ return;
> >+
> >+ dim_update_sample(READ_ONCE(cq->dim_event_ctr), txq-
> >stats.packets,
> >+ txq->stats.bytes, &dim_sample);
> >+ net_dim(&cq->dim, &dim_sample);
> >+}
> >+
> > static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
> > {
> > struct mana_cq *cq = context;
> >@@ -2271,7 +2337,13 @@ static int mana_cq_handler(void *context, struct
> gdma_queue *gdma_queue)
> > if (w < cq->budget) {
> > mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
> > cq->work_done_since_doorbell = 0;
> >- napi_complete_done(&cq->napi, w);
> >+
> >+ if (napi_complete_done(&cq->napi, w)) {
> >+ if (cq->type == MANA_CQ_TYPE_RX)
> >+ mana_update_rx_dim(cq);
> >+ else
> >+ mana_update_tx_dim(cq);
> >+ }
> > } else if (cq->work_done_since_doorbell >=
> > (cq->gdma_cq->queue_size / COMP_ENTRY_SIZE) * 4) {
> > /* MANA hardware requires at least one doorbell ring every
> 8
> >@@ -2303,6 +2375,7 @@ static void mana_schedule_napi(void *context,
> struct gdma_queue *gdma_queue)
> > {
> > struct mana_cq *cq = context;
> >
> >+ WRITE_ONCE(cq->dim_event_ctr, cq->dim_event_ctr + 1);
> > napi_schedule_irqoff(&cq->napi);
> > }
> >
> >@@ -2345,6 +2418,7 @@ static void mana_destroy_txq(struct
> mana_port_context *apc)
> > if (apc->tx_qp[i]->txq.napi_initialized) {
> > napi_synchronize(napi);
> > napi_disable_locked(napi);
> >+ cancel_work_sync(&apc->tx_qp[i]->tx_cq.dim.work);
> > netif_napi_del_locked(napi);
> > apc->tx_qp[i]->txq.napi_initialized = false;
> > }
> >@@ -2475,6 +2549,10 @@ static int mana_create_txq(struct
> mana_port_context *apc,
> > cq_spec.queue_size = cq->gdma_cq->queue_size;
> > cq_spec.modr_ctx_id = 0;
> > cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
> >+ cq_spec.req_cq_moderation = apc->tx_dim_enabled ||
> >+ (apc->intr_modr_tx_usec && apc-
> >intr_modr_tx_comp);
> >+ cq_spec.cq_moderation_usec = apc->intr_modr_tx_usec;
> >+ cq_spec.cq_moderation_comp = apc->intr_modr_tx_comp;
> >
> > err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ,
> > &wq_spec, &cq_spec,
> >@@ -2509,6 +2587,9 @@ static int mana_create_txq(struct mana_port_context
> *apc,
> > napi_enable_locked(&cq->napi);
> > txq->napi_initialized = true;
> >
> >+ INIT_WORK(&cq->dim.work, mana_tx_dim_work);
> >+ cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
> >+
> > mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
> > }
> >
> >@@ -2543,6 +2624,7 @@ static void mana_destroy_rxq(struct
> mana_port_context *apc,
> > napi_synchronize(napi);
> >
> > napi_disable_locked(napi);
> >+ cancel_work_sync(&rxq->rx_cq.dim.work);
> > netif_napi_del_locked(napi);
> > }
> >
> >@@ -2780,6 +2862,10 @@ static struct mana_rxq *mana_create_rxq(struct
> mana_port_context *apc,
> > cq_spec.queue_size = cq->gdma_cq->queue_size;
> > cq_spec.modr_ctx_id = 0;
> > cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
> >+ cq_spec.req_cq_moderation = apc->rx_dim_enabled ||
> >+ (apc->intr_modr_rx_usec && apc->intr_modr_rx_comp);
> >+ cq_spec.cq_moderation_usec = apc->intr_modr_rx_usec;
> >+ cq_spec.cq_moderation_comp = apc->intr_modr_rx_comp;
> >
> > err = mana_create_wq_obj(apc, apc->port_handle, GDMA_RQ,
> > &wq_spec, &cq_spec, &rxq->rxobj);
> >@@ -2815,6 +2901,9 @@ static struct mana_rxq *mana_create_rxq(struct
> mana_port_context *apc,
> >
> > napi_enable_locked(&cq->napi);
> >
> >+ INIT_WORK(&cq->dim.work, mana_rx_dim_work);
> >+ cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
> >+
> > mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
> > out:
> > if (!err)
> >@@ -3432,6 +3521,16 @@ static int mana_probe_port(struct mana_context
> *ac, int port_idx,
> > apc->port_idx = port_idx;
> > apc->cqe_coalescing_enable = 0;
> >
> >+ /* Initialize interrupt moderation settings if supported by HW */
> >+ if (gc->pf_cap_flags1 &
> GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION) {
> >+ apc->intr_modr_rx_usec = MANA_INTR_MODR_USEC_DEF;
> >+ apc->intr_modr_rx_comp = MANA_INTR_MODR_COMP_DEF;
> >+ apc->intr_modr_tx_usec = MANA_INTR_MODR_USEC_DEF;
> >+ apc->intr_modr_tx_comp = MANA_INTR_MODR_COMP_DEF;
> >+ apc->rx_dim_enabled = MANA_ADAPTIVE_RX_DEF;
> >+ apc->tx_dim_enabled = MANA_ADAPTIVE_TX_DEF;
> >+ }
> >+
> > 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 04350973e19e..a90216eba794 100644
> >--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
> >+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
> >@@ -419,6 +419,15 @@ static int mana_get_coalesce(struct net_device
> *ndev,
> > !kernel_coal->rx_cqe_nsecs)
> > kernel_coal->rx_cqe_nsecs = MANA_RX_CQE_NSEC_DEF;
> >
> >+ ec->rx_coalesce_usecs = apc->intr_modr_rx_usec;
> >+ ec->rx_max_coalesced_frames = apc->intr_modr_rx_comp;
> >+
> >+ ec->tx_coalesce_usecs = apc->intr_modr_tx_usec;
> >+ ec->tx_max_coalesced_frames = apc->intr_modr_tx_comp;
> >+
> >+ ec->use_adaptive_rx_coalesce = apc->rx_dim_enabled;
> >+ ec->use_adaptive_tx_coalesce = apc->tx_dim_enabled;
> >+
> > return 0;
> > }
> >
> >@@ -429,8 +438,28 @@ static int mana_set_coalesce(struct net_device
> *ndev,
> > {
> > struct mana_port_context *apc = netdev_priv(ndev);
> > u8 saved_cqe_coalescing_enable;
> >+ u16 old_rx_usec, old_rx_comp;
> >+ u16 old_tx_usec, old_tx_comp;
> >+ bool old_rx_dim, old_tx_dim;
>
> how about using some sort of struct instead of declaring a number
> of params for bookkeeping? imho would be cleaner
Will consider this.
>
> >+ bool modr_changed = false;
> >+ bool dim_changed = false;
> >+ struct gdma_context *gc;
> > int err;
> >
> >+ gc = apc->ac->gdma_dev->gdma_context;
> >+
> >+ /* Both static and dynamic interrupt moderation (DIM) rely on the
> >+ * same HW capability advertised by the PF.
> >+ */
> >+ if ((ec->use_adaptive_rx_coalesce || ec->use_adaptive_tx_coalesce
> ||
> >+ ec->rx_coalesce_usecs || ec->tx_coalesce_usecs ||
> >+ ec->rx_max_coalesced_frames || ec->tx_max_coalesced_frames)
> &&
> >+ !(gc->pf_cap_flags1 &
> GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)) {
> >+ NL_SET_ERR_MSG(extack,
> >+ "Interrupt Moderation is not supported by
> HW");
> >+ return -EOPNOTSUPP;
> >+ }
> >+
> > if (kernel_coal->rx_cqe_frames != 1 &&
> > kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI) {
> > NL_SET_ERR_MSG_FMT(extack,
> >@@ -440,6 +469,47 @@ static int mana_set_coalesce(struct net_device
> *ndev,
> > return -EINVAL;
> > }
> >
> >+ if (ec->rx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX ||
> >+ ec->tx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX) {
> >+ NL_SET_ERR_MSG_FMT(extack,
> >+ "coalesce usecs must be <= %u",
> >+ MANA_INTR_MODR_USEC_MAX);
> >+ return -EINVAL;
> >+ }
> >+
> >+ if (ec->rx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX ||
> >+ ec->tx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX) {
> >+ NL_SET_ERR_MSG_FMT(extack,
> >+ "coalesce frames must be <= %u",
> >+ MANA_INTR_MODR_COMP_MAX);
> >+ return -EINVAL;
> >+ }
> >+
> >+ if (ec->rx_coalesce_usecs != apc->intr_modr_rx_usec ||
> >+ ec->rx_max_coalesced_frames != apc->intr_modr_rx_comp ||
> >+ ec->tx_coalesce_usecs != apc->intr_modr_tx_usec ||
> >+ ec->tx_max_coalesced_frames != apc->intr_modr_tx_comp)
> >+ modr_changed = true;
> >+
> >+ old_rx_usec = apc->intr_modr_rx_usec;
> >+ old_rx_comp = apc->intr_modr_rx_comp;
> >+ old_tx_usec = apc->intr_modr_tx_usec;
> >+ old_tx_comp = apc->intr_modr_tx_comp;
> >+
> >+ apc->intr_modr_rx_usec = ec->rx_coalesce_usecs;
> >+ apc->intr_modr_rx_comp = ec->rx_max_coalesced_frames;
> >+ apc->intr_modr_tx_usec = ec->tx_coalesce_usecs;
> >+ apc->intr_modr_tx_comp = ec->tx_max_coalesced_frames;
> >+
> >+ if (!!ec->use_adaptive_rx_coalesce != apc->rx_dim_enabled ||
> >+ !!ec->use_adaptive_tx_coalesce != apc->tx_dim_enabled)
> >+ dim_changed = true;
> >+
> >+ old_rx_dim = apc->rx_dim_enabled;
> >+ old_tx_dim = apc->tx_dim_enabled;
> >+ apc->rx_dim_enabled = !!ec->use_adaptive_rx_coalesce;
> >+ apc->tx_dim_enabled = !!ec->use_adaptive_tx_coalesce;
> >+
> > saved_cqe_coalescing_enable = apc->cqe_coalescing_enable;
> > apc->cqe_coalescing_enable =
> > kernel_coal->rx_cqe_frames == MANA_RXCOMP_OOB_NUM_PPI;
> >@@ -447,10 +517,46 @@ static int mana_set_coalesce(struct net_device
> *ndev,
> > if (!apc->port_is_up)
> > return 0;
> >
> >- err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
> >- if (err)
> >- apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
> >+ if (apc->cqe_coalescing_enable != saved_cqe_coalescing_enable &&
> >+ !modr_changed && !dim_changed) {
> >+ /* If only CQE coalescing setting is changed, we can just
> update
> >+ * RSS configuration.
> >+ */
> >+ err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
> >+ if (err) {
> >+ netdev_err(ndev, "Change CQE coalescing
> failed: %d\n",
> >+ err);
> >+ apc->cqe_coalescing_enable =
> >+ saved_cqe_coalescing_enable;
> >+ return err;
> >+ }
> >+ return 0;
> >+ }
> >+
> >+ if (modr_changed || dim_changed) {
> >+ err = mana_detach(ndev, false);
> >+ if (err) {
> >+ netdev_err(ndev, "mana_detach failed: %d\n", err);
> >+ goto restore_modr;
> >+ }
> >+
> >+ err = mana_attach(ndev);
> >+ if (err) {
> >+ netdev_err(ndev, "mana_attach failed: %d\n", err);
> >+ goto restore_modr;
>
> i see there is already such pattern in the mana code; how about
> creating a helper?
We are planning to update this pattern. So I keep this part of code like
other functions. And we will refactor/update them in separate patch set.
>
> >+ }
> >+ }
> >+
> >+ return 0;
> >
> >+restore_modr:
> >+ apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
> >+ apc->intr_modr_rx_usec = old_rx_usec;
> >+ apc->intr_modr_rx_comp = old_rx_comp;
> >+ apc->intr_modr_tx_usec = old_tx_usec;
> >+ apc->intr_modr_tx_comp = old_tx_comp;
> >+ apc->rx_dim_enabled = old_rx_dim;
> >+ apc->tx_dim_enabled = old_tx_dim;
> > return err;
> > }
> >
> >@@ -574,7 +680,13 @@ static int mana_get_link_ksettings(struct net_device
> *ndev,
> > }
> >
> > const struct ethtool_ops mana_ethtool_ops = {
> >- .supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES,
> >+ .supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES |
> >+ ETHTOOL_COALESCE_RX_USECS |
> >+ ETHTOOL_COALESCE_RX_MAX_FRAMES |
> >+ ETHTOOL_COALESCE_TX_USECS |
> >+ ETHTOOL_COALESCE_TX_MAX_FRAMES |
> >+ ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
> >+ ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
> > .get_ethtool_stats = mana_get_ethtool_stats,
> > .get_sset_count = mana_get_sset_count,
> > .get_strings = mana_get_strings,
> >diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
> >index 70d62bc32837..0a0cc7b080d3 100644
> >--- a/include/net/mana/gdma.h
> >+++ b/include/net/mana/gdma.h
> >@@ -47,6 +47,7 @@ enum gdma_queue_type {
> > GDMA_RQ,
> > GDMA_CQ,
> > GDMA_EQ,
> >+ GDMA_DIM,
> > };
> >
> > enum gdma_work_request_flags {
> >@@ -126,6 +127,17 @@ union gdma_doorbell_entry {
> > u64 tail_ptr : 31;
> > u64 arm : 1;
> > } eq;
> >+
> >+ struct {
> >+ u64 id : 24;
> >+ u64 reserved : 8;
> >+ u64 mod_usec : 10;
> >+ u64 reserve1 : 5;
> >+ u64 mod_usec_vld : 1;
> >+ u64 mod_comps : 8;
> >+ u64 reserve2 : 7;
> >+ u64 mod_comps_vld: 1;
> >+ } dim;
> > }; /* HW DATA */
> >
> > struct gdma_msg_hdr {
> >@@ -484,6 +496,9 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8
> arm_bit);
> >
> > int mana_schedule_serv_work(struct gdma_context *gc, enum gdma_eqe_type
> type);
> >
> >+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool
> mod_usec_vld,
> >+ u32 mod_comps, bool mod_comps_vld);
> >+
> > struct gdma_wqe {
> > u32 reserved :24;
> > u32 last_vbytes :8;
> >@@ -629,6 +644,9 @@ enum {
> > /* Driver supports self recovery on Hardware Channel timeouts */
> > #define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY BIT(25)
> >
> >+/* Driver supports dynamic interrupt moderation - DIM */
> >+#define GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(27)
> >+
> > #define GDMA_DRV_CAP_FLAGS1 \
> > (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
> > GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
> >@@ -643,7 +661,8 @@ enum {
> > GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE | \
> > GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY | \
> > GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY | \
> >- GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY)
> >+ GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY | \
> >+ GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)
> >
> > #define GDMA_DRV_CAP_FLAGS2 0
> >
> >@@ -679,6 +698,9 @@ struct gdma_verify_ver_req {
> > u8 os_ver_str4[128];
> > }; /* HW DATA */
> >
> >+/* HW supports dynamic interrupt moderation - DIM */
> >+#define GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(15)
> >+
> > struct gdma_verify_ver_resp {
> > struct gdma_resp_hdr hdr;
> > u64 gdma_protocol_ver;
> >diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
> >index d9c27310fd04..57868a79f23d 100644
> >--- a/include/net/mana/mana.h
> >+++ b/include/net/mana/mana.h
> >@@ -4,6 +4,7 @@
> > #ifndef _MANA_H
> > #define _MANA_H
> >
> >+#include <linux/dim.h>
> > #include <net/xdp.h>
> > #include <net/net_shaper.h>
> >
> >@@ -64,6 +65,16 @@ enum TRI_STATE {
> > /* Maximum number of packets per coalesced CQE */
> > #define MANA_RXCOMP_OOB_NUM_PPI 4
> >
> >+/* Default/max interrupt moderation settings */
> >+#define MANA_INTR_MODR_USEC_DEF 0
> >+#define MANA_INTR_MODR_COMP_DEF 0
> >+
> >+#define MANA_ADAPTIVE_RX_DEF true
> >+#define MANA_ADAPTIVE_TX_DEF true
> >+
> >+#define MANA_INTR_MODR_USEC_MAX 1023
> >+#define MANA_INTR_MODR_COMP_MAX 255
>
> used as a limiter and mask - for mask case i believe
> GENMASK cand be used
Will do.
Thanks,
- Haiyang