From nobody Tue Dec 2 02:32:17 2025 Received: from canpmsgout08.his.huawei.com (canpmsgout08.his.huawei.com [113.46.200.223]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 00F0F35C187; Wed, 19 Nov 2025 12:44:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.223 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556259; cv=none; b=ZZCDi58JsbsO17fJVEIOzexmDJbggvoeEJhu6OyEntYztQ2Hk9+iZ1sXMjkBuyjMSnwrDnA1m6DXCcARJPg8Jend99+5MPo9HDjLFq4Q+DX82BPJ9WBrXrQ1wmBl0UcfiUm/+VgM+bYh+6Pam3WJNdiJbLPVz4JKL3C31OI82jc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556259; c=relaxed/simple; bh=W5tawXfsztBHT8hOUA45GhiteEwC32cY4ASs9rXQY9s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oLooyFlxVsuBjZgU9nhdO1WuQNS1AgWFuCVWcd356riUr3XMZmg+i8HdCnbs6VNMD2BOBYqx9SZfSlIPhu0zg9udfkvURiJQfqDGWT714dCRg6wtcyCGKbu2c0TLR03lwLt3N7X/pFjxGTTKlstNYeHNzghNukIvjKxEJTfop68= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=qDV3rcDY; arc=none smtp.client-ip=113.46.200.223 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="qDV3rcDY" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=1+0kD77YeFH8ntwK9CXlH6A6jeGUZigdSSODvB3+vT4=; b=qDV3rcDYWCgsLUqb0Ib8f8oLc25iWMSTBu8YVeXL5oCVUMxQNLii08NBKDBkT5K76cU84tkyk iHwfZa9vVNBbR7SWrzyFJ3JLEpuxV7AG9hi8OZHntI5CHD1sZIVogEzwRzDkNWviHjCxap8r7NX MepYWsiwXj7dnHbc2oXEtkQ= Received: from mail.maildlp.com (unknown [172.19.88.214]) by canpmsgout08.his.huawei.com (SkyGuard) with ESMTPS id 4dBLjH0hxCzmV82; Wed, 19 Nov 2025 20:42:27 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 12DE61A016C; Wed, 19 Nov 2025 20:44:11 +0800 (CST) Received: from DESKTOP-62GVMTR.china.huawei.com (10.174.188.120) by kwepemf100013.china.huawei.com (7.202.181.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Wed, 19 Nov 2025 20:44:09 +0800 From: Fan Gong To: Fan Gong , Zhu Yikai , , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrew Lunn , Markus Elfring , Pavan Chebbi , ALOK TIWARI CC: , , luosifu , Xin Guo , Shen Chenyang , Zhou Shuai , Wu Like , Shi Jing , Luo Yang , Meny Yossefi , Gur Stavi Subject: [PATCH net-next v07 6/9] hinic3: Add adaptive IRQ coalescing with DIM Date: Wed, 19 Nov 2025 20:43:39 +0800 Message-ID: X-Mailer: git-send-email 2.51.0.windows.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: kwepems200002.china.huawei.com (7.221.188.68) To kwepemf100013.china.huawei.com (7.202.181.12) Content-Type: text/plain; charset="utf-8" DIM offers a way to adjust the coalescing settings based on load. As hinic3 rx and tx share interrupts, we only need to base dim on rx stats. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../ethernet/huawei/hinic3/hinic3_hw_comm.c | 54 +++++++++++ .../ethernet/huawei/hinic3/hinic3_hw_comm.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_hwdev.c | 2 +- .../net/ethernet/huawei/hinic3/hinic3_irq.c | 96 ++++++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_main.c | 14 ++- .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 5 + .../net/ethernet/huawei/hinic3/hinic3_rx.h | 6 ++ 7 files changed, 174 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_comm.c index 3ee1ca3c83ad..ecfe6265954e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c @@ -9,6 +9,36 @@ #include "hinic3_hwif.h" #include "hinic3_mbox.h" =20 +static int hinic3_get_interrupt_cfg(struct hinic3_hwdev *hwdev, + struct hinic3_interrupt_info *info) +{ + struct comm_cmd_cfg_msix_ctrl_reg msix_cfg =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + msix_cfg.func_id =3D hinic3_global_func_id(hwdev); + msix_cfg.msix_index =3D info->msix_index; + msix_cfg.opcode =3D MGMT_MSG_CMD_OP_GET; + + mgmt_msg_params_init_default(&msg_params, &msix_cfg, sizeof(msix_cfg)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, + COMM_CMD_CFG_MSIX_CTRL_REG, &msg_params); + if (err || msix_cfg.head.status) { + dev_err(hwdev->dev, "Failed to get interrupt config, err: %d, status: 0x= %x\n", + err, msix_cfg.head.status); + return -EFAULT; + } + + info->lli_credit_limit =3D msix_cfg.lli_credit_cnt; + info->lli_timer_cfg =3D msix_cfg.lli_timer_cnt; + info->pending_limit =3D msix_cfg.pending_cnt; + info->coalesc_timer_cfg =3D msix_cfg.coalesce_timer_cnt; + info->resend_timer_cfg =3D msix_cfg.resend_timer_cnt; + + return 0; +} + int hinic3_set_interrupt_cfg_direct(struct hinic3_hwdev *hwdev, const struct hinic3_interrupt_info *info) { @@ -40,6 +70,30 @@ int hinic3_set_interrupt_cfg_direct(struct hinic3_hwdev = *hwdev, return 0; } =20 +int hinic3_set_interrupt_cfg(struct hinic3_hwdev *hwdev, + struct hinic3_interrupt_info info) +{ + struct hinic3_interrupt_info temp_info; + int err; + + temp_info.msix_index =3D info.msix_index; + + err =3D hinic3_get_interrupt_cfg(hwdev, &temp_info); + if (err) + return err; + + info.lli_credit_limit =3D temp_info.lli_credit_limit; + info.lli_timer_cfg =3D temp_info.lli_timer_cfg; + + if (!info.interrupt_coalesc_set) { + info.pending_limit =3D temp_info.pending_limit; + info.coalesc_timer_cfg =3D temp_info.coalesc_timer_cfg; + info.resend_timer_cfg =3D temp_info.resend_timer_cfg; + } + + return hinic3_set_interrupt_cfg_direct(hwdev, &info); +} + int hinic3_func_reset(struct hinic3_hwdev *hwdev, u16 func_id, u64 reset_f= lag) { struct comm_cmd_func_reset func_reset =3D {}; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_comm.h index c9c6b4fbcb12..8e4737c486b7 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h @@ -23,6 +23,8 @@ struct hinic3_interrupt_info { =20 int hinic3_set_interrupt_cfg_direct(struct hinic3_hwdev *hwdev, const struct hinic3_interrupt_info *info); +int hinic3_set_interrupt_cfg(struct hinic3_hwdev *hwdev, + struct hinic3_interrupt_info info); int hinic3_func_reset(struct hinic3_hwdev *hwdev, u16 func_id, u64 reset_f= lag); =20 int hinic3_get_comm_features(struct hinic3_hwdev *hwdev, u64 *s_feature, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.c index 25e375b20174..4048b3302db7 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c @@ -200,7 +200,7 @@ static int init_ceqs_msix_attr(struct hinic3_hwdev *hwd= ev) for (q_id =3D 0; q_id < ceqs->num_ceqs; q_id++) { eq =3D &ceqs->ceq[q_id]; info.msix_index =3D eq->msix_entry_idx; - err =3D hinic3_set_interrupt_cfg_direct(hwdev, &info); + err =3D hinic3_set_interrupt_cfg(hwdev, info); if (err) { dev_err(hwdev->dev, "Set msix attr for ceq %u failed\n", q_id); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/= ethernet/huawei/hinic3/hinic3_irq.c index a69b361225e9..604e09812977 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. =20 +#include #include =20 #include "hinic3_hw_comm.h" @@ -10,6 +11,22 @@ #include "hinic3_rx.h" #include "hinic3_tx.h" =20 +#define HINIC3_COAL_PKT_SHIFT 5 + +static void hinic3_net_dim(struct hinic3_nic_dev *nic_dev, + struct hinic3_irq_cfg *irq_cfg) +{ + struct hinic3_rxq *rxq =3D irq_cfg->rxq; + struct dim_sample sample =3D {}; + + if (!nic_dev->adaptive_rx_coal) + return; + + dim_update_sample(irq_cfg->total_events, rxq->rxq_stats.packets, + rxq->rxq_stats.bytes, &sample); + net_dim(&rxq->dim, &sample); +} + static int hinic3_poll(struct napi_struct *napi, int budget) { struct hinic3_irq_cfg *irq_cfg =3D @@ -31,9 +48,11 @@ static int hinic3_poll(struct napi_struct *napi, int bud= get) if (busy) return budget; =20 - if (likely(napi_complete_done(napi, work_done))) + if (likely(napi_complete_done(napi, work_done))) { + hinic3_net_dim(nic_dev, irq_cfg); hinic3_set_msix_state(nic_dev->hwdev, irq_cfg->msix_entry_idx, HINIC3_MSIX_ENABLE); + } =20 return work_done; } @@ -70,6 +89,8 @@ static irqreturn_t qp_irq(int irq, void *data) hinic3_msix_intr_clear_resend_bit(nic_dev->hwdev, irq_cfg->msix_entry_idx, 1); =20 + irq_cfg->total_events++; + napi_schedule(&irq_cfg->napi); =20 return IRQ_HANDLED; @@ -92,7 +113,7 @@ static int hinic3_request_irq(struct hinic3_irq_cfg *irq= _cfg, u16 q_id) info.coalesc_timer_cfg =3D nic_dev->intr_coalesce[q_id].coalesce_timer_cfg; info.resend_timer_cfg =3D nic_dev->intr_coalesce[q_id].resend_timer_cfg; - err =3D hinic3_set_interrupt_cfg_direct(nic_dev->hwdev, &info); + err =3D hinic3_set_interrupt_cfg(nic_dev->hwdev, info); if (err) { netdev_err(netdev, "Failed to set RX interrupt coalescing attribute.\n"); qp_del_napi(irq_cfg); @@ -117,6 +138,71 @@ static void hinic3_release_irq(struct hinic3_irq_cfg *= irq_cfg) free_irq(irq_cfg->irq_id, irq_cfg); } =20 +static int hinic3_set_interrupt_moder(struct net_device *netdev, u16 q_id, + u8 coalesc_timer_cfg, u8 pending_limit) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_interrupt_info info =3D {}; + int err; + + if (q_id >=3D nic_dev->q_params.num_qps) + return 0; + + info.interrupt_coalesc_set =3D 1; + info.coalesc_timer_cfg =3D coalesc_timer_cfg; + info.pending_limit =3D pending_limit; + info.msix_index =3D nic_dev->q_params.irq_cfg[q_id].msix_entry_idx; + info.resend_timer_cfg =3D + nic_dev->intr_coalesce[q_id].resend_timer_cfg; + + err =3D hinic3_set_interrupt_cfg(nic_dev->hwdev, info); + if (err) { + netdev_err(netdev, + "Failed to modify moderation for Queue: %u\n", q_id); + } else { + nic_dev->rxqs[q_id].last_coalesc_timer_cfg =3D coalesc_timer_cfg; + nic_dev->rxqs[q_id].last_pending_limit =3D pending_limit; + } + + return err; +} + +static void hinic3_update_queue_coal(struct net_device *netdev, u16 q_id, + u16 coal_timer, u16 coal_pkts) +{ + struct hinic3_intr_coal_info *q_coal; + u8 coalesc_timer_cfg, pending_limit; + struct hinic3_nic_dev *nic_dev; + + nic_dev =3D netdev_priv(netdev); + + q_coal =3D &nic_dev->intr_coalesce[q_id]; + coalesc_timer_cfg =3D (u8)coal_timer; + pending_limit =3D clamp_t(u8, coal_pkts >> HINIC3_COAL_PKT_SHIFT, + q_coal->rx_pending_limit_low, + q_coal->rx_pending_limit_high); + + hinic3_set_interrupt_moder(nic_dev->netdev, q_id, + coalesc_timer_cfg, pending_limit); +} + +static void hinic3_rx_dim_work(struct work_struct *work) +{ + struct dim_cq_moder cur_moder; + struct hinic3_rxq *rxq; + struct dim *dim; + + dim =3D container_of(work, struct dim, work); + rxq =3D container_of(dim, struct hinic3_rxq, dim); + + cur_moder =3D net_dim_get_rx_moderation(dim->mode, dim->profile_ix); + + hinic3_update_queue_coal(rxq->netdev, rxq->q_id, + cur_moder.usec, cur_moder.pkts); + + dim->state =3D DIM_START_MEASURE; +} + int hinic3_qps_irq_init(struct net_device *netdev) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); @@ -150,6 +236,9 @@ int hinic3_qps_irq_init(struct net_device *netdev) goto err_release_irqs; } =20 + INIT_WORK(&irq_cfg->rxq->dim.work, hinic3_rx_dim_work); + irq_cfg->rxq->dim.mode =3D DIM_CQ_PERIOD_MODE_START_FROM_CQE; + hinic3_set_msix_auto_mask_state(nic_dev->hwdev, irq_cfg->msix_entry_idx, HINIC3_SET_MSIX_AUTO_MASK); @@ -164,6 +253,9 @@ int hinic3_qps_irq_init(struct net_device *netdev) q_id--; irq_cfg =3D &nic_dev->q_params.irq_cfg[q_id]; qp_del_napi(irq_cfg); + + disable_work_sync(&irq_cfg->rxq->dim.work); + hinic3_set_msix_state(nic_dev->hwdev, irq_cfg->msix_entry_idx, HINIC3_MSIX_DISABLE); hinic3_set_msix_auto_mask_state(nic_dev->hwdev, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index f0f347c6b6ba..d085ddddbbd7 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -29,6 +29,9 @@ #define HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG 25 #define HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG 7 =20 +#define HINIC3_RX_PENDING_LIMIT_LOW 2 +#define HINIC3_RX_PENDING_LIMIT_HIGH 8 + static void init_intr_coal_param(struct net_device *netdev) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); @@ -38,9 +41,16 @@ static void init_intr_coal_param(struct net_device *netd= ev) for (i =3D 0; i < nic_dev->max_qps; i++) { info =3D &nic_dev->intr_coalesce[i]; info->pending_limit =3D HINIC3_DEFAULT_TXRX_MSIX_PENDING_LIMIT; - info->coalesce_timer_cfg =3D HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG; - info->resend_timer_cfg =3D HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG; + info->coalesce_timer_cfg =3D + HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG; + info->resend_timer_cfg =3D + HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG; + + info->rx_pending_limit_high =3D HINIC3_RX_PENDING_LIMIT_HIGH; + info->rx_pending_limit_low =3D HINIC3_RX_PENDING_LIMIT_LOW; } + + nic_dev->adaptive_rx_coal =3D 1; } =20 static int hinic3_init_intr_coalesce(struct net_device *netdev) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 6e48c29566e1..9ca7794e94a6 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -49,6 +49,7 @@ struct hinic3_irq_cfg { cpumask_t affinity_mask; struct hinic3_txq *txq; struct hinic3_rxq *rxq; + u16 total_events; }; =20 struct hinic3_dyna_txrxq_params { @@ -65,6 +66,9 @@ struct hinic3_intr_coal_info { u8 pending_limit; u8 coalesce_timer_cfg; u8 resend_timer_cfg; + + u8 rx_pending_limit_low; + u8 rx_pending_limit_high; }; =20 struct hinic3_nic_dev { @@ -93,6 +97,7 @@ struct hinic3_nic_dev { struct msix_entry *qps_msix_entries; =20 struct hinic3_intr_coal_info *intr_coalesce; + u32 adaptive_rx_coal; =20 struct workqueue_struct *workq; struct delayed_work periodic_work; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h b/drivers/net/e= thernet/huawei/hinic3/hinic3_rx.h index 68fc237d642b..31622e0a63d0 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h @@ -5,6 +5,7 @@ #define _HINIC3_RX_H_ =20 #include +#include #include =20 #define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK GENMASK(4, 0) @@ -95,6 +96,11 @@ struct hinic3_rxq { struct device *dev; /* device for DMA mapping */ =20 dma_addr_t cqe_start_paddr; + + struct dim dim; + + u8 last_coalesc_timer_cfg; + u8 last_pending_limit; } ____cacheline_aligned; =20 struct hinic3_dyna_rxq_res { --=20 2.43.0