From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout01.his.huawei.com (canpmsgout01.his.huawei.com [113.46.200.216]) (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 390B531ED9D; Wed, 19 Nov 2025 12:44:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.216 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556246; cv=none; b=WuLw/s5FDf9vA9CGsPc67oKuZ+ZxTDZRTm8nG1Cq9YyDo0kssnFCxHM1QWyp01WMxN2N2DIFVNuAx8X5qfcP2OYGBugjJiaa8vbSrNIfmtQtURQ2unjiaojJ2ZWiFW8DnB+RHW5lTKisJRNTk/DVRX9o3VKSqhfIiaLrR3s2eJE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556246; c=relaxed/simple; bh=Kz+Lj7rsshQD79v55oi5utY1vwCHMb8GtcFJaxWS8PE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rNG5XT0C5Yl2u6huSqNLk7Hrc1VRKbnsrWu9QBu8P/fpNGxiOM1Tan8QjdpPc3Hyq6YnPZc4vkjTBtCJYL8XvfXRqiwrUmdWUG6Bvuyqe9EEeIVTc1MggFFPjOr7y1fCtVHILPxVkDEJ14/+eN/hFRFY4gq1qEAFJ65n+/Cu0vo= 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=Z0YRYAle; arc=none smtp.client-ip=113.46.200.216 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="Z0YRYAle" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=yXoI0kbgx8dSzs8dBo4rwbNIFX9DaeNCJHf8Xf+FVk8=; b=Z0YRYAlenH6AdRXiXiRSgNnTGJ86XxmseL4xyTqQ7s7hDteZexjLDmNlMCaFMV7hbS3ji9lfD y+xVJ96IF2Op9WvoEKjwhj5zB7R6gmqNca6lVOmWlRFrkOYmAcW6RXgcPgQFjeCEZnPYiEG1jkU STWewu74d1GGDzyzLDLiJ8U= Received: from mail.maildlp.com (unknown [172.19.88.105]) by canpmsgout01.his.huawei.com (SkyGuard) with ESMTPS id 4dBLj85rvpz1T4Fc; Wed, 19 Nov 2025 20:42:20 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 05D321400DC; Wed, 19 Nov 2025 20:43:54 +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:43:52 +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 1/9] hinic3: Add PF framework Date: Wed, 19 Nov 2025 20:43:34 +0800 Message-ID: <1d4734edb40aea6fb0b24e5fb921f8c81160f7a4.1763555878.git.zhuyikai1@h-partners.com> 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" Add support for PF framework based on the VF code. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../net/ethernet/huawei/hinic3/hinic3_csr.h | 6 ++ .../ethernet/huawei/hinic3/hinic3_hw_comm.c | 61 +++++++++++++ .../ethernet/huawei/hinic3/hinic3_hw_comm.h | 4 + .../ethernet/huawei/hinic3/hinic3_hw_intf.h | 22 +++++ .../net/ethernet/huawei/hinic3/hinic3_hwdev.c | 44 ++++++++- .../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_hwif.c | 90 ++++++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_hwif.h | 23 +++++ .../net/ethernet/huawei/hinic3/hinic3_lld.c | 53 ++++++++++- .../net/ethernet/huawei/hinic3/hinic3_main.c | 30 +++++-- .../net/ethernet/huawei/hinic3/hinic3_mbox.c | 34 +++++-- .../huawei/hinic3/hinic3_mgmt_interface.h | 1 + .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 61 ++++++++++++- .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 3 + 14 files changed, 409 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_csr.h b/drivers/net/= ethernet/huawei/hinic3/hinic3_csr.h index e7417e8efa99..f7083a6e7df9 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_csr.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_csr.h @@ -5,6 +5,7 @@ #define _HINIC3_CSR_H_ =20 #define HINIC3_CFG_REGS_FLAG 0x40000000 +#define HINIC3_MGMT_REGS_FLAG 0xC0000000 #define HINIC3_REGS_FLAG_MASK 0x3FFFFFFF =20 #define HINIC3_VF_CFG_REG_OFFSET 0x2000 @@ -24,6 +25,11 @@ #define HINIC3_FUNC_CSR_MAILBOX_RESULT_H_OFF (HINIC3_CFG_REGS_FLAG + 0x01= 08) #define HINIC3_FUNC_CSR_MAILBOX_RESULT_L_OFF (HINIC3_CFG_REGS_FLAG + 0x01= 0C) =20 +#define HINIC3_HOST_CSR_BASE_ADDR (HINIC3_MGMT_REGS_FLAG + 0x6= 000) +#define HINIC3_PPF_ELECTION_OFFSET 0x0 +#define HINIC3_CSR_PPF_ELECTION_ADDR \ + (HINIC3_HOST_CSR_BASE_ADDR + HINIC3_PPF_ELECTION_OFFSET) + #define HINIC3_CSR_DMA_ATTR_TBL_ADDR (HINIC3_CFG_REGS_FLAG + 0x38= 0) #define HINIC3_CSR_DMA_ATTR_INDIR_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x39= 0) =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_comm.c index 89638813df40..3ee1ca3c83ad 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c @@ -314,6 +314,8 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev) ret =3D -EFAULT; } =20 + hinic3_set_pf_status(hwif, HINIC3_PF_STATUS_FLR_START_FLAG); + clr_res.func_id =3D hwif->attr.func_global_idx; msg_params.buf_in =3D &clr_res; msg_params.in_size =3D sizeof(clr_res); @@ -337,6 +339,65 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev) return ret; } =20 +int hinic3_set_bdf_ctxt(struct hinic3_hwdev *hwdev, + struct comm_cmd_bdf_info *bdf_info) +{ + struct mgmt_msg_params msg_params =3D {}; + int err; + + mgmt_msg_params_init_default(&msg_params, bdf_info, sizeof(*bdf_info)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, + COMM_CMD_SEND_BDF_INFO, &msg_params); + if (err || bdf_info->head.status) { + dev_err(hwdev->dev, + "Failed to set bdf info to fw, err: %d, status: 0x%x\n", + err, bdf_info->head.status); + return -EFAULT; + } + + return 0; +} + +static int hinic3_sync_time(struct hinic3_hwdev *hwdev, u64 time) +{ + struct comm_cmd_sync_time time_info =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + time_info.mstime =3D time; + + mgmt_msg_params_init_default(&msg_params, &time_info, + sizeof(time_info)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, + COMM_CMD_SYNC_TIME, &msg_params); + if (err || time_info.head.status) { + dev_err(hwdev->dev, + "Failed to sync time to mgmt, err: %d, status: 0x%x\n", + err, time_info.head.status); + return -EFAULT; + } + + return 0; +} + +void hinic3_sync_time_to_fw(struct hinic3_hwdev *hwdev) +{ + struct timespec64 ts =3D {}; + u64 time; + int err; + + ktime_get_real_ts64(&ts); + time =3D (u64)(ts.tv_sec * MSEC_PER_SEC + ts.tv_nsec / NSEC_PER_MSEC); + + err =3D hinic3_sync_time(hwdev, time); + if (err) + dev_err(hwdev->dev, + "Synchronize UTC time to firmware failed, err=3D%d\n", + err); +} + static int get_hw_rx_buf_size_idx(int rx_buf_sz, u16 *buf_sz_idx) { /* Supported RX buffer sizes in bytes. Configured by array index. */ diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_comm.h index 304f5691f0c2..c9c6b4fbcb12 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h @@ -40,6 +40,10 @@ int hinic3_set_wq_page_size(struct hinic3_hwdev *hwdev, = u16 func_idx, u32 page_size); int hinic3_set_cmdq_depth(struct hinic3_hwdev *hwdev, u16 cmdq_depth); int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev); +int hinic3_set_bdf_ctxt(struct hinic3_hwdev *hwdev, + struct comm_cmd_bdf_info *bdf_info); +void hinic3_sync_time_to_fw(struct hinic3_hwdev *hwdev); + int hinic3_set_root_ctxt(struct hinic3_hwdev *hwdev, u32 rq_depth, u32 sq_= depth, int rx_buf_sz); int hinic3_clean_root_ctxt(struct hinic3_hwdev *hwdev); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_intf.h index 623cf2d14cbc..a0422ec0500f 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h @@ -110,6 +110,10 @@ enum comm_cmd { COMM_CMD_CFG_MSIX_CTRL_REG =3D 23, COMM_CMD_SET_CEQ_CTRL_REG =3D 24, COMM_CMD_SET_DMA_ATTR =3D 25, + + /* Commands for obtaining information */ + COMM_CMD_SYNC_TIME =3D 62, + COMM_CMD_SEND_BDF_INFO =3D 64, }; =20 struct comm_cmd_cfg_msix_ctrl_reg { @@ -251,6 +255,24 @@ struct comm_cmd_clear_resource { u16 rsvd1[3]; }; =20 +struct comm_cmd_sync_time { + struct mgmt_msg_head head; + + u64 mstime; + u64 rsvd1; +}; + +struct comm_cmd_bdf_info { + struct mgmt_msg_head head; + + u16 function_idx; + u8 rsvd1[2]; + u8 bus; + u8 device; + u8 function; + u8 rsvd2[5]; +}; + /* Services supported by HW. HW uses these values when delivering events. * HW supports multiple services that are not yet supported by driver * (e.g. RoCE). diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.c index 95a213133be9..2b1f1036620e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c @@ -13,6 +13,8 @@ #define HINIC3_PCIE_SNOOP 0 #define HINIC3_PCIE_TPH_DISABLE 0 =20 +#define HINIC3_SYNFW_TIME_PERIOD (60 * 60 * 1000) + #define HINIC3_DMA_ATTR_INDIR_IDX_MASK GENMASK(9, 0) #define HINIC3_DMA_ATTR_INDIR_IDX_SET(val, member) \ FIELD_PREP(HINIC3_DMA_ATTR_INDIR_##member##_MASK, val) @@ -38,6 +40,7 @@ #define HINIC3_WQ_MAX_REQ 10 =20 enum hinic3_hwdev_init_state { + HINIC3_HWDEV_MGMT_INITED =3D 1, HINIC3_HWDEV_MBOX_INITED =3D 2, HINIC3_HWDEV_CMDQ_INITED =3D 3, }; @@ -419,6 +422,8 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *hwd= ev) goto err_clear_func_svc_used_state; } =20 + hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_ACTIVE_FLAG); + return 0; =20 err_clear_func_svc_used_state: @@ -431,11 +436,43 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *h= wdev) =20 static void hinic3_uninit_comm_ch(struct hinic3_hwdev *hwdev) { + hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_INIT); hinic3_free_cmdqs_channel(hwdev); hinic3_set_func_svc_used_state(hwdev, COMM_FUNC_SVC_T_COMM, 0); free_base_mgmt_channel(hwdev); } =20 +static void hinic3_auto_sync_time_work(struct work_struct *work) +{ + struct delayed_work *delay =3D to_delayed_work(work); + struct hinic3_hwdev *hwdev; + + hwdev =3D container_of(delay, struct hinic3_hwdev, sync_time_task); + + hinic3_sync_time_to_fw(hwdev); + + queue_delayed_work(hwdev->workq, &hwdev->sync_time_task, + msecs_to_jiffies(HINIC3_SYNFW_TIME_PERIOD)); +} + +static void hinic3_init_ppf_work(struct hinic3_hwdev *hwdev) +{ + if (hinic3_ppf_idx(hwdev) !=3D hinic3_global_func_id(hwdev)) + return; + + INIT_DELAYED_WORK(&hwdev->sync_time_task, hinic3_auto_sync_time_work); + queue_delayed_work(hwdev->workq, &hwdev->sync_time_task, + msecs_to_jiffies(HINIC3_SYNFW_TIME_PERIOD)); +} + +static void hinic3_free_ppf_work(struct hinic3_hwdev *hwdev) +{ + if (hinic3_ppf_idx(hwdev) !=3D hinic3_global_func_id(hwdev)) + return; + + disable_delayed_work_sync(&hwdev->sync_time_task); +} + static DEFINE_IDA(hinic3_adev_ida); =20 static int hinic3_adev_idx_alloc(void) @@ -498,15 +535,19 @@ int hinic3_init_hwdev(struct pci_dev *pdev) goto err_uninit_comm_ch; } =20 + hinic3_init_ppf_work(hwdev); + err =3D hinic3_set_comm_features(hwdev, hwdev->features, COMM_MAX_FEATURE_QWORD); if (err) { dev_err(hwdev->dev, "Failed to set comm features\n"); - goto err_uninit_comm_ch; + goto err_free_ppf_work; } =20 return 0; =20 +err_free_ppf_work: + hinic3_free_ppf_work(hwdev); err_uninit_comm_ch: hinic3_uninit_comm_ch(hwdev); err_free_cfg_mgmt: @@ -528,6 +569,7 @@ void hinic3_free_hwdev(struct hinic3_hwdev *hwdev) u64 drv_features[COMM_MAX_FEATURE_QWORD] =3D {}; =20 hinic3_set_comm_features(hwdev, drv_features, COMM_MAX_FEATURE_QWORD); + hinic3_free_ppf_work(hwdev); hinic3_func_rx_tx_flush(hwdev); hinic3_uninit_comm_ch(hwdev); hinic3_free_cfg_mgmt(hwdev); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.h index 62e2745e9316..78cface6ddd7 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h @@ -28,6 +28,7 @@ struct hinic3_pcidev { =20 void __iomem *cfg_reg_base; void __iomem *intr_reg_base; + void __iomem *mgmt_reg_base; void __iomem *db_base; u64 db_dwqe_len; u64 db_base_phy; @@ -48,6 +49,7 @@ struct hinic3_hwdev { struct hinic3_ceqs *ceqs; struct hinic3_mbox *mbox; struct hinic3_cmdqs *cmdqs; + struct delayed_work sync_time_task; struct workqueue_struct *workq; /* protect channel init and uninit */ spinlock_t channel_lock; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwif.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_hwif.c index f76f140fb6f7..801f48e241f8 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwif.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwif.c @@ -31,6 +31,7 @@ #define HINIC3_AF0_GET(val, member) \ FIELD_GET(HINIC3_AF0_##member##_MASK, val) =20 +#define HINIC3_AF1_PPF_IDX_MASK GENMASK(5, 0) #define HINIC3_AF1_AEQS_PER_FUNC_MASK GENMASK(9, 8) #define HINIC3_AF1_MGMT_INIT_STATUS_MASK BIT(30) #define HINIC3_AF1_GET(val, member) \ @@ -41,6 +42,10 @@ #define HINIC3_AF2_GET(val, member) \ FIELD_GET(HINIC3_AF2_##member##_MASK, val) =20 +#define HINIC3_AF3_GLOBAL_VF_ID_OF_PF_MASK GENMASK(27, 16) +#define HINIC3_AF3_GET(val, member) \ + FIELD_GET(HINIC3_AF3_##member##_MASK, val) + #define HINIC3_AF4_DOORBELL_CTRL_MASK BIT(0) #define HINIC3_AF4_GET(val, member) \ FIELD_GET(HINIC3_AF4_##member##_MASK, val) @@ -54,9 +59,17 @@ #define HINIC3_AF6_PF_STATUS_MASK GENMASK(15, 0) #define HINIC3_AF6_FUNC_MAX_SQ_MASK GENMASK(31, 23) #define HINIC3_AF6_MSIX_FLEX_EN_MASK BIT(22) +#define HINIC3_AF6_SET(val, member) \ + FIELD_PREP(HINIC3_AF6_##member##_MASK, val) #define HINIC3_AF6_GET(val, member) \ FIELD_GET(HINIC3_AF6_##member##_MASK, val) =20 +#define HINIC3_PPF_ELECTION_IDX_MASK GENMASK(5, 0) +#define HINIC3_PPF_ELECTION_SET(val, member) \ + FIELD_PREP(HINIC3_PPF_ELECTION_##member##_MASK, val) +#define HINIC3_PPF_ELECTION_GET(val, member) \ + FIELD_GET(HINIC3_PPF_ELECTION_##member##_MASK, val) + #define HINIC3_GET_REG_ADDR(reg) ((reg) & (HINIC3_REGS_FLAG_MASK)) =20 static void __iomem *hinic3_reg_addr(struct hinic3_hwif *hwif, u32 reg) @@ -105,12 +118,15 @@ static void set_hwif_attr(struct hinic3_func_attr *at= tr, u32 attr0, u32 attr1, attr->pci_intf_idx =3D HINIC3_AF0_GET(attr0, PCI_INTF_IDX); attr->func_type =3D HINIC3_AF0_GET(attr0, FUNC_TYPE); =20 + attr->ppf_idx =3D HINIC3_AF1_GET(attr1, PPF_IDX); attr->num_aeqs =3D BIT(HINIC3_AF1_GET(attr1, AEQS_PER_FUNC)); attr->num_ceqs =3D HINIC3_AF2_GET(attr2, CEQS_PER_FUNC); attr->num_irqs =3D HINIC3_AF2_GET(attr2, IRQS_PER_FUNC); if (attr->num_irqs > HINIC3_MAX_MSIX_ENTRY) attr->num_irqs =3D HINIC3_MAX_MSIX_ENTRY; =20 + attr->global_vf_id_of_pf =3D HINIC3_AF3_GET(attr3, GLOBAL_VF_ID_OF_PF); + attr->num_sq =3D HINIC3_AF6_GET(attr6, FUNC_MAX_SQ); attr->msix_flex_en =3D HINIC3_AF6_GET(attr6, MSIX_FLEX_EN); } @@ -187,6 +203,28 @@ void hinic3_toggle_doorbell(struct hinic3_hwif *hwif, hinic3_hwif_write_reg(hwif, addr, attr4); } =20 +static void hinic3_set_ppf(struct hinic3_hwdev *hwdev) +{ + struct hinic3_hwif *hwif =3D hwdev->hwif; + struct hinic3_func_attr *attr; + u32 addr, val; + + if (HINIC3_IS_VF(hwdev)) + return; + + /* Read Modify Write */ + attr =3D &hwif->attr; + addr =3D HINIC3_CSR_PPF_ELECTION_ADDR; + val =3D hinic3_hwif_read_reg(hwif, addr); + val &=3D ~HINIC3_PPF_ELECTION_IDX_MASK; + val |=3D HINIC3_PPF_ELECTION_SET(attr->func_global_idx, IDX); + hinic3_hwif_write_reg(hwif, addr, val); + + /* Check PPF index */ + val =3D hinic3_hwif_read_reg(hwif, addr); + attr->ppf_idx =3D HINIC3_PPF_ELECTION_GET(val, IDX); +} + static int db_area_idx_init(struct hinic3_hwif *hwif, u64 db_base_phy, u8 __iomem *db_base, u64 db_dwqe_len) { @@ -366,6 +404,27 @@ static int wait_until_doorbell_and_outbound_enabled(st= ruct hinic3_hwif *hwif) USEC_PER_MSEC); } =20 +void hinic3_set_pf_status(struct hinic3_hwif *hwif, + enum hinic3_pf_status status) +{ + u32 attr6 =3D hinic3_hwif_read_reg(hwif, HINIC3_CSR_FUNC_ATTR6_ADDR); + + attr6 &=3D ~HINIC3_AF6_PF_STATUS_MASK; + attr6 |=3D HINIC3_AF6_SET(status, PF_STATUS); + + if (hwif->attr.func_type =3D=3D HINIC3_FUNC_TYPE_VF) + return; + + hinic3_hwif_write_reg(hwif, HINIC3_CSR_FUNC_ATTR6_ADDR, attr6); +} + +enum hinic3_pf_status hinic3_get_pf_status(struct hinic3_hwif *hwif) +{ + u32 attr6 =3D hinic3_hwif_read_reg(hwif, HINIC3_CSR_FUNC_ATTR6_ADDR); + + return HINIC3_AF6_GET(attr6, PF_STATUS); +} + int hinic3_init_hwif(struct hinic3_hwdev *hwdev) { struct hinic3_pcidev *pci_adapter =3D hwdev->adapter; @@ -378,9 +437,15 @@ int hinic3_init_hwif(struct hinic3_hwdev *hwdev) return -ENOMEM; =20 hwdev->hwif =3D hwif; - hwif->cfg_regs_base =3D (u8 __iomem *)pci_adapter->cfg_reg_base + + /* if function is VF, mgmt_regs_base will be NULL */ + hwif->cfg_regs_base =3D pci_adapter->mgmt_reg_base ? + pci_adapter->cfg_reg_base : + (u8 __iomem *)pci_adapter->cfg_reg_base + HINIC3_VF_CFG_REG_OFFSET; =20 + hwif->intr_regs_base =3D pci_adapter->intr_reg_base; + hwif->mgmt_regs_base =3D pci_adapter->mgmt_reg_base; + err =3D db_area_idx_init(hwif, pci_adapter->db_base_phy, pci_adapter->db_base, pci_adapter->db_dwqe_len); @@ -412,7 +477,15 @@ int hinic3_init_hwif(struct hinic3_hwdev *hwdev) goto err_free_db_area_idx; } =20 + hinic3_set_ppf(hwdev); + disable_all_msix(hwdev); + /* disable mgmt cpu from reporting any event */ + hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_INIT); + + dev_dbg(hwdev->dev, "global_func_idx: %u, func_type: %d, host_id: %u, ppf= : %u\n", + hwif->attr.func_global_idx, hwif->attr.func_type, + hwif->attr.pci_intf_idx, hwif->attr.ppf_idx); =20 return 0; =20 @@ -434,3 +507,18 @@ u16 hinic3_global_func_id(struct hinic3_hwdev *hwdev) { return hwdev->hwif->attr.func_global_idx; } + +u8 hinic3_pf_id_of_vf(struct hinic3_hwdev *hwdev) +{ + return hwdev->hwif->attr.port_to_port_idx; +} + +u16 hinic3_glb_pf_vf_offset(struct hinic3_hwdev *hwdev) +{ + return hwdev->hwif->attr.global_vf_id_of_pf; +} + +u8 hinic3_ppf_idx(struct hinic3_hwdev *hwdev) +{ + return hwdev->hwif->attr.ppf_idx; +} diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwif.h b/drivers/net= /ethernet/huawei/hinic3/hinic3_hwif.h index c02904e861cc..445bf7fa79b4 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwif.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwif.h @@ -10,6 +10,7 @@ struct hinic3_hwdev; =20 enum hinic3_func_type { + HINIC3_FUNC_TYPE_PF =3D 0, HINIC3_FUNC_TYPE_VF =3D 1, }; =20 @@ -38,6 +39,8 @@ static_assert(sizeof(struct hinic3_func_attr) =3D=3D 20); =20 struct hinic3_hwif { u8 __iomem *cfg_regs_base; + u8 __iomem *intr_regs_base; + u8 __iomem *mgmt_regs_base; u64 db_base_phy; u64 db_dwqe_len; u8 __iomem *db_base; @@ -50,6 +53,13 @@ enum hinic3_outbound_ctrl { DISABLE_OUTBOUND =3D 0x1, }; =20 +enum hinic3_pf_status { + HINIC3_PF_STATUS_INIT =3D 0x0, + HINIC3_PF_STATUS_ACTIVE_FLAG =3D 0x11, + HINIC3_PF_STATUS_FLR_START_FLAG =3D 0x12, + HINIC3_PF_STATUS_FLR_FINISH_FLAG =3D 0x13, +}; + enum hinic3_doorbell_ctrl { ENABLE_DOORBELL =3D 0, DISABLE_DOORBELL =3D 1, @@ -65,6 +75,12 @@ enum hinic3_msix_auto_mask { HINIC3_SET_MSIX_AUTO_MASK, }; =20 +#define HINIC3_FUNC_TYPE(hwdev) ((hwdev)->hwif->attr.func_type) +#define HINIC3_IS_PF(hwdev) \ + (HINIC3_FUNC_TYPE(hwdev) =3D=3D HINIC3_FUNC_TYPE_PF) +#define HINIC3_IS_VF(hwdev) \ + (HINIC3_FUNC_TYPE(hwdev) =3D=3D HINIC3_FUNC_TYPE_VF) + u32 hinic3_hwif_read_reg(struct hinic3_hwif *hwif, u32 reg); void hinic3_hwif_write_reg(struct hinic3_hwif *hwif, u32 reg, u32 val); =20 @@ -75,6 +91,10 @@ int hinic3_alloc_db_addr(struct hinic3_hwdev *hwdev, voi= d __iomem **db_base, void __iomem **dwqe_base); void hinic3_free_db_addr(struct hinic3_hwdev *hwdev, const u8 __iomem *db_= base); =20 +void hinic3_set_pf_status(struct hinic3_hwif *hwif, + enum hinic3_pf_status status); +enum hinic3_pf_status hinic3_get_pf_status(struct hinic3_hwif *hwif); + int hinic3_init_hwif(struct hinic3_hwdev *hwdev); void hinic3_free_hwif(struct hinic3_hwdev *hwdev); =20 @@ -86,5 +106,8 @@ void hinic3_set_msix_auto_mask_state(struct hinic3_hwdev= *hwdev, u16 msix_idx, enum hinic3_msix_auto_mask flag); =20 u16 hinic3_global_func_id(struct hinic3_hwdev *hwdev); +u8 hinic3_pf_id_of_vf(struct hinic3_hwdev *hwdev); +u16 hinic3_glb_pf_vf_offset(struct hinic3_hwdev *hwdev); +u8 hinic3_ppf_idx(struct hinic3_hwdev *hwdev); =20 #endif diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c b/drivers/net/= ethernet/huawei/hinic3/hinic3_lld.c index 3db8241a3b0c..2b77fea1e0b3 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c @@ -5,15 +5,22 @@ #include =20 #include "hinic3_hw_cfg.h" +#include "hinic3_hw_comm.h" #include "hinic3_hwdev.h" +#include "hinic3_hwif.h" #include "hinic3_lld.h" #include "hinic3_mgmt.h" #include "hinic3_pci_id_tbl.h" =20 #define HINIC3_VF_PCI_CFG_REG_BAR 0 +#define HINIC3_PF_PCI_CFG_REG_BAR 1 #define HINIC3_PCI_INTR_REG_BAR 2 +/* Only PF has mgmt bar */ +#define HINIC3_PCI_MGMT_REG_BAR 3 #define HINIC3_PCI_DB_BAR 4 =20 +#define HINIC3_IS_VF_DEV(pdev) ((pdev)->device =3D=3D PCI_DEV_ID_HINIC= 3_VF) + #define HINIC3_EVENT_POLL_SLEEP_US 1000 #define HINIC3_EVENT_POLL_TIMEOUT_US 10000000 =20 @@ -181,8 +188,12 @@ void hinic3_adev_event_unregister(struct auxiliary_dev= ice *adev) static int hinic3_mapping_bar(struct pci_dev *pdev, struct hinic3_pcidev *pci_adapter) { - pci_adapter->cfg_reg_base =3D pci_ioremap_bar(pdev, - HINIC3_VF_PCI_CFG_REG_BAR); + int cfg_bar; + + cfg_bar =3D HINIC3_IS_VF_DEV(pdev) ? + HINIC3_VF_PCI_CFG_REG_BAR : HINIC3_PF_PCI_CFG_REG_BAR; + + pci_adapter->cfg_reg_base =3D pci_ioremap_bar(pdev, cfg_bar); if (!pci_adapter->cfg_reg_base) { dev_err(&pdev->dev, "Failed to map configuration regs\n"); return -ENOMEM; @@ -195,16 +206,28 @@ static int hinic3_mapping_bar(struct pci_dev *pdev, goto err_unmap_cfg_reg_base; } =20 + if (!HINIC3_IS_VF_DEV(pdev)) { + pci_adapter->mgmt_reg_base =3D + pci_ioremap_bar(pdev, HINIC3_PCI_MGMT_REG_BAR); + if (!pci_adapter->mgmt_reg_base) { + dev_err(&pdev->dev, "Failed to map mgmt regs\n"); + goto err_unmap_intr_reg_base; + } + } + pci_adapter->db_base_phy =3D pci_resource_start(pdev, HINIC3_PCI_DB_BAR); pci_adapter->db_dwqe_len =3D pci_resource_len(pdev, HINIC3_PCI_DB_BAR); pci_adapter->db_base =3D pci_ioremap_bar(pdev, HINIC3_PCI_DB_BAR); if (!pci_adapter->db_base) { dev_err(&pdev->dev, "Failed to map doorbell regs\n"); - goto err_unmap_intr_reg_base; + goto err_unmap_mgmt_reg_base; } =20 return 0; =20 +err_unmap_mgmt_reg_base: + if (!HINIC3_IS_VF_DEV(pdev)) + iounmap(pci_adapter->mgmt_reg_base); err_unmap_intr_reg_base: iounmap(pci_adapter->intr_reg_base); =20 @@ -217,6 +240,8 @@ static int hinic3_mapping_bar(struct pci_dev *pdev, static void hinic3_unmapping_bar(struct hinic3_pcidev *pci_adapter) { iounmap(pci_adapter->db_base); + if (!HINIC3_IS_VF_DEV(pci_adapter->pdev)) + iounmap(pci_adapter->mgmt_reg_base); iounmap(pci_adapter->intr_reg_base); iounmap(pci_adapter->cfg_reg_base); } @@ -295,6 +320,9 @@ static int hinic3_func_init(struct pci_dev *pdev, return err; } =20 + if (HINIC3_IS_PF(pci_adapter->hwdev)) + hinic3_sync_time_to_fw(pci_adapter->hwdev); + err =3D hinic3_attach_aux_devices(pci_adapter->hwdev); if (err) goto err_free_hwdev; @@ -311,6 +339,8 @@ static void hinic3_func_uninit(struct pci_dev *pdev) { struct hinic3_pcidev *pci_adapter =3D pci_get_drvdata(pdev); =20 + /* disable mgmt reporting before flushing mgmt work-queue. */ + hinic3_set_pf_status(pci_adapter->hwdev->hwif, HINIC3_PF_STATUS_INIT); hinic3_flush_mgmt_workq(pci_adapter->hwdev); hinic3_detach_aux_devices(pci_adapter->hwdev); hinic3_free_hwdev(pci_adapter->hwdev); @@ -319,6 +349,7 @@ static void hinic3_func_uninit(struct pci_dev *pdev) static int hinic3_probe_func(struct hinic3_pcidev *pci_adapter) { struct pci_dev *pdev =3D pci_adapter->pdev; + struct comm_cmd_bdf_info bdf_info =3D {}; int err; =20 err =3D hinic3_mapping_bar(pdev, pci_adapter); @@ -331,8 +362,24 @@ static int hinic3_probe_func(struct hinic3_pcidev *pci= _adapter) if (err) goto err_unmap_bar; =20 + if (HINIC3_IS_PF(pci_adapter->hwdev)) { + bdf_info.function_idx =3D + hinic3_global_func_id(pci_adapter->hwdev); + bdf_info.bus =3D pdev->bus->number; + bdf_info.device =3D PCI_SLOT(pdev->devfn); + bdf_info.function =3D PCI_FUNC(pdev->devfn); + + err =3D hinic3_set_bdf_ctxt(pci_adapter->hwdev, &bdf_info); + if (err) { + dev_err(&pdev->dev, "Failed to set BDF info to fw\n"); + goto err_uninit_func; + } + } + return 0; =20 +err_uninit_func: + hinic3_func_uninit(pdev); err_unmap_bar: hinic3_unmapping_bar(pci_adapter); =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 6d87d4d895ba..9249dd588feb 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -130,6 +130,7 @@ static int hinic3_sw_init(struct net_device *netdev) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); struct hinic3_hwdev *hwdev =3D nic_dev->hwdev; + u8 mac_addr[ETH_ALEN]; int err; =20 nic_dev->q_params.sq_depth =3D HINIC3_SQ_DEPTH; @@ -137,16 +138,29 @@ static int hinic3_sw_init(struct net_device *netdev) =20 hinic3_try_to_enable_rss(netdev); =20 - /* VF driver always uses random MAC address. During VM migration to a - * new device, the new device should learn the VMs old MAC rather than - * provide its own MAC. The product design assumes that every VF is - * suspectable to migration so the device avoids offering MAC address - * to VFs. - */ - eth_hw_addr_random(netdev); + if (HINIC3_IS_VF(hwdev)) { + /* VF driver always uses random MAC address. During VM migration + * to a new device, the new device should learn the VMs old MAC + * rather than provide its own MAC. The product design assumes + * that every VF is susceptible to migration so the device + * avoids offering MAC address to VFs. + */ + eth_hw_addr_random(netdev); + } else { + err =3D hinic3_get_default_mac(hwdev, mac_addr); + if (err) { + dev_err(hwdev->dev, "Failed to get MAC address\n"); + goto err_clear_rss_config; + } + eth_hw_addr_set(netdev, mac_addr); + } + err =3D hinic3_set_mac(hwdev, netdev->dev_addr, 0, hinic3_global_func_id(hwdev)); - if (err) { + /* Failure to set MAC is not a fatal error for VF since its MAC may have + * already been set by PF + */ + if (err && err !=3D -EADDRINUSE) { dev_err(hwdev->dev, "Failed to set default MAC\n"); goto err_clear_rss_config; } diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_mbox.c index cf67e26acece..1cb0d88911a2 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c @@ -82,10 +82,19 @@ static struct hinic3_msg_desc *get_mbox_msg_desc(struct= hinic3_mbox *mbox, enum mbox_msg_direction_type dir, u16 src_func_id) { + struct hinic3_hwdev *hwdev =3D mbox->hwdev; struct hinic3_msg_channel *msg_ch; =20 - msg_ch =3D (src_func_id =3D=3D MBOX_MGMT_FUNC_ID) ? - &mbox->mgmt_msg : mbox->func_msg; + if (src_func_id =3D=3D MBOX_MGMT_FUNC_ID) { + msg_ch =3D &mbox->mgmt_msg; + } else if (HINIC3_IS_VF(hwdev)) { + /* message from pf */ + msg_ch =3D mbox->func_msg; + if (src_func_id !=3D hinic3_pf_id_of_vf(hwdev) || !msg_ch) + return NULL; + } else { + return NULL; + } =20 return (dir =3D=3D MBOX_MSG_SEND) ? &msg_ch->recv_msg : &msg_ch->resp_msg; @@ -409,9 +418,12 @@ int hinic3_init_mbox(struct hinic3_hwdev *hwdev) if (err) goto err_destroy_workqueue; =20 - err =3D hinic3_init_func_mbox_msg_channel(hwdev); - if (err) - goto err_uninit_mgmt_msg_ch; + if (HINIC3_IS_VF(hwdev)) { + /* VF to PF mbox message channel */ + err =3D hinic3_init_func_mbox_msg_channel(hwdev); + if (err) + goto err_uninit_mgmt_msg_ch; + } =20 err =3D alloc_mbox_wb_status(mbox); if (err) { @@ -424,8 +436,8 @@ int hinic3_init_mbox(struct hinic3_hwdev *hwdev) return 0; =20 err_uninit_func_mbox_msg_ch: - hinic3_uninit_func_mbox_msg_channel(hwdev); - + if (HINIC3_IS_VF(hwdev)) + hinic3_uninit_func_mbox_msg_channel(hwdev); err_uninit_mgmt_msg_ch: uninit_mgmt_msg_channel(mbox); =20 @@ -576,7 +588,13 @@ static void write_mbox_msg_attr(struct hinic3_mbox *mb= ox, { struct hinic3_hwif *hwif =3D mbox->hwdev->hwif; u32 mbox_int, mbox_ctrl, tx_size; + u16 func =3D dst_func; =20 + /* VF can send non-management messages only to PF. We set DST_FUNC field + * to 0 since HW will ignore it anyway. + */ + if (HINIC3_IS_VF(mbox->hwdev) && dst_func !=3D MBOX_MGMT_FUNC_ID) + func =3D 0; tx_size =3D ALIGN(seg_len + MBOX_HEADER_SZ, MBOX_SEG_LEN_ALIGN) >> 2; =20 mbox_int =3D MBOX_INT_SET(dst_aeqn, DST_AEQN) | @@ -587,7 +605,7 @@ static void write_mbox_msg_attr(struct hinic3_mbox *mbo= x, =20 mbox_ctrl =3D MBOX_CTRL_SET(1, TX_STATUS) | MBOX_CTRL_SET(0, TRIGGER_AEQE) | - MBOX_CTRL_SET(dst_func, DST_FUNC); + MBOX_CTRL_SET(func, DST_FUNC); =20 hinic3_hwif_write_reg(hwif, HINIC3_FUNC_CSR_MAILBOX_INT_OFF, mbox_int); hinic3_hwif_write_reg(hwif, HINIC3_FUNC_CSR_MAILBOX_CONTROL_OFF, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/d= rivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index 6cc0345c39e4..f9a3222b1b46 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -163,6 +163,7 @@ enum l2nic_cmd { L2NIC_CMD_SET_SQ_CI_ATTR =3D 8, L2NIC_CMD_CLEAR_QP_RESOURCE =3D 11, L2NIC_CMD_FEATURE_NEGO =3D 15, + L2NIC_CMD_GET_MAC =3D 20, L2NIC_CMD_SET_MAC =3D 21, L2NIC_CMD_DEL_MAC =3D 22, L2NIC_CMD_UPDATE_MAC =3D 23, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index 979f47ca77f9..e784f1b04a41 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -117,17 +117,52 @@ int hinic3_set_port_mtu(struct net_device *netdev, u1= 6 new_mtu) &func_tbl_cfg); } =20 +static bool hinic3_check_vf_set_by_pf(struct hinic3_hwdev *hwdev, + u8 status) +{ + return HINIC3_IS_VF(hwdev) && status =3D=3D HINIC3_PF_SET_VF_ALREADY; +} + static int hinic3_check_mac_info(struct hinic3_hwdev *hwdev, u8 status, u16 vlan_id) { if ((status && status !=3D MGMT_STATUS_EXIST) || ((vlan_id & BIT(15)) && status =3D=3D MGMT_STATUS_EXIST)) { + if (hinic3_check_vf_set_by_pf(hwdev, status)) + return 0; + return -EINVAL; } =20 return 0; } =20 +int hinic3_get_default_mac(struct hinic3_hwdev *hwdev, u8 *mac_addr) +{ + struct l2nic_cmd_set_mac mac_info =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + mac_info.func_id =3D hinic3_global_func_id(hwdev); + + mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_GET_MAC, + &msg_params); + + if (err || mac_info.msg_head.status) { + dev_err(hwdev->dev, + "Failed to get mac, err: %d, status: 0x%x\n", + err, mac_info.msg_head.status); + return -EFAULT; + } + + ether_addr_copy(mac_addr, mac_info.mac); + + return 0; +} + int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vla= n_id, u16 func_id) { @@ -157,9 +192,9 @@ int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8= *mac_addr, u16 vlan_id, return -EIO; } =20 - if (mac_info.msg_head.status =3D=3D MGMT_STATUS_PF_SET_VF_ALREADY) { + if (hinic3_check_vf_set_by_pf(hwdev, mac_info.msg_head.status)) { dev_warn(hwdev->dev, "PF has already set VF mac, Ignore set operation\n"= ); - return 0; + return -EADDRINUSE; } =20 if (mac_info.msg_head.status =3D=3D MGMT_STATUS_EXIST) { @@ -191,11 +226,18 @@ int hinic3_del_mac(struct hinic3_hwdev *hwdev, const = u8 *mac_addr, u16 vlan_id, =20 err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, L2NIC_CMD_DEL_MAC, &msg_params); - if (err) { + if (err || + (mac_info.msg_head.status && + !hinic3_check_vf_set_by_pf(hwdev, mac_info.msg_head.status))) { dev_err(hwdev->dev, "Failed to delete MAC, err: %d, status: 0x%x\n", err, mac_info.msg_head.status); - return err; + return -EFAULT; + } + + if (hinic3_check_vf_set_by_pf(hwdev, mac_info.msg_head.status)) { + dev_warn(hwdev->dev, "PF has already set VF mac, Ignore delete operation= .\n"); + return -EADDRINUSE; } =20 return 0; @@ -231,6 +273,17 @@ int hinic3_update_mac(struct hinic3_hwdev *hwdev, cons= t u8 *old_mac, return -EIO; } =20 + if (hinic3_check_vf_set_by_pf(hwdev, mac_info.msg_head.status)) { + dev_warn(hwdev->dev, "PF has already set VF MAC. Ignore update operation= \n"); + return -EADDRINUSE; + } + + if (mac_info.msg_head.status =3D=3D HINIC3_MGMT_STATUS_EXIST) { + dev_warn(hwdev->dev, + "MAC is repeated. Ignore update operation\n"); + return 0; + } + return 0; } =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index b83b567fa542..08bf14679bf8 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -16,6 +16,8 @@ struct hinic3_nic_dev; #define HINIC3_MAX_JUMBO_FRAME_SIZE 9600 =20 #define HINIC3_VLAN_ID_MASK 0x7FFF +#define HINIC3_PF_SET_VF_ALREADY 0x4 +#define HINIC3_MGMT_STATUS_EXIST 0x6 =20 enum hinic3_nic_event_type { HINIC3_NIC_EVENT_LINK_DOWN =3D 0, @@ -41,6 +43,7 @@ void hinic3_update_nic_feature(struct hinic3_nic_dev *nic= _dev, u64 feature_cap); int hinic3_init_function_table(struct hinic3_nic_dev *nic_dev); int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu); =20 +int hinic3_get_default_mac(struct hinic3_hwdev *hwdev, u8 *mac_addr); int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vla= n_id, u16 func_id); int hinic3_del_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vla= n_id, --=20 2.43.0 From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout04.his.huawei.com (canpmsgout04.his.huawei.com [113.46.200.219]) (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 389BF3596E6; Wed, 19 Nov 2025 12:44:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.219 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556250; cv=none; b=jJ8i4eiOOXlSZileFvnYaYsaEvT8UY1clKd7vyF3klccrRWvVHkIy+AK3omFRyJQSrc4Obu3REQ81UB11IxRG0XG5M1gEhwNcvapq3ZbX/Q+Q8hJ/XtXFC0oYXjP2fVywquC8gQSUpL5rXr9iyiq2fpmS9wSFljQQscCT/mfYcE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556250; c=relaxed/simple; bh=0Y3Cvw+kKr93+miw7bEGKYGzgJez3nQErgDbsHvflJc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=n3doc/ZyMJltldNcFhbXKwz5ndE/SBoDuPaJ5GouBeeK4WlQWVmTr+6taPdgSAd3gImX4o9em9FqQKu+fPLtIQ78+98bZ4Ejl7gizeEeHvb2L5FFXZlHeK5D/PsYhhCw381P9wibh8tCpkQVPkzYafl7wCouwL2P84NUVq/Y4yk= 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=F4oUKx2P; arc=none smtp.client-ip=113.46.200.219 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="F4oUKx2P" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=1R0asz8w9wWtbnTE6+YHorZTK7F5d2Z4iEVgJjFjuAI=; b=F4oUKx2P79le9wkJLW8dymk8LTEgSVHDIgERgGfOiQPl5TpLnijpr/xwKU7SjUOSocLY+MHdU pGPbHP5TaBZDuROTN6NnwcnCVLx9NItepetC38ant2IGL/dwFrgS0d6cOylTAZ/i8Qagn5l/oom 9C/EgMDADpKZTiTdegTXjjI= Received: from mail.maildlp.com (unknown [172.19.163.48]) by canpmsgout04.his.huawei.com (SkyGuard) with ESMTPS id 4dBLj053tKz1prLF; Wed, 19 Nov 2025 20:42:12 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 48023180477; Wed, 19 Nov 2025 20:43:57 +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:43:55 +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 2/9] hinic3: Add PF management interfaces Date: Wed, 19 Nov 2025 20:43:35 +0800 Message-ID: <42f0b74c6365a4e1bf1016b12d688d0d06e390f8.1763555878.git.zhuyikai1@h-partners.com> 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" Add management and communication pathways between PF and HW. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../ethernet/huawei/hinic3/hinic3_hw_intf.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_hwdev.c | 51 ++- .../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 1 + .../net/ethernet/huawei/hinic3/hinic3_main.c | 2 + .../net/ethernet/huawei/hinic3/hinic3_mbox.c | 13 + .../net/ethernet/huawei/hinic3/hinic3_mbox.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_mgmt.c | 311 +++++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_mgmt.h | 53 +++ .../huawei/hinic3/hinic3_mgmt_interface.h | 1 + .../huawei/hinic3/hinic3_netdev_ops.c | 35 ++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 28 ++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 18 + .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 3 + 13 files changed, 518 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_intf.h index a0422ec0500f..329a9c464ff9 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h @@ -39,6 +39,8 @@ enum mgmt_mod_type { /* Configuration module */ MGMT_MOD_CFGM =3D 7, MGMT_MOD_HILINK =3D 14, + /* hardware max module id */ + MGMT_MOD_HW_MAX =3D 20, }; =20 static inline void mgmt_msg_params_init_default(struct mgmt_msg_params *ms= g_params, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.c index 2b1f1036620e..25e375b20174 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c @@ -211,6 +211,36 @@ static int init_ceqs_msix_attr(struct hinic3_hwdev *hw= dev) return 0; } =20 +static int hinic3_comm_pf_to_mgmt_init(struct hinic3_hwdev *hwdev) +{ + int err; + + if (HINIC3_IS_VF(hwdev)) + return 0; + + err =3D hinic3_pf_to_mgmt_init(hwdev); + if (err) + return err; + + set_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state); + + return 0; +} + +static void hinic3_comm_pf_to_mgmt_free(struct hinic3_hwdev *hwdev) +{ + if (HINIC3_IS_VF(hwdev)) + return; + + spin_lock_bh(&hwdev->channel_lock); + clear_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state); + spin_unlock_bh(&hwdev->channel_lock); + + hinic3_aeq_unregister_cb(hwdev, HINIC3_MSG_FROM_FW); + + hinic3_pf_to_mgmt_free(hwdev); +} + static int init_basic_mgmt_channel(struct hinic3_hwdev *hwdev) { int err; @@ -412,10 +442,14 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *h= wdev) if (err) return err; =20 - err =3D init_basic_attributes(hwdev); + err =3D hinic3_comm_pf_to_mgmt_init(hwdev); if (err) goto err_free_basic_mgmt_ch; =20 + err =3D init_basic_attributes(hwdev); + if (err) + goto err_free_comm_pf_to_mgmt; + err =3D init_cmdqs_channel(hwdev); if (err) { dev_err(hwdev->dev, "Failed to init cmdq channel\n"); @@ -428,6 +462,8 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *hwd= ev) =20 err_clear_func_svc_used_state: hinic3_set_func_svc_used_state(hwdev, COMM_FUNC_SVC_T_COMM, 0); +err_free_comm_pf_to_mgmt: + hinic3_comm_pf_to_mgmt_free(hwdev); err_free_basic_mgmt_ch: free_base_mgmt_channel(hwdev); =20 @@ -439,6 +475,7 @@ static void hinic3_uninit_comm_ch(struct hinic3_hwdev *= hwdev) hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_INIT); hinic3_free_cmdqs_channel(hwdev); hinic3_set_func_svc_used_state(hwdev, COMM_FUNC_SVC_T_COMM, 0); + hinic3_comm_pf_to_mgmt_free(hwdev); free_base_mgmt_channel(hwdev); } =20 @@ -581,9 +618,21 @@ void hinic3_free_hwdev(struct hinic3_hwdev *hwdev) =20 void hinic3_set_api_stop(struct hinic3_hwdev *hwdev) { + struct hinic3_recv_msg *recv_resp_msg; struct hinic3_mbox *mbox; =20 spin_lock_bh(&hwdev->channel_lock); + if (HINIC3_IS_PF(hwdev) && + test_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state)) { + recv_resp_msg =3D &hwdev->pf_to_mgmt->recv_resp_msg_from_mgmt; + spin_lock_bh(&hwdev->pf_to_mgmt->sync_event_lock); + if (hwdev->pf_to_mgmt->event_flag =3D=3D COMM_SEND_EVENT_START) { + complete(&recv_resp_msg->recv_done); + hwdev->pf_to_mgmt->event_flag =3D COMM_SEND_EVENT_TIMEOUT; + } + spin_unlock_bh(&hwdev->pf_to_mgmt->sync_event_lock); + } + if (test_bit(HINIC3_HWDEV_MBOX_INITED, &hwdev->func_state)) { mbox =3D hwdev->mbox; spin_lock(&mbox->mbox_lock); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.h index 78cface6ddd7..3c15f22973fe 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h @@ -51,6 +51,7 @@ struct hinic3_hwdev { struct hinic3_cmdqs *cmdqs; struct delayed_work sync_time_task; struct workqueue_struct *workq; + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; /* protect channel init and uninit */ spinlock_t channel_lock; u64 features[COMM_MAX_FEATURE_QWORD]; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 9249dd588feb..ce10ae7c0d9e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -133,6 +133,8 @@ static int hinic3_sw_init(struct net_device *netdev) u8 mac_addr[ETH_ALEN]; int err; =20 + mutex_init(&nic_dev->port_state_mutex); + nic_dev->q_params.sq_depth =3D HINIC3_SQ_DEPTH; nic_dev->q_params.rq_depth =3D HINIC3_RQ_DEPTH; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_mbox.c index 1cb0d88911a2..90e704107e7e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c @@ -858,6 +858,19 @@ int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwde= v, u8 mod, u16 cmd, return err; } =20 +void hinic3_response_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 = cmd, + const void *buf_in, u32 in_size, u16 msg_id) +{ + struct mbox_msg_info msg_info; + + msg_info.msg_id =3D (u8)msg_id; + msg_info.status =3D 0; + + send_mbox_msg(hwdev->mbox, mod, cmd, buf_in, in_size, + MBOX_MGMT_FUNC_ID, MBOX_MSG_RESP, + MBOX_MSG_NO_ACK, &msg_info); +} + int hinic3_send_mbox_to_mgmt_no_ack(struct hinic3_hwdev *hwdev, u8 mod, u1= 6 cmd, const struct mgmt_msg_params *msg_params) { diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h b/drivers/net= /ethernet/huawei/hinic3/hinic3_mbox.h index e71629e95086..e26f22d1d564 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h @@ -135,6 +135,8 @@ void hinic3_free_mbox(struct hinic3_hwdev *hwdev); =20 int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd, const struct mgmt_msg_params *msg_params); +void hinic3_response_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 = cmd, + const void *buf_in, u32 in_size, u16 msg_id); int hinic3_send_mbox_to_mgmt_no_ack(struct hinic3_hwdev *hwdev, u8 mod, u1= 6 cmd, const struct mgmt_msg_params *msg_params); =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_mgmt.c index c38d10cd7fac..e1d2a4444663 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c @@ -3,19 +3,328 @@ =20 #include "hinic3_eqs.h" #include "hinic3_hwdev.h" +#include "hinic3_hwif.h" #include "hinic3_mbox.h" #include "hinic3_mgmt.h" =20 +#define HINIC3_MSG_TO_MGMT_MAX_LEN 2016 + +#define MGMT_MAX_PF_BUF_SIZE 2048UL +#define MGMT_SEG_LEN_MAX 48 +#define MGMT_ASYNC_MSG_FLAG 0x8 + +#define HINIC3_MGMT_WQ_NAME "hinic3_mgmt" + +/* Bogus sequence ID to prevent accidental match following partial message= */ +#define MGMT_BOGUS_SEQ_ID \ + (MGMT_MAX_PF_BUF_SIZE / MGMT_SEG_LEN_MAX + 1) + +static void +hinic3_mgmt_resp_msg_handler(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt, + struct hinic3_recv_msg *recv_msg) +{ + struct device *dev =3D pf_to_mgmt->hwdev->dev; + + /* Ignore async msg */ + if (recv_msg->msg_id & MGMT_ASYNC_MSG_FLAG) + return; + + spin_lock(&pf_to_mgmt->sync_event_lock); + if (recv_msg->msg_id !=3D pf_to_mgmt->sync_msg_id) { + dev_err(dev, "msg id mismatch, send msg id: 0x%x, recv msg id: 0x%x, eve= nt state: %d\n", + pf_to_mgmt->sync_msg_id, recv_msg->msg_id, + pf_to_mgmt->event_flag); + } else if (pf_to_mgmt->event_flag =3D=3D COMM_SEND_EVENT_START) { + pf_to_mgmt->event_flag =3D COMM_SEND_EVENT_SUCCESS; + complete(&recv_msg->recv_done); + } else { + dev_err(dev, "Wait timeout, send msg id: 0x%x, recv msg id: 0x%x, event = state: %d\n", + pf_to_mgmt->sync_msg_id, recv_msg->msg_id, + pf_to_mgmt->event_flag); + } + spin_unlock(&pf_to_mgmt->sync_event_lock); +} + +static void hinic3_recv_mgmt_msg_work_handler(struct work_struct *work) +{ + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + struct mgmt_msg_handle_work *mgmt_work; + struct mgmt_msg_head *ack_cmd; + + mgmt_work =3D container_of(work, struct mgmt_msg_handle_work, work); + + /* At the moment, we do not expect any meaningful messages but if the + * sender expects an ACK we still need to provide one with "unsupported" + * status. + */ + if (mgmt_work->async_mgmt_to_pf) + goto out; + + pf_to_mgmt =3D mgmt_work->pf_to_mgmt; + ack_cmd =3D pf_to_mgmt->mgmt_ack_buf; + memset(ack_cmd, 0, sizeof(*ack_cmd)); + ack_cmd->status =3D MGMT_STATUS_CMD_UNSUPPORTED; + + hinic3_response_mbox_to_mgmt(pf_to_mgmt->hwdev, mgmt_work->mod, + mgmt_work->cmd, ack_cmd, sizeof(*ack_cmd), + mgmt_work->msg_id); + +out: + kfree(mgmt_work->msg); + kfree(mgmt_work); +} + +static int hinic3_recv_msg_add_seg(struct hinic3_recv_msg *recv_msg, + __le64 msg_header, const void *seg_data, + bool *is_complete) +{ + u8 seq_id, msg_id, seg_len, is_last; + char *msg_buff; + u32 offset; + + seg_len =3D MBOX_MSG_HEADER_GET(msg_header, SEG_LEN); + is_last =3D MBOX_MSG_HEADER_GET(msg_header, LAST); + seq_id =3D MBOX_MSG_HEADER_GET(msg_header, SEQID); + msg_id =3D MBOX_MSG_HEADER_GET(msg_header, MSG_ID); + + if (seg_len > MGMT_SEG_LEN_MAX) + return -EINVAL; + + /* All segments but last must be of maximal size */ + if (seg_len !=3D MGMT_SEG_LEN_MAX && !is_last) + return -EINVAL; + + if (seq_id =3D=3D 0) { + recv_msg->seq_id =3D seq_id; + recv_msg->msg_id =3D msg_id; + } else if (seq_id !=3D recv_msg->seq_id + 1 || + msg_id !=3D recv_msg->msg_id) { + return -EINVAL; + } + + offset =3D seq_id * MGMT_SEG_LEN_MAX; + if (offset + seg_len > MGMT_MAX_PF_BUF_SIZE) + return -EINVAL; + + msg_buff =3D recv_msg->msg; + memcpy(msg_buff + offset, seg_data, seg_len); + recv_msg->msg_len =3D offset + seg_len; + recv_msg->seq_id =3D seq_id; + *is_complete =3D !!is_last; + + return 0; +} + +static void hinic3_init_mgmt_msg_work(struct hinic3_msg_pf_to_mgmt *pf_to_= mgmt, + struct hinic3_recv_msg *recv_msg) +{ + struct mgmt_msg_handle_work *mgmt_work; + + mgmt_work =3D kmalloc(sizeof(*mgmt_work), GFP_KERNEL); + if (!mgmt_work) + return; + + if (recv_msg->msg_len) { + mgmt_work->msg =3D kmalloc(recv_msg->msg_len, GFP_KERNEL); + if (!mgmt_work->msg) { + kfree(mgmt_work); + return; + } + } + + mgmt_work->pf_to_mgmt =3D pf_to_mgmt; + mgmt_work->msg_len =3D recv_msg->msg_len; + memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len); + mgmt_work->msg_id =3D recv_msg->msg_id; + mgmt_work->mod =3D recv_msg->mod; + mgmt_work->cmd =3D recv_msg->cmd; + mgmt_work->async_mgmt_to_pf =3D recv_msg->async_mgmt_to_pf; + + INIT_WORK(&mgmt_work->work, hinic3_recv_mgmt_msg_work_handler); + queue_work(pf_to_mgmt->workq, &mgmt_work->work); +} + +static void +hinic3_recv_mgmt_msg_handler(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt, + const u8 *header, + struct hinic3_recv_msg *recv_msg) +{ + struct hinic3_hwdev *hwdev =3D pf_to_mgmt->hwdev; + const void *seg_data; + __le64 msg_header; + bool is_complete; + u8 dir, msg_id; + int err; + + msg_header =3D *(__force __le64 *)header; + dir =3D MBOX_MSG_HEADER_GET(msg_header, DIRECTION); + msg_id =3D MBOX_MSG_HEADER_GET(msg_header, MSG_ID); + /* Don't need to get anything from hw when cmd is async */ + if (dir =3D=3D MBOX_MSG_RESP && (msg_id & MGMT_ASYNC_MSG_FLAG)) + return; + + seg_data =3D header + sizeof(msg_header); + err =3D hinic3_recv_msg_add_seg(recv_msg, msg_header, + seg_data, &is_complete); + if (err) { + dev_err(hwdev->dev, "invalid receive segment\n"); + /* set seq_id to invalid seq_id */ + recv_msg->seq_id =3D MGMT_BOGUS_SEQ_ID; + + return; + } + + if (!is_complete) + return; + + recv_msg->cmd =3D MBOX_MSG_HEADER_GET(msg_header, CMD); + recv_msg->mod =3D MBOX_MSG_HEADER_GET(msg_header, MODULE); + recv_msg->async_mgmt_to_pf =3D MBOX_MSG_HEADER_GET(msg_header, NO_ACK); + recv_msg->seq_id =3D MGMT_BOGUS_SEQ_ID; + + if (dir =3D=3D MBOX_MSG_RESP) + hinic3_mgmt_resp_msg_handler(pf_to_mgmt, recv_msg); + else + hinic3_init_mgmt_msg_work(pf_to_mgmt, recv_msg); +} + +static int alloc_recv_msg(struct hinic3_recv_msg *recv_msg) +{ + recv_msg->seq_id =3D MGMT_BOGUS_SEQ_ID; + + recv_msg->msg =3D kzalloc(MGMT_MAX_PF_BUF_SIZE, GFP_KERNEL); + if (!recv_msg->msg) + return -ENOMEM; + + return 0; +} + +static void free_recv_msg(struct hinic3_recv_msg *recv_msg) +{ + kfree(recv_msg->msg); +} + +static int alloc_msg_buf(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt) +{ + struct device *dev =3D pf_to_mgmt->hwdev->dev; + int err; + + err =3D alloc_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt); + if (err) { + dev_err(dev, "Failed to allocate recv msg\n"); + return err; + } + + err =3D alloc_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt); + if (err) { + dev_err(dev, "Failed to allocate resp recv msg\n"); + goto err_free_msg_from_mgmt; + } + + pf_to_mgmt->mgmt_ack_buf =3D kzalloc(MGMT_MAX_PF_BUF_SIZE, GFP_KERNEL); + if (!pf_to_mgmt->mgmt_ack_buf) { + err =3D -ENOMEM; + goto err_free_resp_msg_from_mgmt; + } + + return 0; + +err_free_resp_msg_from_mgmt: + free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt); +err_free_msg_from_mgmt: + free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt); + + return err; +} + +static void free_msg_buf(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt) +{ + kfree(pf_to_mgmt->mgmt_ack_buf); + + free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt); + free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt); +} + +int hinic3_pf_to_mgmt_init(struct hinic3_hwdev *hwdev) +{ + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + int err; + + pf_to_mgmt =3D kzalloc(sizeof(*pf_to_mgmt), GFP_KERNEL); + if (!pf_to_mgmt) + return -ENOMEM; + + hwdev->pf_to_mgmt =3D pf_to_mgmt; + pf_to_mgmt->hwdev =3D hwdev; + spin_lock_init(&pf_to_mgmt->sync_event_lock); + pf_to_mgmt->workq =3D create_singlethread_workqueue(HINIC3_MGMT_WQ_NAME); + if (!pf_to_mgmt->workq) { + dev_err(hwdev->dev, "Failed to initialize MGMT workqueue\n"); + err =3D -ENOMEM; + goto err_free_pf_to_mgmt; + } + + err =3D alloc_msg_buf(pf_to_mgmt); + if (err) { + dev_err(hwdev->dev, "Failed to allocate msg buffers\n"); + goto err_destroy_workqueue; + } + + return 0; + +err_destroy_workqueue: + destroy_workqueue(pf_to_mgmt->workq); +err_free_pf_to_mgmt: + kfree(pf_to_mgmt); + + return err; +} + +void hinic3_pf_to_mgmt_free(struct hinic3_hwdev *hwdev) +{ + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt =3D hwdev->pf_to_mgmt; + + /* destroy workqueue before free related pf_to_mgmt resources in case of + * illegal resource access + */ + destroy_workqueue(pf_to_mgmt->workq); + + free_msg_buf(pf_to_mgmt); + kfree(pf_to_mgmt); +} + void hinic3_flush_mgmt_workq(struct hinic3_hwdev *hwdev) { if (hwdev->aeqs) flush_workqueue(hwdev->aeqs->workq); + + if (HINIC3_IS_PF(hwdev) && hwdev->pf_to_mgmt) + flush_workqueue(hwdev->pf_to_mgmt->workq); } =20 void hinic3_mgmt_msg_aeqe_handler(struct hinic3_hwdev *hwdev, u8 *header, u8 size) { + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + struct hinic3_recv_msg *recv_msg; + __le64 msg_header; + bool is_send_dir; + if (MBOX_MSG_HEADER_GET(*(__force __le64 *)header, SOURCE) =3D=3D - MBOX_MSG_FROM_MBOX) + MBOX_MSG_FROM_MBOX) { hinic3_mbox_func_aeqe_handler(hwdev, header, size); + + return; + } + + pf_to_mgmt =3D hwdev->pf_to_mgmt; + msg_header =3D *(__force __le64 *)header; + + is_send_dir =3D (MBOX_MSG_HEADER_GET(msg_header, DIRECTION) =3D=3D + MBOX_MSG_SEND) ? true : false; + + recv_msg =3D is_send_dir ? &pf_to_mgmt->recv_msg_from_mgmt : + &pf_to_mgmt->recv_resp_msg_from_mgmt; + + hinic3_recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg); } diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.h b/drivers/net= /ethernet/huawei/hinic3/hinic3_mgmt.h index bbef3b32a6ec..56f48d5442bc 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.h @@ -6,8 +6,61 @@ =20 #include =20 +#include "hinic3_mbox.h" +#include "hinic3_hw_intf.h" + struct hinic3_hwdev; =20 +struct hinic3_recv_msg { + /* Preallocated buffer of size MAX_PF_MGMT_BUF_SIZE that accumulates + * receive message, segment-by-segment. + */ + void *msg; + /* Message id for which segments are accumulated. */ + u8 msg_id; + /* Sequence id of last received segment of current message. */ + u8 seq_id; + u16 msg_len; + int async_mgmt_to_pf; + enum mgmt_mod_type mod; + u16 cmd; + struct completion recv_done; +}; + +enum comm_pf_to_mgmt_event_state { + COMM_SEND_EVENT_UNINIT, + COMM_SEND_EVENT_START, + COMM_SEND_EVENT_SUCCESS, + COMM_SEND_EVENT_TIMEOUT, +}; + +struct hinic3_msg_pf_to_mgmt { + struct hinic3_hwdev *hwdev; + struct workqueue_struct *workq; + void *mgmt_ack_buf; + struct hinic3_recv_msg recv_msg_from_mgmt; + struct hinic3_recv_msg recv_resp_msg_from_mgmt; + u16 async_msg_id; + u16 sync_msg_id; + void *async_msg_cb_data[MGMT_MOD_HW_MAX]; + /* synchronizes message send with message receives via event queue */ + spinlock_t sync_event_lock; + enum comm_pf_to_mgmt_event_state event_flag; +}; + +struct mgmt_msg_handle_work { + struct work_struct work; + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + void *msg; + u16 msg_len; + enum mgmt_mod_type mod; + u16 cmd; + u16 msg_id; + int async_mgmt_to_pf; +}; + +int hinic3_pf_to_mgmt_init(struct hinic3_hwdev *hwdev); +void hinic3_pf_to_mgmt_free(struct hinic3_hwdev *hwdev); void hinic3_flush_mgmt_workq(struct hinic3_hwdev *hwdev); void hinic3_mgmt_msg_aeqe_handler(struct hinic3_hwdev *hwdev, u8 *header, u8 size); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/d= rivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index f9a3222b1b46..3a6d3ee534d0 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -190,6 +190,7 @@ enum l2nic_ucode_cmd { =20 /* hilink mac group command */ enum mag_cmd { + MAG_CMD_SET_PORT_ENABLE =3D 6, MAG_CMD_GET_LINK_STATUS =3D 7, }; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index 0fa3c7900225..3d371291ad04 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -327,6 +327,31 @@ static void hinic3_close_channel(struct net_device *ne= tdev) hinic3_free_qp_ctxts(nic_dev); } =20 +static int hinic3_maybe_set_port_state(struct net_device *netdev, bool ena= ble) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + int err; + + mutex_lock(&nic_dev->port_state_mutex); + err =3D hinic3_set_port_enable(nic_dev->hwdev, enable); + mutex_unlock(&nic_dev->port_state_mutex); + + return err; +} + +static void hinic3_print_link_message(struct net_device *netdev, + bool link_status_up) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + + if (nic_dev->link_status_up =3D=3D link_status_up) + return; + + nic_dev->link_status_up =3D link_status_up; + + netdev_dbg(netdev, "Link is %s\n", str_up_down(link_status_up)); +} + static int hinic3_vport_up(struct net_device *netdev) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); @@ -341,6 +366,12 @@ static int hinic3_vport_up(struct net_device *netdev) goto err_flush_qps_res; } =20 + err =3D hinic3_maybe_set_port_state(netdev, true); + if (err) { + netdev_err(netdev, "Failed to enable port\n"); + goto err_disable_vport; + } + err =3D netif_set_real_num_queues(netdev, nic_dev->q_params.num_qps, nic_dev->q_params.num_qps); if (err) { @@ -353,8 +384,12 @@ static int hinic3_vport_up(struct net_device *netdev) if (!err && link_status_up) netif_carrier_on(netdev); =20 + hinic3_print_link_message(netdev, link_status_up); + return 0; =20 +err_disable_vport: + hinic3_set_vport_enable(nic_dev->hwdev, glb_func_id, false); err_flush_qps_res: hinic3_flush_qps_res(nic_dev->hwdev); /* wait to guarantee that no packets will be sent to host */ diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index e784f1b04a41..7fec13bbe60e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -366,6 +366,34 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwde= v) return pkt_drop.msg_head.status; } =20 +int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable) +{ + struct mag_cmd_set_port_enable en_state =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + if (HINIC3_IS_VF(hwdev)) + return 0; + + en_state.function_id =3D hinic3_global_func_id(hwdev); + en_state.state =3D enable ? MAG_CMD_TX_ENABLE | MAG_CMD_RX_ENABLE : + MAG_CMD_PORT_DISABLE; + + mgmt_msg_params_init_default(&msg_params, &en_state, + sizeof(en_state)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_HILINK, + MAG_CMD_SET_PORT_ENABLE, &msg_params); + + if (err || en_state.head.status) { + dev_err(hwdev->dev, "Failed to set port state, err: %d, status: 0x%x\n", + err, en_state.head.status); + return -EFAULT; + } + + return 0; +} + int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state) { struct l2nic_cmd_set_dcb_state dcb_state =3D {}; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index 08bf14679bf8..d4326937db48 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -34,6 +34,23 @@ struct hinic3_sq_attr { u64 ci_dma_base; }; =20 +#define MAG_CMD_PORT_DISABLE 0x0 +#define MAG_CMD_TX_ENABLE 0x1 +#define MAG_CMD_RX_ENABLE 0x2 +/* the physical port is disabled only when all pf of the port are set to d= own, + * if any pf is enabled, the port is enabled + */ +struct mag_cmd_set_port_enable { + struct mgmt_msg_head head; + + u16 function_id; + u16 rsvd0; + + /* bitmap bit0:tx_en bit1:rx_en */ + u8 state; + u8 rsvd1[3]; +}; + int hinic3_get_nic_feature_from_hw(struct hinic3_nic_dev *nic_dev); int hinic3_set_nic_feature_to_hw(struct hinic3_nic_dev *nic_dev); bool hinic3_test_support(struct hinic3_nic_dev *nic_dev, @@ -57,6 +74,7 @@ int hinic3_flush_qps_res(struct hinic3_hwdev *hwdev); int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev); =20 int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state= ); +int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable); int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_u= p); int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id, bool enable); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 5ba83261616c..52bcf6fb14f2 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -83,6 +83,9 @@ struct hinic3_nic_dev { =20 struct hinic3_intr_coal_info *intr_coalesce; =20 + /* lock for enable/disable port */ + struct mutex port_state_mutex; + bool link_status_up; }; =20 --=20 2.43.0 From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout03.his.huawei.com (canpmsgout03.his.huawei.com [113.46.200.218]) (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 54BA63590A3; Wed, 19 Nov 2025 12:44:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.218 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556253; cv=none; b=ukQ0l4ZjIL5/W1gFu3/RvIB521h8yE1304o0lWVc5oN0xLZX91Yp/QjyoSUmywBi6kpwdYwWucEqcFIGCIBb0R/LyiCW1eJqlyCsVWACT+yHyPcgLzSnOlFP8DvQ+8V/+ntXltbyuICZCLINasS4k4Vw6EL9H5eYw8m3ux0OkfI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556253; c=relaxed/simple; bh=V5zPEgQ7V0aKomvP5bLgA4HXTUrs+9cQus7O5AqNaRg=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HoUaiFEoytyjoO45tGrJz0LpM9AJdQODS05P3ddIu5th1KHLeD6wHRPyrnv/NQEVhJi1yBI1jVdtlZFvtU9RU6oh8glc8h3K9ez9DUOUQe9qfxB5T6oCptFZP/8ySDe2c4Ic+RN3OUAEMhGEC8T6gtoQUX5btJyqRzfymLsyK/Q= 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=QD489fAl; arc=none smtp.client-ip=113.46.200.218 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="QD489fAl" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=Vt4RfNnxosKtTjHH0aWHYwqePHpE9SDJvLjva/kFwHA=; b=QD489fAlAMFCSEH7uxnzZEsxjq9Sq3lCmtIIExsch+wT+Hh8zeAfbAsypfqsPt4PELau45zlA v1vgZDK+SSU9MXxj+wmB9oe/Lft/vWjAnLKM/vdxVhx3FR8v9h7rM8g2JANQsv7bBBWWurI3uEs dKfNdCdfpA0ruT6aTXL817c= Received: from mail.maildlp.com (unknown [172.19.163.252]) by canpmsgout03.his.huawei.com (SkyGuard) with ESMTPS id 4dBLhs44VGzpSwp; Wed, 19 Nov 2025 20:42:05 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id D96E2180B56; Wed, 19 Nov 2025 20:44:00 +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:43:59 +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 3/9] hinic3: Add .ndo_tx_timeout and .ndo_get_stats64 Date: Wed, 19 Nov 2025 20:43:36 +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" Implement following callback function: .ndo_tx_timeout .ndo_get_stats64 Use a work queue to trace tx_timeout callback and dump necessary debug information. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 9 +++ .../net/ethernet/huawei/hinic3/hinic3_main.c | 39 +++++++++- .../huawei/hinic3/hinic3_netdev_ops.c | 77 +++++++++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 8 ++ .../net/ethernet/huawei/hinic3/hinic3_rx.h | 15 ++++ .../net/ethernet/huawei/hinic3/hinic3_tx.h | 16 ++++ 6 files changed, 162 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.h index 3c15f22973fe..58bc561f95b3 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h @@ -17,6 +17,15 @@ enum hinic3_event_service_type { HINIC3_EVENT_SRV_NIC =3D 1 }; =20 +enum hinic3_fault_err_level { + HINIC3_FAULT_LEVEL_SERIOUS_FLR =3D 3, +}; + +enum hinic3_fault_source_type { + HINIC3_FAULT_SRC_HW_PHY_FAULT =3D 9, + HINIC3_FAULT_SRC_TX_TIMEOUT =3D 22, +}; + #define HINIC3_SRV_EVENT_TYPE(svc, type) (((svc) << 16) | (type)) =20 /* driver-specific data of pci_dev */ diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index ce10ae7c0d9e..4503c9303ee4 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -108,6 +108,22 @@ static void hinic3_free_txrxqs(struct net_device *netd= ev) hinic3_free_txqs(netdev); } =20 +static void hinic3_periodic_work_handler(struct work_struct *work) +{ + struct delayed_work *delay =3D to_delayed_work(work); + struct hinic3_nic_dev *nic_dev; + + nic_dev =3D container_of(delay, struct hinic3_nic_dev, periodic_work); + if (test_and_clear_bit(HINIC3_EVENT_WORK_TX_TIMEOUT, + &nic_dev->event_flag)) + dev_info(nic_dev->hwdev->dev, + "Fault event report, src: %u, level: %u\n", + HINIC3_FAULT_SRC_TX_TIMEOUT, + HINIC3_FAULT_LEVEL_SERIOUS_FLR); + + queue_delayed_work(nic_dev->workq, &nic_dev->periodic_work, HZ); +} + static int hinic3_init_nic_dev(struct net_device *netdev, struct hinic3_hwdev *hwdev) { @@ -123,6 +139,15 @@ static int hinic3_init_nic_dev(struct net_device *netd= ev, nic_dev->lro_replenish_thld =3D HINIC3_LRO_REPLENISH_THLD; nic_dev->nic_svc_cap =3D hwdev->cfg_mgmt->cap.nic_svc_cap; =20 + nic_dev->workq =3D create_singlethread_workqueue(HINIC3_NIC_DEV_WQ_NAME); + if (!nic_dev->workq) { + dev_err(hwdev->dev, "Failed to initialize nic workqueue\n"); + return -ENOMEM; + } + + INIT_DELAYED_WORK(&nic_dev->periodic_work, + hinic3_periodic_work_handler); + return 0; } =20 @@ -276,6 +301,11 @@ static void hinic3_nic_event(struct auxiliary_device *= adev, } } =20 +static void hinic3_free_nic_dev(struct hinic3_nic_dev *nic_dev) +{ + destroy_workqueue(nic_dev->workq); +} + static int hinic3_nic_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) { @@ -316,7 +346,7 @@ static int hinic3_nic_probe(struct auxiliary_device *ad= ev, =20 err =3D hinic3_init_nic_io(nic_dev); if (err) - goto err_free_netdev; + goto err_free_nic_dev; =20 err =3D hinic3_sw_init(netdev); if (err) @@ -329,6 +359,7 @@ static int hinic3_nic_probe(struct auxiliary_device *ad= ev, if (err) goto err_uninit_sw; =20 + queue_delayed_work(nic_dev->workq, &nic_dev->periodic_work, HZ); netif_carrier_off(netdev); =20 err =3D register_netdev(netdev); @@ -346,7 +377,8 @@ static int hinic3_nic_probe(struct auxiliary_device *ad= ev, =20 err_free_nic_io: hinic3_free_nic_io(nic_dev); - +err_free_nic_dev: + hinic3_free_nic_dev(nic_dev); err_free_netdev: free_netdev(netdev); =20 @@ -368,6 +400,9 @@ static void hinic3_nic_remove(struct auxiliary_device *= adev) netdev =3D nic_dev->netdev; unregister_netdev(netdev); =20 + disable_delayed_work_sync(&nic_dev->periodic_work); + hinic3_free_nic_dev(nic_dev); + hinic3_update_nic_feature(nic_dev, 0); hinic3_set_nic_feature_to_hw(nic_dev); hinic3_sw_uninit(netdev); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index 3d371291ad04..16a17deb15d8 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -517,11 +517,88 @@ static int hinic3_set_mac_addr(struct net_device *net= dev, void *addr) return 0; } =20 +static void hinic3_tx_timeout(struct net_device *netdev, unsigned int txqu= eue) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_io_queue *sq; + u16 sw_pi, hw_ci; + + sq =3D nic_dev->txqs[txqueue].sq; + sw_pi =3D hinic3_get_sq_local_pi(sq); + hw_ci =3D hinic3_get_sq_hw_ci(sq); + netdev_dbg(netdev, + "txq%u: sw_pi: %u, hw_ci: %u, sw_ci: %u, napi->state: 0x%lx.\n", + txqueue, sw_pi, hw_ci, hinic3_get_sq_local_ci(sq), + nic_dev->q_params.irq_cfg[txqueue].napi.state); + + if (sw_pi !=3D hw_ci) + set_bit(HINIC3_EVENT_WORK_TX_TIMEOUT, &nic_dev->event_flag); +} + +static void hinic3_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + u64 bytes, packets, dropped, errors; + struct hinic3_txq_stats *txq_stats; + struct hinic3_rxq_stats *rxq_stats; + struct hinic3_txq *txq; + struct hinic3_rxq *rxq; + unsigned int start; + int i; + + bytes =3D 0; + packets =3D 0; + dropped =3D 0; + for (i =3D 0; i < nic_dev->max_qps; i++) { + if (!nic_dev->txqs) + break; + + txq =3D &nic_dev->txqs[i]; + txq_stats =3D &txq->txq_stats; + do { + start =3D u64_stats_fetch_begin(&txq_stats->syncp); + bytes +=3D txq_stats->bytes; + packets +=3D txq_stats->packets; + dropped +=3D txq_stats->dropped; + } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); + } + stats->tx_packets =3D packets; + stats->tx_bytes =3D bytes; + stats->tx_dropped =3D dropped; + + bytes =3D 0; + packets =3D 0; + errors =3D 0; + dropped =3D 0; + for (i =3D 0; i < nic_dev->max_qps; i++) { + if (!nic_dev->rxqs) + break; + + rxq =3D &nic_dev->rxqs[i]; + rxq_stats =3D &rxq->rxq_stats; + do { + start =3D u64_stats_fetch_begin(&rxq_stats->syncp); + bytes +=3D rxq_stats->bytes; + packets +=3D rxq_stats->packets; + errors +=3D rxq_stats->csum_errors + + rxq_stats->other_errors; + dropped +=3D rxq_stats->dropped; + } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); + } + stats->rx_packets =3D packets; + stats->rx_bytes =3D bytes; + stats->rx_errors =3D errors; + stats->rx_dropped =3D dropped; +} + static const struct net_device_ops hinic3_netdev_ops =3D { .ndo_open =3D hinic3_open, .ndo_stop =3D hinic3_close, .ndo_change_mtu =3D hinic3_change_mtu, .ndo_set_mac_address =3D hinic3_set_mac_addr, + .ndo_tx_timeout =3D hinic3_tx_timeout, + .ndo_get_stats64 =3D hinic3_get_stats64, .ndo_start_xmit =3D hinic3_xmit_frame, }; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 52bcf6fb14f2..b8c9c325a45a 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -13,6 +13,10 @@ enum hinic3_flags { HINIC3_RSS_ENABLE, }; =20 +enum hinic3_event_work_flags { + HINIC3_EVENT_WORK_TX_TIMEOUT, +}; + enum hinic3_rss_hash_type { HINIC3_RSS_HASH_ENGINE_TYPE_XOR =3D 0, HINIC3_RSS_HASH_ENGINE_TYPE_TOEP =3D 1, @@ -83,9 +87,13 @@ struct hinic3_nic_dev { =20 struct hinic3_intr_coal_info *intr_coalesce; =20 + struct workqueue_struct *workq; + struct delayed_work periodic_work; /* lock for enable/disable port */ struct mutex port_state_mutex; =20 + /* flag bits defined by hinic3_event_work_flags */ + unsigned long event_flag; bool link_status_up; }; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h b/drivers/net/e= thernet/huawei/hinic3/hinic3_rx.h index 44ae841a3648..68fc237d642b 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h @@ -25,6 +25,20 @@ #define RQ_CQE_STATUS_GET(val, member) \ FIELD_GET(RQ_CQE_STATUS_##member##_MASK, val) =20 +struct hinic3_rxq_stats { + u64 packets; + u64 bytes; + u64 errors; + u64 csum_errors; + u64 other_errors; + u64 dropped; + u64 rx_buf_empty; + u64 alloc_skb_err; + u64 alloc_rx_buf_err; + u64 restore_drop_sge; + struct u64_stats_sync syncp; +}; + /* RX Completion information that is provided by HW for a specific RX WQE = */ struct hinic3_rq_cqe { __le32 status; @@ -59,6 +73,7 @@ struct hinic3_rxq { u16 buf_len; u32 buf_len_shift; =20 + struct hinic3_rxq_stats rxq_stats; u32 cons_idx; u32 delta; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h b/drivers/net/e= thernet/huawei/hinic3/hinic3_tx.h index 7e1b872ba752..00194f2a1bcc 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h @@ -100,6 +100,20 @@ struct hinic3_sq_wqe_combo { u32 task_type; }; =20 +struct hinic3_txq_stats { + u64 packets; + u64 bytes; + u64 busy; + u64 dropped; + u64 skb_pad_err; + u64 frag_len_overflow; + u64 offload_cow_skb_err; + u64 map_frag_err; + u64 unknown_tunnel_pkt; + u64 frag_size_err; + struct u64_stats_sync syncp; +}; + struct hinic3_dma_info { dma_addr_t dma; u32 len; @@ -123,6 +137,8 @@ struct hinic3_txq { =20 struct hinic3_tx_info *tx_info; struct hinic3_io_queue *sq; + + struct hinic3_txq_stats txq_stats; } ____cacheline_aligned; =20 struct hinic3_dyna_txq_res { --=20 2.43.0 From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout05.his.huawei.com (canpmsgout05.his.huawei.com [113.46.200.220]) (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 387C1359F8B; Wed, 19 Nov 2025 12:44:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.220 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556252; cv=none; b=MRFxGD1kMIM8j4tuwomj9GElNmjeHeUBLLJQX80smdUCtB6GzaHGFmbPkRP5ZNiny9JQcY5Y54OUg2lf/gMYUX9Dw9vHq/Tj0VHRWxrdTgsxGNWtUael0mDtNloJYjp/mbf40FbHNZn0hj+mFCXgVTH5qnxjv6sbZdSvO0kj0ws= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556252; c=relaxed/simple; bh=jrM5cgcV1cJohIs/FY7VPbvNe8nhB3Oly2yey0low9g=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=i9VvOPM4JsEdIeNwKGpdT1YnN+9sgM/TZl6q9A2ZsFezuEF+VP7dRl8nJTsEIfBApke+sEOnBnUckBDJvTJ4WeEaoY5XvcX+tRifj4kjbVqE2m3S68QyMVe767G1RNfjJ1z/j/JubLK4ZkckPlvXaKdahRFeB1Yqpxkr6Mgx0Ow= 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=sPdhC2K8; arc=none smtp.client-ip=113.46.200.220 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="sPdhC2K8" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=NAfzeS+BkTKzD/AtiyMnFFpFNZaaQkEUpMvYzdclXvI=; b=sPdhC2K8+v2iPPn3JOch/GMuRkstwHasu4XirKV4XUU1QT5+EGrjPlzjbER0mbIftt57fdjFD jMN7AYFyhJh3iMBTxiDTS8CkkqJFf7pmfkfwr31XXh9ix9RZ3f2cXSDVeUle5f1r2aneyrjvaGn enfFjJiqxJdUYBtowgKa4x8= Received: from mail.maildlp.com (unknown [172.19.88.105]) by canpmsgout05.his.huawei.com (SkyGuard) with ESMTPS id 4dBLjR4BnQz12LCZ; Wed, 19 Nov 2025 20:42:35 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 1903D1400DC; Wed, 19 Nov 2025 20:44:03 +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:01 +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 4/9] hinic3: Add .ndo_set_features and .ndo_fix_features Date: Wed, 19 Nov 2025 20:43:37 +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" Implement following callback function: .ndo_set_features .ndo_fix_features The .ndo_set_features function includes five features: rx_csum, tso, lro, rx_cvlan and vlan_filter. Add these new features in netdev_feature_init. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../net/ethernet/huawei/hinic3/hinic3_main.c | 33 +++- .../huawei/hinic3/hinic3_mgmt_interface.h | 40 +++++ .../huawei/hinic3/hinic3_netdev_ops.c | 161 ++++++++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 130 ++++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 5 + .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 2 + 6 files changed, 370 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 4503c9303ee4..704afd3189ee 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -227,6 +227,8 @@ static void hinic3_assign_netdev_ops(struct net_device = *netdev) static void netdev_feature_init(struct net_device *netdev) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + netdev_features_t hw_features =3D 0; + netdev_features_t vlan_fts =3D 0; netdev_features_t cso_fts =3D 0; netdev_features_t tso_fts =3D 0; netdev_features_t dft_fts; @@ -239,7 +241,29 @@ static void netdev_feature_init(struct net_device *net= dev) if (hinic3_test_support(nic_dev, HINIC3_NIC_F_TSO)) tso_fts |=3D NETIF_F_TSO | NETIF_F_TSO6; =20 - netdev->features |=3D dft_fts | cso_fts | tso_fts; + if (hinic3_test_support(nic_dev, HINIC3_NIC_F_RX_VLAN_STRIP | + HINIC3_NIC_F_TX_VLAN_INSERT)) + vlan_fts |=3D NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; + + if (hinic3_test_support(nic_dev, HINIC3_NIC_F_RX_VLAN_FILTER)) + vlan_fts |=3D NETIF_F_HW_VLAN_CTAG_FILTER; + + if (hinic3_test_support(nic_dev, HINIC3_NIC_F_VXLAN_OFFLOAD)) + tso_fts |=3D NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL_CSUM; + + /* LRO is disabled by default, only set hw features */ + if (hinic3_test_support(nic_dev, HINIC3_NIC_F_LRO)) + hw_features |=3D NETIF_F_LRO; + + netdev->features |=3D dft_fts | cso_fts | tso_fts | vlan_fts; + netdev->vlan_features |=3D dft_fts | cso_fts | tso_fts; + hw_features |=3D netdev->hw_features | netdev->features; + netdev->hw_features =3D hw_features; + netdev->priv_flags |=3D IFF_UNICAST_FLT; + + netdev->hw_enc_features |=3D dft_fts; + if (hinic3_test_support(nic_dev, HINIC3_NIC_F_VXLAN_OFFLOAD)) + netdev->hw_enc_features |=3D cso_fts | tso_fts | NETIF_F_TSO_ECN; } =20 static int hinic3_set_default_hw_feature(struct net_device *netdev) @@ -254,6 +278,13 @@ static int hinic3_set_default_hw_feature(struct net_de= vice *netdev) return err; } =20 + err =3D hinic3_set_hw_features(netdev); + if (err) { + hinic3_update_nic_feature(nic_dev, 0); + hinic3_set_nic_feature_to_hw(nic_dev); + return err; + } + return 0; } =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/d= rivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index 3a6d3ee534d0..69405715e734 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -56,6 +56,22 @@ struct l2nic_cmd_update_mac { u8 new_mac[ETH_ALEN]; }; =20 +struct l2nic_cmd_vlan_offload { + struct mgmt_msg_head msg_head; + u16 func_id; + u8 vlan_offload; + u8 rsvd1[5]; +}; + +/* set vlan filter */ +struct l2nic_cmd_set_vlan_filter { + struct mgmt_msg_head msg_head; + u16 func_id; + u8 rsvd[2]; + /* bit0:vlan filter en; bit1:broadcast_filter_en */ + u32 vlan_filter_ctrl; +}; + struct l2nic_cmd_set_ci_attr { struct mgmt_msg_head msg_head; u16 func_idx; @@ -102,6 +118,26 @@ struct l2nic_cmd_set_dcb_state { u8 rsvd[7]; }; =20 +struct l2nic_cmd_lro_config { + struct mgmt_msg_head msg_head; + u16 func_id; + u8 opcode; + u8 rsvd1; + u8 lro_ipv4_en; + u8 lro_ipv6_en; + /* unit is 1K */ + u8 lro_max_pkt_len; + u8 resv2[13]; +}; + +struct l2nic_cmd_lro_timer { + struct mgmt_msg_head msg_head; + /* 1: set timer value, 0: get timer value */ + u8 opcode; + u8 rsvd[3]; + u32 timer; +}; + #define L2NIC_RSS_TYPE_VALID_MASK BIT(23) #define L2NIC_RSS_TYPE_TCP_IPV6_EXT_MASK BIT(24) #define L2NIC_RSS_TYPE_IPV6_EXT_MASK BIT(25) @@ -162,11 +198,15 @@ enum l2nic_cmd { L2NIC_CMD_SET_VPORT_ENABLE =3D 6, L2NIC_CMD_SET_SQ_CI_ATTR =3D 8, L2NIC_CMD_CLEAR_QP_RESOURCE =3D 11, + L2NIC_CMD_CFG_RX_LRO =3D 13, + L2NIC_CMD_CFG_LRO_TIMER =3D 14, L2NIC_CMD_FEATURE_NEGO =3D 15, L2NIC_CMD_GET_MAC =3D 20, L2NIC_CMD_SET_MAC =3D 21, L2NIC_CMD_DEL_MAC =3D 22, L2NIC_CMD_UPDATE_MAC =3D 23, + L2NIC_CMD_SET_VLAN_FILTER_EN =3D 26, + L2NIC_CMD_SET_RX_VLAN_OFFLOAD =3D 27, L2NIC_CMD_CFG_RSS =3D 60, L2NIC_CMD_CFG_RSS_HASH_KEY =3D 63, L2NIC_CMD_CFG_RSS_HASH_ENGINE =3D 64, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index 16a17deb15d8..f7e6fbdec40b 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -12,6 +12,9 @@ #include "hinic3_rx.h" #include "hinic3_tx.h" =20 +#define HINIC3_LRO_DEFAULT_COAL_PKT_SIZE 32 +#define HINIC3_LRO_DEFAULT_TIME_LIMIT 16 + /* try to modify the number of irq to the target number, * and return the actual number of irq. */ @@ -476,6 +479,162 @@ static int hinic3_close(struct net_device *netdev) return 0; } =20 +#define SET_FEATURES_OP_STR(op) ((op) ? "Enable" : "Disable") + +static int hinic3_set_feature_rx_csum(struct net_device *netdev, + netdev_features_t wanted_features, + netdev_features_t features, + netdev_features_t *failed_features) +{ + netdev_features_t changed =3D wanted_features ^ features; + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_hwdev *hwdev =3D nic_dev->hwdev; + + if (changed & NETIF_F_RXCSUM) + dev_dbg(hwdev->dev, "%s rx csum success\n", + SET_FEATURES_OP_STR(wanted_features & NETIF_F_RXCSUM)); + + return 0; +} + +static int hinic3_set_feature_tso(struct net_device *netdev, + netdev_features_t wanted_features, + netdev_features_t features, + netdev_features_t *failed_features) +{ + netdev_features_t changed =3D wanted_features ^ features; + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_hwdev *hwdev =3D nic_dev->hwdev; + + if (changed & NETIF_F_TSO) + dev_dbg(hwdev->dev, "%s tso success\n", + SET_FEATURES_OP_STR(wanted_features & NETIF_F_TSO)); + + return 0; +} + +static int hinic3_set_feature_lro(struct net_device *netdev, + netdev_features_t wanted_features, + netdev_features_t features, + netdev_features_t *failed_features) +{ + netdev_features_t changed =3D wanted_features ^ features; + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_hwdev *hwdev =3D nic_dev->hwdev; + bool en =3D !!(wanted_features & NETIF_F_LRO); + int err; + + if (!(changed & NETIF_F_LRO)) + return 0; + + err =3D hinic3_set_rx_lro_state(hwdev, en, + HINIC3_LRO_DEFAULT_TIME_LIMIT, + HINIC3_LRO_DEFAULT_COAL_PKT_SIZE); + if (err) { + dev_err(hwdev->dev, "%s lro failed\n", SET_FEATURES_OP_STR(en)); + *failed_features |=3D NETIF_F_LRO; + } + + return err; +} + +static int hinic3_set_feature_rx_cvlan(struct net_device *netdev, + netdev_features_t wanted_features, + netdev_features_t features, + netdev_features_t *failed_features) +{ + bool en =3D !!(wanted_features & NETIF_F_HW_VLAN_CTAG_RX); + netdev_features_t changed =3D wanted_features ^ features; + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_hwdev *hwdev =3D nic_dev->hwdev; + int err; + + if (!(changed & NETIF_F_HW_VLAN_CTAG_RX)) + return 0; + + err =3D hinic3_set_rx_vlan_offload(hwdev, en); + if (err) { + dev_err(hwdev->dev, "%s rx vlan offload failed\n", + SET_FEATURES_OP_STR(en)); + *failed_features |=3D NETIF_F_HW_VLAN_CTAG_RX; + } + + return err; +} + +static int hinic3_set_feature_vlan_filter(struct net_device *netdev, + netdev_features_t wanted_features, + netdev_features_t features, + netdev_features_t *failed_features) +{ + bool en =3D !!(wanted_features & NETIF_F_HW_VLAN_CTAG_FILTER); + netdev_features_t changed =3D wanted_features ^ features; + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_hwdev *hwdev =3D nic_dev->hwdev; + int err; + + if (!(changed & NETIF_F_HW_VLAN_CTAG_FILTER)) + return 0; + + err =3D hinic3_set_vlan_filter(hwdev, en); + if (err) { + dev_err(hwdev->dev, "%s rx vlan filter failed\n", + SET_FEATURES_OP_STR(en)); + *failed_features |=3D NETIF_F_HW_VLAN_CTAG_FILTER; + } + + return err; +} + +static int hinic3_set_features(struct net_device *netdev, + netdev_features_t curr, + netdev_features_t wanted) +{ + netdev_features_t failed =3D 0; + int err; + + err =3D hinic3_set_feature_rx_csum(netdev, wanted, curr, &failed) | + hinic3_set_feature_tso(netdev, wanted, curr, &failed) | + hinic3_set_feature_lro(netdev, wanted, curr, &failed) | + hinic3_set_feature_rx_cvlan(netdev, wanted, curr, &failed) | + hinic3_set_feature_vlan_filter(netdev, wanted, curr, &failed); + if (err) { + netdev->features =3D wanted ^ failed; + return err; + } + + return 0; +} + +static int hinic3_ndo_set_features(struct net_device *netdev, + netdev_features_t features) +{ + return hinic3_set_features(netdev, netdev->features, features); +} + +static netdev_features_t hinic3_fix_features(struct net_device *netdev, + netdev_features_t features) +{ + netdev_features_t features_tmp =3D features; + + /* If Rx checksum is disabled, then LRO should also be disabled */ + if (!(features_tmp & NETIF_F_RXCSUM)) + features_tmp &=3D ~NETIF_F_LRO; + + return features_tmp; +} + +int hinic3_set_hw_features(struct net_device *netdev) +{ + netdev_features_t wanted, curr; + + wanted =3D netdev->features; + /* fake current features so all wanted are enabled */ + curr =3D ~wanted; + + return hinic3_set_features(netdev, curr, wanted); +} + static int hinic3_change_mtu(struct net_device *netdev, int new_mtu) { int err; @@ -595,6 +754,8 @@ static void hinic3_get_stats64(struct net_device *netde= v, static const struct net_device_ops hinic3_netdev_ops =3D { .ndo_open =3D hinic3_open, .ndo_stop =3D hinic3_close, + .ndo_set_features =3D hinic3_ndo_set_features, + .ndo_fix_features =3D hinic3_fix_features, .ndo_change_mtu =3D hinic3_change_mtu, .ndo_set_mac_address =3D hinic3_set_mac_addr, .ndo_tx_timeout =3D hinic3_tx_timeout, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index 7fec13bbe60e..c8944c51e6bf 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -57,6 +57,136 @@ bool hinic3_test_support(struct hinic3_nic_dev *nic_dev, return (nic_dev->nic_io->feature_cap & feature_bits) =3D=3D feature_bits; } =20 +static int hinic3_set_rx_lro(struct hinic3_hwdev *hwdev, u8 ipv4_en, u8 ip= v6_en, + u8 lro_max_pkt_len) +{ + struct l2nic_cmd_lro_config lro_cfg =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + lro_cfg.func_id =3D hinic3_global_func_id(hwdev); + lro_cfg.opcode =3D MGMT_MSG_CMD_OP_SET; + lro_cfg.lro_ipv4_en =3D ipv4_en; + lro_cfg.lro_ipv6_en =3D ipv6_en; + lro_cfg.lro_max_pkt_len =3D lro_max_pkt_len; + + mgmt_msg_params_init_default(&msg_params, &lro_cfg, + sizeof(lro_cfg)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_CFG_RX_LRO, + &msg_params); + + if (err || lro_cfg.msg_head.status) { + dev_err(hwdev->dev, "Failed to set lro offload, err: %d, status: 0x%x\n", + err, lro_cfg.msg_head.status); + return -EFAULT; + } + + return 0; +} + +static int hinic3_set_rx_lro_timer(struct hinic3_hwdev *hwdev, u32 timer_v= alue) +{ + struct l2nic_cmd_lro_timer lro_timer =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + lro_timer.opcode =3D MGMT_MSG_CMD_OP_SET; + lro_timer.timer =3D timer_value; + + mgmt_msg_params_init_default(&msg_params, &lro_timer, + sizeof(lro_timer)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_CFG_LRO_TIMER, + &msg_params); + + if (err || lro_timer.msg_head.status) { + dev_err(hwdev->dev, "Failed to set lro timer, err: %d, status: 0x%x\n", + err, lro_timer.msg_head.status); + + return -EFAULT; + } + + return 0; +} + +int hinic3_set_rx_lro_state(struct hinic3_hwdev *hwdev, u8 lro_en, + u32 lro_timer, u8 lro_max_pkt_len) +{ + u8 ipv4_en, ipv6_en; + int err; + + ipv4_en =3D lro_en ? 1 : 0; + ipv6_en =3D lro_en ? 1 : 0; + + dev_dbg(hwdev->dev, "Set LRO max coalesce packet size to %uK\n", + lro_max_pkt_len); + + err =3D hinic3_set_rx_lro(hwdev, ipv4_en, ipv6_en, lro_max_pkt_len); + if (err) + return err; + + /* we don't set LRO timer for VF */ + if (HINIC3_IS_VF(hwdev)) + return 0; + + dev_dbg(hwdev->dev, "Set LRO timer to %u\n", lro_timer); + + return hinic3_set_rx_lro_timer(hwdev, lro_timer); +} + +int hinic3_set_rx_vlan_offload(struct hinic3_hwdev *hwdev, u8 en) +{ + struct l2nic_cmd_vlan_offload vlan_cfg =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + vlan_cfg.func_id =3D hinic3_global_func_id(hwdev); + vlan_cfg.vlan_offload =3D en; + + mgmt_msg_params_init_default(&msg_params, &vlan_cfg, + sizeof(vlan_cfg)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_SET_RX_VLAN_OFFLOAD, + &msg_params); + + if (err || vlan_cfg.msg_head.status) { + dev_err(hwdev->dev, "Failed to set rx vlan offload, err: %d, status: 0x%= x\n", + err, vlan_cfg.msg_head.status); + return -EFAULT; + } + + return 0; +} + +int hinic3_set_vlan_filter(struct hinic3_hwdev *hwdev, u32 vlan_filter_ctr= l) +{ + struct l2nic_cmd_set_vlan_filter vlan_filter; + struct mgmt_msg_params msg_params =3D {}; + int err; + + vlan_filter.func_id =3D hinic3_global_func_id(hwdev); + vlan_filter.vlan_filter_ctrl =3D vlan_filter_ctrl; + + mgmt_msg_params_init_default(&msg_params, &vlan_filter, + sizeof(vlan_filter)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_SET_VLAN_FILTER_EN, + &msg_params); + + if (err || vlan_filter.msg_head.status) { + dev_err(hwdev->dev, "Failed to set vlan filter, err: %d, status: 0x%x\n", + err, vlan_filter.msg_head.status); + return -EFAULT; + } + + return 0; +} + void hinic3_update_nic_feature(struct hinic3_nic_dev *nic_dev, u64 feature= _cap) { nic_dev->nic_io->feature_cap =3D feature_cap; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index d4326937db48..a17cd56bce71 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -57,6 +57,11 @@ bool hinic3_test_support(struct hinic3_nic_dev *nic_dev, enum hinic3_nic_feature_cap feature_bits); void hinic3_update_nic_feature(struct hinic3_nic_dev *nic_dev, u64 feature= _cap); =20 +int hinic3_set_rx_lro_state(struct hinic3_hwdev *hwdev, u8 lro_en, + u32 lro_timer, u8 lro_max_pkt_len); +int hinic3_set_rx_vlan_offload(struct hinic3_hwdev *hwdev, u8 en); +int hinic3_set_vlan_filter(struct hinic3_hwdev *hwdev, u32 vlan_filter_ctr= l); + int hinic3_init_function_table(struct hinic3_nic_dev *nic_dev); int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu); =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index b8c9c325a45a..a8e92e070d9e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -7,6 +7,7 @@ #include =20 #include "hinic3_hw_cfg.h" +#include "hinic3_hwdev.h" #include "hinic3_mgmt_interface.h" =20 enum hinic3_flags { @@ -98,6 +99,7 @@ struct hinic3_nic_dev { }; =20 void hinic3_set_netdev_ops(struct net_device *netdev); +int hinic3_set_hw_features(struct net_device *netdev); int hinic3_qps_irq_init(struct net_device *netdev); void hinic3_qps_irq_uninit(struct net_device *netdev); =20 --=20 2.43.0 From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout01.his.huawei.com (canpmsgout01.his.huawei.com [113.46.200.216]) (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 BA8CA3559C9; Wed, 19 Nov 2025 12:44:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.216 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556254; cv=none; b=hExhmSL9jbtpgECyOEisj7peD7daFKizj6f5sT3l+g6RfbSKVn/E2RodIrKhSnJn8DtOyRZR7WdpieNKlqIHVcUxt7+L0uwNsBR+RmRv3gjK6cRniMSLkkdksEudKk9YfBvs4flxojk63i8VhbFqasK4z5VmQob/b7uO2wptEbg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556254; c=relaxed/simple; bh=N/pG+796n6dtmC+ReMP+O0qSXOzw1+BxCsjlLHlqP6c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HIArryfHz2PicQ1sypS8+J9NgpB/OQRoasGK1bgvjDwKwpoIbdJKM+Id5PI1myoW3YMW3Gi1sauBhcyb6ucVvK19UTRIgh4yu/YW78Zpzl3odqnSaFQoEcyiT+gtkqtbYnf0dWQTbI6r5QAU/JvphVqI6Wmj63+N4CR4iUsKiW4= 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=JyQux/uV; arc=none smtp.client-ip=113.46.200.216 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="JyQux/uV" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=0jf9RYMP/5laEAnMJdwviHAN2p67D+g6/gkP5rRQzps=; b=JyQux/uVOsOKf4wPwFmjPlXCkBrMFOu5uOXo1WL9HD3QVih5DwARSZ0sXj9vyqz51lJbtLJyO pCjbacRa0AuzRpu5K2DqSa2TWXpgJ8cxDLClXrAr+W1+1GqwwFeEDKSzT/ATAM4tXd/2lh3/vlh DUVKvqWXauKLlN4M0ji7xwU= Received: from mail.maildlp.com (unknown [172.19.163.174]) by canpmsgout01.his.huawei.com (SkyGuard) with ESMTPS id 4dBLjR1WdGz1T4Fc; Wed, 19 Nov 2025 20:42:35 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 6DB7F140135; Wed, 19 Nov 2025 20:44:08 +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:07 +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 5/9] hinic3: Add .ndo_vlan_rx_add/kill_vid and .ndo_validate_addr Date: Wed, 19 Nov 2025 20:43:38 +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" Implement following callback function: .ndo_vlan_rx_add_vid .ndo_vlan_rx_kill_vid .ndo_validate_addr Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../net/ethernet/huawei/hinic3/hinic3_main.c | 7 +++ .../huawei/hinic3/hinic3_mgmt_interface.h | 10 +++ .../huawei/hinic3/hinic3_netdev_ops.c | 62 +++++++++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 41 ++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 2 + .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 6 ++ 6 files changed, 128 insertions(+) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 704afd3189ee..f0f347c6b6ba 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -137,11 +137,17 @@ static int hinic3_init_nic_dev(struct net_device *net= dev, =20 nic_dev->rx_buf_len =3D HINIC3_RX_BUF_LEN; nic_dev->lro_replenish_thld =3D HINIC3_LRO_REPLENISH_THLD; + nic_dev->vlan_bitmap =3D kzalloc(HINIC3_VLAN_BITMAP_SIZE(nic_dev), + GFP_KERNEL); + if (!nic_dev->vlan_bitmap) + return -ENOMEM; + nic_dev->nic_svc_cap =3D hwdev->cfg_mgmt->cap.nic_svc_cap; =20 nic_dev->workq =3D create_singlethread_workqueue(HINIC3_NIC_DEV_WQ_NAME); if (!nic_dev->workq) { dev_err(hwdev->dev, "Failed to initialize nic workqueue\n"); + kfree(nic_dev->vlan_bitmap); return -ENOMEM; } =20 @@ -335,6 +341,7 @@ static void hinic3_nic_event(struct auxiliary_device *a= dev, static void hinic3_free_nic_dev(struct hinic3_nic_dev *nic_dev) { destroy_workqueue(nic_dev->workq); + kfree(nic_dev->vlan_bitmap); } =20 static int hinic3_nic_probe(struct auxiliary_device *adev, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/d= rivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index 69405715e734..60f47152c01d 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -56,6 +56,15 @@ struct l2nic_cmd_update_mac { u8 new_mac[ETH_ALEN]; }; =20 +struct l2nic_cmd_vlan_config { + struct mgmt_msg_head msg_head; + u16 func_id; + u8 opcode; + u8 rsvd1; + u16 vlan_id; + u16 rsvd2; +}; + struct l2nic_cmd_vlan_offload { struct mgmt_msg_head msg_head; u16 func_id; @@ -205,6 +214,7 @@ enum l2nic_cmd { L2NIC_CMD_SET_MAC =3D 21, L2NIC_CMD_DEL_MAC =3D 22, L2NIC_CMD_UPDATE_MAC =3D 23, + L2NIC_CMD_CFG_FUNC_VLAN =3D 25, L2NIC_CMD_SET_VLAN_FILTER_EN =3D 26, L2NIC_CMD_SET_RX_VLAN_OFFLOAD =3D 27, L2NIC_CMD_CFG_RSS =3D 60, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index f7e6fbdec40b..1e298be6e0d1 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -15,6 +15,12 @@ #define HINIC3_LRO_DEFAULT_COAL_PKT_SIZE 32 #define HINIC3_LRO_DEFAULT_TIME_LIMIT 16 =20 +#define VLAN_BITMAP_BITS_SIZE(nic_dev) (sizeof(*(nic_dev)->vlan_bitmap)= * 8) +#define VID_LINE(nic_dev, vid) \ + ((vid) / VLAN_BITMAP_BITS_SIZE(nic_dev)) +#define VID_COL(nic_dev, vid) \ + ((vid) & (VLAN_BITMAP_BITS_SIZE(nic_dev) - 1)) + /* try to modify the number of irq to the target number, * and return the actual number of irq. */ @@ -676,6 +682,59 @@ static int hinic3_set_mac_addr(struct net_device *netd= ev, void *addr) return 0; } =20 +static int hinic3_vlan_rx_add_vid(struct net_device *netdev, + __be16 proto, u16 vid) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + unsigned long *vlan_bitmap =3D nic_dev->vlan_bitmap; + u32 column, row; + u16 func_id; + int err; + + column =3D VID_COL(nic_dev, vid); + row =3D VID_LINE(nic_dev, vid); + + func_id =3D hinic3_global_func_id(nic_dev->hwdev); + + err =3D hinic3_add_vlan(nic_dev->hwdev, vid, func_id); + if (err) { + netdev_err(netdev, "Failed to add vlan %u\n", vid); + goto out; + } + + set_bit(column, &vlan_bitmap[row]); + netdev_dbg(netdev, "Add vlan %u\n", vid); + +out: + return err; +} + +static int hinic3_vlan_rx_kill_vid(struct net_device *netdev, + __be16 proto, u16 vid) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + unsigned long *vlan_bitmap =3D nic_dev->vlan_bitmap; + u32 column, row; + u16 func_id; + int err; + + column =3D VID_COL(nic_dev, vid); + row =3D VID_LINE(nic_dev, vid); + + func_id =3D hinic3_global_func_id(nic_dev->hwdev); + err =3D hinic3_del_vlan(nic_dev->hwdev, vid, func_id); + if (err) { + netdev_err(netdev, "Failed to delete vlan %u\n", vid); + goto out; + } + + clear_bit(column, &vlan_bitmap[row]); + netdev_dbg(netdev, "Remove vlan %u\n", vid); + +out: + return err; +} + static void hinic3_tx_timeout(struct net_device *netdev, unsigned int txqu= eue) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); @@ -758,6 +817,9 @@ static const struct net_device_ops hinic3_netdev_ops = =3D { .ndo_fix_features =3D hinic3_fix_features, .ndo_change_mtu =3D hinic3_change_mtu, .ndo_set_mac_address =3D hinic3_set_mac_addr, + .ndo_validate_addr =3D eth_validate_addr, + .ndo_vlan_rx_add_vid =3D hinic3_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid =3D hinic3_vlan_rx_kill_vid, .ndo_tx_timeout =3D hinic3_tx_timeout, .ndo_get_stats64 =3D hinic3_get_stats64, .ndo_start_xmit =3D hinic3_xmit_frame, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index c8944c51e6bf..4a5356cf51a5 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -10,6 +10,9 @@ #include "hinic3_nic_dev.h" #include "hinic3_nic_io.h" =20 +#define MGMT_MSG_CMD_OP_ADD 1 +#define MGMT_MSG_CMD_OP_DEL 0 + static int hinic3_feature_nego(struct hinic3_hwdev *hwdev, u8 opcode, u64 *s_feature, u16 size) { @@ -496,6 +499,44 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwde= v) return pkt_drop.msg_head.status; } =20 +static int hinic3_config_vlan(struct hinic3_hwdev *hwdev, + u8 opcode, u16 vlan_id, u16 func_id) +{ + struct l2nic_cmd_vlan_config vlan_info =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + vlan_info.opcode =3D opcode; + vlan_info.func_id =3D func_id; + vlan_info.vlan_id =3D vlan_id; + + mgmt_msg_params_init_default(&msg_params, &vlan_info, + sizeof(vlan_info)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_CFG_FUNC_VLAN, &msg_params); + + if (err || vlan_info.msg_head.status) { + dev_err(hwdev->dev, + "Failed to %s vlan, err: %d, status: 0x%x\n", + opcode =3D=3D MGMT_MSG_CMD_OP_ADD ? "add" : "delete", + err, vlan_info.msg_head.status); + return -EFAULT; + } + + return 0; +} + +int hinic3_add_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id) +{ + return hinic3_config_vlan(hwdev, MGMT_MSG_CMD_OP_ADD, vlan_id, func_id); +} + +int hinic3_del_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id) +{ + return hinic3_config_vlan(hwdev, MGMT_MSG_CMD_OP_DEL, vlan_id, func_id); +} + int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable) { struct mag_cmd_set_port_enable en_state =3D {}; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index a17cd56bce71..84831c87507b 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -83,5 +83,7 @@ int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bo= ol enable); int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_u= p); int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id, bool enable); +int hinic3_add_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id); +int hinic3_del_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id); =20 #endif diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index a8e92e070d9e..6e48c29566e1 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -4,12 +4,17 @@ #ifndef _HINIC3_NIC_DEV_H_ #define _HINIC3_NIC_DEV_H_ =20 +#include #include =20 #include "hinic3_hw_cfg.h" #include "hinic3_hwdev.h" #include "hinic3_mgmt_interface.h" =20 +#define HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev) (sizeof(*(nic_dev)->vlan_bi= tmap)) +#define HINIC3_VLAN_BITMAP_SIZE(nic_dev) \ + (VLAN_N_VID / HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev)) + enum hinic3_flags { HINIC3_RSS_ENABLE, }; @@ -71,6 +76,7 @@ struct hinic3_nic_dev { u16 max_qps; u16 rx_buf_len; u32 lro_replenish_thld; + unsigned long *vlan_bitmap; unsigned long flags; struct hinic3_nic_service_cap nic_svc_cap; =20 --=20 2.43.0 From nobody Tue Dec 2 02:19:59 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 From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout11.his.huawei.com (canpmsgout11.his.huawei.com [113.46.200.226]) (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 03C9335B149; Wed, 19 Nov 2025 12:44:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.226 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556259; cv=none; b=BLE9fHTxBKEO0z1k2uq6jrKxLSue3yj8jiIgtgkLfNzZ2CL3MdmgaiVMWG/0zsOMa2wGWJTreg9cHylmmL0YXvDtLdJggwWNTJYzeOyXTFi9+g/QsnLcVvOStwnlb4gK1nxsB63Mr/0+ncHpUo1VqFte5dAl9BQfcYUh5rzg/iw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556259; c=relaxed/simple; bh=Sl+NpXD58EkYZts5alqPffkNzKbV13aimlfGai8Ib50=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=N9F0LNiRd19bewwLImxtte5WGriylZxaW+N24BEyxvom2RYl0bAWkNi9cAYvk83sdCIrSKTMMgcDcRSNS0Xe8O2Ax9E6tc6KkgqrM57RGOGshdcgUR0GR/+nT07Bp2Z1KMsgvH3nKGXk0uBV8chHaguSkdsEufgF0HRVT1Y+y8Q= 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=ToD63eq1; arc=none smtp.client-ip=113.46.200.226 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="ToD63eq1" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=uMle+dS4ErJd5IH2e8fI9/iqDThlkGzfezQTBzMK1Ds=; b=ToD63eq1Q8Gvlz8VqTFHHLSTQ2RQM899Nh4N1+84L4QKJJvbYEkeEyHLtyplBDMMP43AR6pyj v7uJ2t3oYe/21RmJVzMU/5qFYMjzEeBoCV784w07VBXskrvimvigCdI9XXwE+1JoQg5vn8E7pq1 ifFJ4BJKdj6DsLtIO8ncvPE= Received: from mail.maildlp.com (unknown [172.19.163.44]) by canpmsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4dBLjJ6WFgzKm4D; Wed, 19 Nov 2025 20:42:28 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 598D0140109; Wed, 19 Nov 2025 20:44:13 +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:11 +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 7/9] hinic3: Add mac filter ops Date: Wed, 19 Nov 2025 20:43:40 +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" Add ops to support unicast and multicast to filter mac address in packets sending and receiving. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- drivers/net/ethernet/huawei/hinic3/Makefile | 1 + .../ethernet/huawei/hinic3/hinic3_filter.c | 416 ++++++++++++++++++ .../net/ethernet/huawei/hinic3/hinic3_main.c | 6 + .../huawei/hinic3/hinic3_mgmt_interface.h | 17 + .../huawei/hinic3/hinic3_netdev_ops.c | 15 + .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 24 + .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 1 + .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 33 ++ 8 files changed, 513 insertions(+) diff --git a/drivers/net/ethernet/huawei/hinic3/Makefile b/drivers/net/ethe= rnet/huawei/hinic3/Makefile index c3efa45a6a42..26c05ecf31c9 100644 --- a/drivers/net/ethernet/huawei/hinic3/Makefile +++ b/drivers/net/ethernet/huawei/hinic3/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_HINIC3) +=3D hinic3.o hinic3-objs :=3D hinic3_cmdq.o \ hinic3_common.o \ hinic3_eqs.o \ + hinic3_filter.o \ hinic3_hw_cfg.o \ hinic3_hw_comm.o \ hinic3_hwdev.o \ diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_filter.c b/drivers/n= et/ethernet/huawei/hinic3/hinic3_filter.c new file mode 100644 index 000000000000..81e3f8368429 --- /dev/null +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_filter.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hinic3_hwif.h" +#include "hinic3_nic_dev.h" +#include "hinic3_nic_cfg.h" + +static int hinic3_filter_addr_sync(struct net_device *netdev, u8 *addr) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + + return hinic3_set_mac(nic_dev->hwdev, addr, 0, + hinic3_global_func_id(nic_dev->hwdev)); +} + +static int hinic3_filter_addr_unsync(struct net_device *netdev, u8 *addr) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + + /* The addr is in use */ + if (ether_addr_equal(addr, netdev->dev_addr)) + return 0; + + return hinic3_del_mac(nic_dev->hwdev, addr, 0, + hinic3_global_func_id(nic_dev->hwdev)); +} + +void hinic3_clean_mac_list_filter(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_mac_filter *ftmp; + struct hinic3_mac_filter *f; + + list_for_each_entry_safe(f, ftmp, &nic_dev->uc_filter_list, list) { + if (f->state =3D=3D HINIC3_MAC_HW_SYNCED) + hinic3_filter_addr_unsync(netdev, f->addr); + list_del(&f->list); + kfree(f); + } + + list_for_each_entry_safe(f, ftmp, &nic_dev->mc_filter_list, list) { + if (f->state =3D=3D HINIC3_MAC_HW_SYNCED) + hinic3_filter_addr_unsync(netdev, f->addr); + list_del(&f->list); + kfree(f); + } +} + +static struct hinic3_mac_filter * +hinic3_find_mac(const struct list_head *filter_list, u8 *addr) +{ + struct hinic3_mac_filter *f; + + list_for_each_entry(f, filter_list, list) { + if (ether_addr_equal(addr, f->addr)) + return f; + } + return NULL; +} + +static void hinic3_add_filter(struct net_device *netdev, + struct list_head *mac_filter_list, + u8 *addr) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct hinic3_mac_filter *f; + + f =3D kzalloc(sizeof(*f), GFP_ATOMIC); + if (!f) + return; + + ether_addr_copy(f->addr, addr); + + INIT_LIST_HEAD(&f->list); + list_add_tail(&f->list, mac_filter_list); + + f->state =3D HINIC3_MAC_WAIT_HW_SYNC; + set_bit(HINIC3_MAC_FILTER_CHANGED, &nic_dev->flags); +} + +static void hinic3_del_filter(struct net_device *netdev, + struct hinic3_mac_filter *f) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + + set_bit(HINIC3_MAC_FILTER_CHANGED, &nic_dev->flags); + + if (f->state =3D=3D HINIC3_MAC_WAIT_HW_SYNC) { + /* have not added to hw, delete it directly */ + list_del(&f->list); + kfree(f); + return; + } + + f->state =3D HINIC3_MAC_WAIT_HW_UNSYNC; +} + +static struct hinic3_mac_filter * +hinic3_mac_filter_entry_clone(const struct hinic3_mac_filter *src) +{ + struct hinic3_mac_filter *f; + + f =3D kzalloc(sizeof(*f), GFP_ATOMIC); + if (!f) + return NULL; + + *f =3D *src; + INIT_LIST_HEAD(&f->list); + + return f; +} + +static void hinic3_undo_del_filter_entries(struct list_head *filter_list, + const struct list_head *from) +{ + struct hinic3_mac_filter *ftmp; + struct hinic3_mac_filter *f; + + list_for_each_entry_safe(f, ftmp, from, list) { + if (hinic3_find_mac(filter_list, f->addr)) + continue; + + if (f->state =3D=3D HINIC3_MAC_HW_SYNCED) + f->state =3D HINIC3_MAC_WAIT_HW_UNSYNC; + + list_move_tail(&f->list, filter_list); + } +} + +static void hinic3_undo_add_filter_entries(struct list_head *filter_list, + const struct list_head *from) +{ + struct hinic3_mac_filter *ftmp; + struct hinic3_mac_filter *tmp; + struct hinic3_mac_filter *f; + + list_for_each_entry_safe(f, ftmp, from, list) { + tmp =3D hinic3_find_mac(filter_list, f->addr); + if (tmp && tmp->state =3D=3D HINIC3_MAC_HW_SYNCING) + tmp->state =3D HINIC3_MAC_WAIT_HW_SYNC; + } +} + +static void hinic3_cleanup_filter_list(const struct list_head *head) +{ + struct hinic3_mac_filter *ftmp; + struct hinic3_mac_filter *f; + + list_for_each_entry_safe(f, ftmp, head, list) { + list_del(&f->list); + kfree(f); + } +} + +static int hinic3_mac_filter_sync_hw(struct net_device *netdev, + struct list_head *del_list, + struct list_head *add_list, + int *add_count) +{ + struct hinic3_mac_filter *ftmp; + struct hinic3_mac_filter *f; + int err; + + if (!list_empty(del_list)) { + list_for_each_entry_safe(f, ftmp, del_list, list) { + /* ignore errors when deleting mac */ + hinic3_filter_addr_unsync(netdev, f->addr); + list_del(&f->list); + kfree(f); + } + } + + if (!list_empty(add_list)) { + list_for_each_entry_safe(f, ftmp, add_list, list) { + if (f->state !=3D HINIC3_MAC_HW_SYNCING) + continue; + + err =3D hinic3_filter_addr_sync(netdev, f->addr); + if (err) { + netdev_err(netdev, "Failed to add mac\n"); + return err; + } + + f->state =3D HINIC3_MAC_HW_SYNCED; + (*add_count)++; + } + } + + return 0; +} + +static int hinic3_mac_filter_sync(struct net_device *netdev, + struct list_head *mac_filter_list, bool uc) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + struct list_head tmp_del_list, tmp_add_list; + struct hinic3_mac_filter *fclone; + struct hinic3_mac_filter *ftmp; + struct hinic3_mac_filter *f; + int err =3D 0, add_count =3D 0; + + INIT_LIST_HEAD(&tmp_del_list); + INIT_LIST_HEAD(&tmp_add_list); + + list_for_each_entry_safe(f, ftmp, mac_filter_list, list) { + if (f->state !=3D HINIC3_MAC_WAIT_HW_UNSYNC) + continue; + + f->state =3D HINIC3_MAC_HW_UNSYNCED; + list_move_tail(&f->list, &tmp_del_list); + } + + list_for_each_entry_safe(f, ftmp, mac_filter_list, list) { + if (f->state !=3D HINIC3_MAC_WAIT_HW_SYNC) + continue; + + fclone =3D hinic3_mac_filter_entry_clone(f); + if (!fclone) { + hinic3_undo_del_filter_entries(mac_filter_list, + &tmp_del_list); + hinic3_undo_add_filter_entries(mac_filter_list, + &tmp_add_list); + + netdev_err(netdev, + "Failed to clone mac_filter_entry\n"); + err =3D -ENOMEM; + goto cleanup_tmp_filter_list; + } + + f->state =3D HINIC3_MAC_HW_SYNCING; + list_add_tail(&fclone->list, &tmp_add_list); + } + + err =3D hinic3_mac_filter_sync_hw(netdev, &tmp_del_list, + &tmp_add_list, &add_count); + if (err) { + /* there were errors, delete all mac in hw */ + hinic3_undo_add_filter_entries(mac_filter_list, &tmp_add_list); + /* VF does not support promiscuous mode, + * don't delete any other uc mac. + */ + if (!HINIC3_IS_VF(nic_dev->hwdev) || !uc) { + list_for_each_entry_safe(f, ftmp, mac_filter_list, + list) { + if (f->state !=3D HINIC3_MAC_HW_SYNCED) + continue; + + fclone =3D hinic3_mac_filter_entry_clone(f); + if (!fclone) + break; + + f->state =3D HINIC3_MAC_HW_SYNCING; + list_add_tail(&fclone->list, &tmp_del_list); + } + } + + hinic3_mac_filter_sync_hw(netdev, &tmp_del_list, + &tmp_add_list, NULL); + } + +cleanup_tmp_filter_list: + hinic3_cleanup_filter_list(&tmp_del_list); + hinic3_cleanup_filter_list(&tmp_add_list); + + return err ? err : add_count; +} + +static void hinic3_mac_filter_sync_all(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + int add_count; + + if (test_bit(HINIC3_MAC_FILTER_CHANGED, &nic_dev->flags)) { + clear_bit(HINIC3_MAC_FILTER_CHANGED, &nic_dev->flags); + add_count =3D hinic3_mac_filter_sync(netdev, + &nic_dev->uc_filter_list, + true); + if (add_count < 0 && + hinic3_test_support(nic_dev, HINIC3_NIC_F_PROMISC)) + set_bit(HINIC3_PROMISC_FORCE_ON, + &nic_dev->rx_mod_state); + else if (add_count) + clear_bit(HINIC3_PROMISC_FORCE_ON, + &nic_dev->rx_mod_state); + + add_count =3D hinic3_mac_filter_sync(netdev, + &nic_dev->mc_filter_list, + false); + if (add_count < 0 && + hinic3_test_support(nic_dev, HINIC3_NIC_F_ALLMULTI)) + set_bit(HINIC3_ALLMULTI_FORCE_ON, + &nic_dev->rx_mod_state); + else if (add_count) + clear_bit(HINIC3_ALLMULTI_FORCE_ON, + &nic_dev->rx_mod_state); + } +} + +#define HINIC3_DEFAULT_RX_MODE \ + (L2NIC_RX_MODE_UC | L2NIC_RX_MODE_MC | L2NIC_RX_MODE_BC) + +static void hinic3_update_mac_filter(struct net_device *netdev, + const struct netdev_hw_addr_list *src_list, + struct list_head *filter_list) +{ + struct hinic3_mac_filter *filter; + struct hinic3_mac_filter *ftmp; + struct hinic3_mac_filter *f; + struct netdev_hw_addr *ha; + + /* add addr if not already in the filter list */ + netif_addr_lock_bh(netdev); + netdev_hw_addr_list_for_each(ha, src_list) { + filter =3D hinic3_find_mac(filter_list, ha->addr); + if (!filter) + hinic3_add_filter(netdev, filter_list, ha->addr); + else if (filter->state =3D=3D HINIC3_MAC_WAIT_HW_UNSYNC) + filter->state =3D HINIC3_MAC_HW_SYNCED; + } + netif_addr_unlock_bh(netdev); + + /* delete addr if not in netdev list */ + list_for_each_entry_safe(f, ftmp, filter_list, list) { + bool found =3D false; + + netif_addr_lock_bh(netdev); + netdev_hw_addr_list_for_each(ha, src_list) + if (ether_addr_equal(ha->addr, f->addr)) { + found =3D true; + break; + } + netif_addr_unlock_bh(netdev); + + if (found) + continue; + + hinic3_del_filter(netdev, f); + } +} + +static void hinic3_sync_rx_mode_to_hw(struct net_device *netdev, int promi= sc_en, + int allmulti_en) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + u32 rx_mode =3D HINIC3_DEFAULT_RX_MODE; + int err; + + rx_mode |=3D (promisc_en ? L2NIC_RX_MODE_PROMISC : 0); + rx_mode |=3D (allmulti_en ? L2NIC_RX_MODE_MC_ALL : 0); + + if (promisc_en !=3D test_bit(HINIC3_HW_PROMISC_ON, + &nic_dev->rx_mod_state)) + netdev_dbg(netdev, "%s promisc mode\n", + promisc_en ? "Enter" : "Left"); + if (allmulti_en !=3D + test_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state)) + netdev_dbg(netdev, "%s all_multi mode\n", + allmulti_en ? "Enter" : "Left"); + + err =3D hinic3_set_rx_mode(nic_dev->hwdev, rx_mode); + if (err) { + netdev_err(netdev, "Failed to set rx_mode\n"); + return; + } + + promisc_en ? set_bit(HINIC3_HW_PROMISC_ON, &nic_dev->rx_mod_state) : + clear_bit(HINIC3_HW_PROMISC_ON, &nic_dev->rx_mod_state); + + allmulti_en ? set_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state) : + clear_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state); +} + +void hinic3_set_rx_mode_work(struct work_struct *work) +{ + int promisc_en =3D 0, allmulti_en =3D 0; + struct hinic3_nic_dev *nic_dev; + struct net_device *netdev; + + nic_dev =3D container_of(work, struct hinic3_nic_dev, rx_mode_work); + netdev =3D nic_dev->netdev; + + if (test_and_clear_bit(HINIC3_UPDATE_MAC_FILTER, &nic_dev->flags)) { + hinic3_update_mac_filter(netdev, &netdev->uc, + &nic_dev->uc_filter_list); + hinic3_update_mac_filter(netdev, &netdev->mc, + &nic_dev->mc_filter_list); + } + + hinic3_mac_filter_sync_all(netdev); + + if (hinic3_test_support(nic_dev, HINIC3_NIC_F_PROMISC)) + promisc_en =3D !!(netdev->flags & IFF_PROMISC) || + test_bit(HINIC3_PROMISC_FORCE_ON, + &nic_dev->rx_mod_state); + + if (hinic3_test_support(nic_dev, HINIC3_NIC_F_ALLMULTI)) + allmulti_en =3D !!(netdev->flags & IFF_ALLMULTI) || + test_bit(HINIC3_ALLMULTI_FORCE_ON, + &nic_dev->rx_mod_state); + + if (promisc_en !=3D test_bit(HINIC3_HW_PROMISC_ON, + &nic_dev->rx_mod_state) || + allmulti_en !=3D test_bit(HINIC3_HW_ALLMULTI_ON, + &nic_dev->rx_mod_state)) + hinic3_sync_rx_mode_to_hw(netdev, promisc_en, allmulti_en); +} diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index d085ddddbbd7..1308653819ef 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -164,6 +164,10 @@ static int hinic3_init_nic_dev(struct net_device *netd= ev, INIT_DELAYED_WORK(&nic_dev->periodic_work, hinic3_periodic_work_handler); =20 + INIT_LIST_HEAD(&nic_dev->uc_filter_list); + INIT_LIST_HEAD(&nic_dev->mc_filter_list); + INIT_WORK(&nic_dev->rx_mode_work, hinic3_set_rx_mode_work); + return 0; } =20 @@ -230,6 +234,7 @@ static void hinic3_sw_uninit(struct net_device *netdev) struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); =20 hinic3_free_txrxqs(netdev); + hinic3_clean_mac_list_filter(netdev); hinic3_del_mac(nic_dev->hwdev, netdev->dev_addr, 0, hinic3_global_func_id(nic_dev->hwdev)); hinic3_clear_rss_config(netdev); @@ -449,6 +454,7 @@ static void hinic3_nic_remove(struct auxiliary_device *= adev) unregister_netdev(netdev); =20 disable_delayed_work_sync(&nic_dev->periodic_work); + cancel_work_sync(&nic_dev->rx_mode_work); hinic3_free_nic_dev(nic_dev); =20 hinic3_update_nic_feature(nic_dev, 0); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/d= rivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index 60f47152c01d..c0c87a8c2198 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -115,6 +115,22 @@ struct l2nic_cmd_set_vport_state { u8 rsvd2[3]; }; =20 +/* * + * Definition of the NIC receiving mode + */ +#define L2NIC_RX_MODE_UC 0x01 +#define L2NIC_RX_MODE_MC 0x02 +#define L2NIC_RX_MODE_BC 0x04 +#define L2NIC_RX_MODE_MC_ALL 0x08 +#define L2NIC_RX_MODE_PROMISC 0x10 + +struct l2nic_rx_mode_config { + struct mgmt_msg_head msg_head; + u16 func_id; + u16 rsvd1; + u32 rx_mode; +}; + struct l2nic_cmd_set_dcb_state { struct mgmt_msg_head head; u16 func_id; @@ -205,6 +221,7 @@ enum l2nic_cmd { /* FUNC CFG */ L2NIC_CMD_SET_FUNC_TBL =3D 5, L2NIC_CMD_SET_VPORT_ENABLE =3D 6, + L2NIC_CMD_SET_RX_MODE =3D 7, L2NIC_CMD_SET_SQ_CI_ATTR =3D 8, L2NIC_CMD_CLEAR_QP_RESOURCE =3D 11, L2NIC_CMD_CFG_RX_LRO =3D 13, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index 1e298be6e0d1..52bc30cc8a0b 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -810,6 +810,20 @@ static void hinic3_get_stats64(struct net_device *netd= ev, stats->rx_dropped =3D dropped; } =20 +static void hinic3_nic_set_rx_mode(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + + if (netdev_uc_count(netdev) !=3D nic_dev->netdev_uc_cnt || + netdev_mc_count(netdev) !=3D nic_dev->netdev_mc_cnt) { + set_bit(HINIC3_UPDATE_MAC_FILTER, &nic_dev->flags); + nic_dev->netdev_uc_cnt =3D netdev_uc_count(netdev); + nic_dev->netdev_mc_cnt =3D netdev_mc_count(netdev); + } + + queue_work(nic_dev->workq, &nic_dev->rx_mode_work); +} + static const struct net_device_ops hinic3_netdev_ops =3D { .ndo_open =3D hinic3_open, .ndo_stop =3D hinic3_close, @@ -822,6 +836,7 @@ static const struct net_device_ops hinic3_netdev_ops = =3D { .ndo_vlan_rx_kill_vid =3D hinic3_vlan_rx_kill_vid, .ndo_tx_timeout =3D hinic3_tx_timeout, .ndo_get_stats64 =3D hinic3_get_stats64, + .ndo_set_rx_mode =3D hinic3_nic_set_rx_mode, .ndo_start_xmit =3D hinic3_xmit_frame, }; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index 4a5356cf51a5..da2e45c65d4b 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -499,6 +499,30 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwde= v) return pkt_drop.msg_head.status; } =20 +int hinic3_set_rx_mode(struct hinic3_hwdev *hwdev, u32 rx_mode) +{ + struct l2nic_rx_mode_config rx_mode_cfg =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + rx_mode_cfg.func_id =3D hinic3_global_func_id(hwdev); + rx_mode_cfg.rx_mode =3D rx_mode; + + mgmt_msg_params_init_default(&msg_params, &rx_mode_cfg, + sizeof(rx_mode_cfg)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, + L2NIC_CMD_SET_RX_MODE, &msg_params); + + if (err || rx_mode_cfg.msg_head.status) { + dev_err(hwdev->dev, "Failed to set rx mode, err: %d, status: 0x%x\n", + err, rx_mode_cfg.msg_head.status); + return -EFAULT; + } + + return 0; +} + static int hinic3_config_vlan(struct hinic3_hwdev *hwdev, u8 opcode, u16 vlan_id, u16 func_id) { diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index 84831c87507b..f83913e74cb5 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -77,6 +77,7 @@ int hinic3_set_ci_table(struct hinic3_hwdev *hwdev, struct hinic3_sq_attr *attr); int hinic3_flush_qps_res(struct hinic3_hwdev *hwdev); int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev); +int hinic3_set_rx_mode(struct hinic3_hwdev *hwdev, u32 rx_mode); =20 int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state= ); int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 9ca7794e94a6..9bd46541b3e3 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -16,13 +16,36 @@ (VLAN_N_VID / HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev)) =20 enum hinic3_flags { + HINIC3_MAC_FILTER_CHANGED, HINIC3_RSS_ENABLE, + HINIC3_UPDATE_MAC_FILTER, }; =20 enum hinic3_event_work_flags { HINIC3_EVENT_WORK_TX_TIMEOUT, }; =20 +enum hinic3_rx_mode_state { + HINIC3_HW_PROMISC_ON, + HINIC3_HW_ALLMULTI_ON, + HINIC3_PROMISC_FORCE_ON, + HINIC3_ALLMULTI_FORCE_ON, +}; + +enum hinic3_mac_filter_state { + HINIC3_MAC_WAIT_HW_SYNC, + HINIC3_MAC_HW_SYNCING, + HINIC3_MAC_HW_SYNCED, + HINIC3_MAC_WAIT_HW_UNSYNC, + HINIC3_MAC_HW_UNSYNCED, +}; + +struct hinic3_mac_filter { + struct list_head list; + u8 addr[ETH_ALEN]; + unsigned long state; +}; + enum hinic3_rss_hash_type { HINIC3_RSS_HASH_ENGINE_TYPE_XOR =3D 0, HINIC3_RSS_HASH_ENGINE_TYPE_TOEP =3D 1, @@ -101,9 +124,16 @@ struct hinic3_nic_dev { =20 struct workqueue_struct *workq; struct delayed_work periodic_work; + struct work_struct rx_mode_work; /* lock for enable/disable port */ struct mutex port_state_mutex; =20 + struct list_head uc_filter_list; + struct list_head mc_filter_list; + unsigned long rx_mod_state; + int netdev_uc_cnt; + int netdev_mc_cnt; + /* flag bits defined by hinic3_event_work_flags */ unsigned long event_flag; bool link_status_up; @@ -114,4 +144,7 @@ int hinic3_set_hw_features(struct net_device *netdev); int hinic3_qps_irq_init(struct net_device *netdev); void hinic3_qps_irq_uninit(struct net_device *netdev); =20 +void hinic3_set_rx_mode_work(struct work_struct *work); +void hinic3_clean_mac_list_filter(struct net_device *netdev); + #endif --=20 2.43.0 From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout09.his.huawei.com (canpmsgout09.his.huawei.com [113.46.200.224]) (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 0C31835FF69; Wed, 19 Nov 2025 12:44:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.224 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556269; cv=none; b=B1wWcxg+fs1V8QLRFYGvaboNBiTv1UnBAurXUHVbI4y6IR7dvULZ0lumF0zJutiLcto2s3BND1qDiwROihZpUNB8p1QshqmhvUxH41B0d+f2zg72pBJBd9YVH7bDZRB4uRwhVqz3iY3o7AbQeVqM+11ixL26JZTGbzHwc+82rTc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556269; c=relaxed/simple; bh=Rnru5ouamGLdHTyWUlFahVoXs373OdFK7aMwp2vqL8c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Zv/RWZC9WS4o2+Tf0rRHJCHefyxqp7cwFp+hlXHa3mzlu1VSNa7bkswUTesIrzmGU/MtvWFvANUbQE2YO6tKl6cZIHHtKMy8QcJ2VmzVvY2jBF7vwaVBzDkUCuz2QxISAt+A1fcGY4TYwhHBMljQVsztIkgS5/RcaTy3MTUSvDU= 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=lXswAYIq; arc=none smtp.client-ip=113.46.200.224 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="lXswAYIq" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=f4H1DyMnqMWXqfDqjmax/RukEGIiAKVw3Nhx0Pp/47o=; b=lXswAYIqGP91adavjcMz/EDM1U2IgrVsicsR9DuyEy7ZIIVJXWMMasznqrJCF9Zwfg2kD6NZI nI++14Me3jjtmYi3tEkeZV6SjzwqRG0pCrGcNyf0Be2cUSuvweXOEd4HcV6GMmDG6wBs00G9p75 r4WGt+KT5LwamaMggl2pdGQ= Received: from mail.maildlp.com (unknown [172.19.88.163]) by canpmsgout09.his.huawei.com (SkyGuard) with ESMTPS id 4dBLjM36Mgz1cyQ2; Wed, 19 Nov 2025 20:42:31 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 977D118001B; Wed, 19 Nov 2025 20:44:15 +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:14 +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 8/9] hinic3: Add netdev notifier interfaces Date: Wed, 19 Nov 2025 20:43:41 +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" Add netdev notifier interfaces. As we stipulate that netdevices with a vlan depth greater than 1 should disable the offload feature, Layer 1 vlan netdevices use notifier to modify vlan_features. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../net/ethernet/huawei/hinic3/hinic3_main.c | 89 +++++++++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 1 + 2 files changed, 90 insertions(+) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 1308653819ef..463609585f46 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -32,6 +32,61 @@ #define HINIC3_RX_PENDING_LIMIT_LOW 2 #define HINIC3_RX_PENDING_LIMIT_HIGH 8 =20 +#define HINIC3_MAX_VLAN_DEPTH_OFFLOAD_SUPPORT 1 +#define HINIC3_VLAN_CLEAR_OFFLOAD \ + (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \ + NETIF_F_SCTP_CRC | NETIF_F_RXCSUM | NETIF_F_ALL_TSO) + +/* used for netdev notifier register/unregister */ +static DEFINE_MUTEX(hinic3_netdev_notifiers_mutex); +static int hinic3_netdev_notifiers_ref_cnt; + +static u16 hinic3_get_vlan_depth(struct net_device *netdev) +{ + u16 vlan_depth =3D 0; + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + while (is_vlan_dev(netdev)) { + netdev =3D vlan_dev_priv(netdev)->real_dev; + vlan_depth++; + } +#endif + return vlan_depth; +} + +static int hinic3_netdev_event(struct notifier_block *notifier, + unsigned long event, void *ptr) +{ + struct net_device *ndev =3D netdev_notifier_info_to_dev(ptr); + struct hinic3_nic_dev *nic_dev =3D netdev_priv(ndev); + u16 vlan_depth; + + if (!is_vlan_dev(ndev)) + return NOTIFY_DONE; + + netdev_hold(ndev, &nic_dev->tracker, GFP_ATOMIC); + + switch (event) { + case NETDEV_REGISTER: + vlan_depth =3D hinic3_get_vlan_depth(ndev); + if (vlan_depth =3D=3D HINIC3_MAX_VLAN_DEPTH_OFFLOAD_SUPPORT) + ndev->vlan_features &=3D (~HINIC3_VLAN_CLEAR_OFFLOAD); + + break; + + default: + break; + } + + netdev_put(ndev, &nic_dev->tracker); + + return NOTIFY_DONE; +} + +static struct notifier_block hinic3_netdev_notifier =3D { + .notifier_call =3D hinic3_netdev_event, +}; + static void init_intr_coal_param(struct net_device *netdev) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); @@ -309,6 +364,36 @@ static int hinic3_set_default_hw_feature(struct net_de= vice *netdev) return 0; } =20 +static void hinic3_register_notifier(struct net_device *netdev) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + int err; + + mutex_lock(&hinic3_netdev_notifiers_mutex); + hinic3_netdev_notifiers_ref_cnt++; + if (hinic3_netdev_notifiers_ref_cnt =3D=3D 1) { + err =3D register_netdevice_notifier(&hinic3_netdev_notifier); + if (err) { + dev_dbg(nic_dev->hwdev->dev, + "Register netdevice notifier failed, err: %d\n", + err); + hinic3_netdev_notifiers_ref_cnt--; + } + } + mutex_unlock(&hinic3_netdev_notifiers_mutex); +} + +static void hinic3_unregister_notifier(void) +{ + mutex_lock(&hinic3_netdev_notifiers_mutex); + if (hinic3_netdev_notifiers_ref_cnt =3D=3D 1) + unregister_netdevice_notifier(&hinic3_netdev_notifier); + + if (hinic3_netdev_notifiers_ref_cnt) + hinic3_netdev_notifiers_ref_cnt--; + mutex_unlock(&hinic3_netdev_notifiers_mutex); +} + static void hinic3_link_status_change(struct net_device *netdev, bool link_status_up) { @@ -412,6 +497,8 @@ static int hinic3_nic_probe(struct auxiliary_device *ad= ev, if (err) goto err_uninit_sw; =20 + hinic3_register_notifier(netdev); + queue_delayed_work(nic_dev->workq, &nic_dev->periodic_work, HZ); netif_carrier_off(netdev); =20 @@ -422,6 +509,7 @@ static int hinic3_nic_probe(struct auxiliary_device *ad= ev, return 0; =20 err_uninit_nic_feature: + hinic3_unregister_notifier(); hinic3_update_nic_feature(nic_dev, 0); hinic3_set_nic_feature_to_hw(nic_dev); =20 @@ -452,6 +540,7 @@ static void hinic3_nic_remove(struct auxiliary_device *= adev) =20 netdev =3D nic_dev->netdev; unregister_netdev(netdev); + hinic3_unregister_notifier(); =20 disable_delayed_work_sync(&nic_dev->periodic_work); cancel_work_sync(&nic_dev->rx_mode_work); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 9bd46541b3e3..899f60588d25 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -97,6 +97,7 @@ struct hinic3_intr_coal_info { struct hinic3_nic_dev { struct pci_dev *pdev; struct net_device *netdev; + netdevice_tracker tracker; struct hinic3_hwdev *hwdev; struct hinic3_nic_io *nic_io; =20 --=20 2.43.0 From nobody Tue Dec 2 02:19:59 2025 Received: from canpmsgout03.his.huawei.com (canpmsgout03.his.huawei.com [113.46.200.218]) (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 A602335F8C1; Wed, 19 Nov 2025 12:44:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.218 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556264; cv=none; b=r55K0F9wgmqfSpKuLdWEA0LKScIi8U8X1GgILzc0fDewgw9fK6+16JonsyASkyVmRSetGWoI6JyS8z5beptXKZ1mPAQoPefLgkn74akQe9DhRnn/HDIrjLZbbHAzr37J48eY1sxjQhDCCGrwmDGvnGrVIU8A5UPHVNo1ZcG/vcw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556264; c=relaxed/simple; bh=h4GHaccWqxCegFHLSWVNzQ3SeCZPuJrjnZn5eftcTXY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ei/K8y74xO+xpiPmkmTGNUbQvAjlgaqwdmdHZY3vQx72F0+QiN5oCr7Ibis+bwlBk9yml+B2wRVaCwmpk1qJrjcgeKkc9+jHwaaqiKqbTPoj0YxOIspg9uc03t1uxMF/ToComR9PyaMlCFDp2zDgFE5ZHS+F1ZKBqgaO5tgteTc= 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=gfTOKdAF; arc=none smtp.client-ip=113.46.200.218 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="gfTOKdAF" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=QLgAYi+bkoyYJz97IbUgd1HG2TEXgw9fBz1b1oCAi28=; b=gfTOKdAFrkewhPD4IzGH2GgXD5gq2GftoGAXm9dfHCHv4DRrSuQJnigtal1ZqOdhsMz7CMLdw lKOGNNryhYjQy1QFnTekkbmGtpzonCJzQiiDS2By9p/FKZFmdsrGktSgrxbxUeUf9g506q0qGHV rbiDWNwECTanFlwcQIvIpqE= Received: from mail.maildlp.com (unknown [172.19.162.254]) by canpmsgout03.his.huawei.com (SkyGuard) with ESMTPS id 4dBLjB74T5zpSwn; Wed, 19 Nov 2025 20:42:22 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 4A56A180495; Wed, 19 Nov 2025 20:44:18 +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:16 +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 9/9] hinic3: Add HW event handler Date: Wed, 19 Nov 2025 20:43:42 +0800 Message-ID: <960cf26830046e9b25fd4bc28636880efe89b1a7.1763555878.git.zhuyikai1@h-partners.com> 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" Add HINIC3_INIT_UP flags to trace netdev open status. Add port module event handler. Add link status event type(FAULT, PCIE link down, heart lost, mgmt watchdog). Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 9 ++++ .../net/ethernet/huawei/hinic3/hinic3_irq.c | 3 +- .../net/ethernet/huawei/hinic3/hinic3_main.c | 50 +++++++++++++++++++ .../huawei/hinic3/hinic3_netdev_ops.c | 12 +++++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 18 +++++++ .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 1 + 6 files changed, 92 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.h index 58bc561f95b3..9686c2600b46 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h @@ -17,6 +17,15 @@ enum hinic3_event_service_type { HINIC3_EVENT_SRV_NIC =3D 1 }; =20 +enum hinic3_comm_event_type { + HINIC3_COMM_EVENT_PCIE_LINK_DOWN =3D 0, + HINIC3_COMM_EVENT_HEART_LOST =3D 1, + HINIC3_COMM_EVENT_FAULT =3D 2, + HINIC3_COMM_EVENT_SRIOV_STATE_CHANGE =3D 3, + HINIC3_COMM_EVENT_CARD_REMOVE =3D 4, + HINIC3_COMM_EVENT_MGMT_WATCHDOG =3D 5, +}; + enum hinic3_fault_err_level { HINIC3_FAULT_LEVEL_SERIOUS_FLR =3D 3, }; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/= ethernet/huawei/hinic3/hinic3_irq.c index 604e09812977..8a47320ffd3f 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c @@ -19,7 +19,8 @@ static void hinic3_net_dim(struct hinic3_nic_dev *nic_dev, struct hinic3_rxq *rxq =3D irq_cfg->rxq; struct dim_sample sample =3D {}; =20 - if (!nic_dev->adaptive_rx_coal) + if (!test_bit(HINIC3_INTF_UP, &nic_dev->flags) || + !nic_dev->adaptive_rx_coal) return; =20 dim_update_sample(irq_cfg->total_events, rxq->rxq_stats.packets, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 463609585f46..c556c853859d 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -416,6 +416,44 @@ static void hinic3_link_status_change(struct net_devic= e *netdev, } } =20 +static void hinic3_port_module_event_handler(struct net_device *netdev, + struct hinic3_event_info *event) +{ + const char *g_hinic3_module_link_err[LINK_ERR_NUM] =3D { + "Unrecognized module" + }; + struct hinic3_port_module_event *module_event; + enum port_module_event_type type; + enum link_err_type err_type; + + module_event =3D (struct hinic3_port_module_event *)event->event_data; + type =3D module_event->type; + err_type =3D module_event->err_type; + + switch (type) { + case HINIC3_PORT_MODULE_CABLE_PLUGGED: + case HINIC3_PORT_MODULE_CABLE_UNPLUGGED: + netdev_info(netdev, "Port module event: Cable %s\n", + type =3D=3D HINIC3_PORT_MODULE_CABLE_PLUGGED ? + "plugged" : "unplugged"); + break; + case HINIC3_PORT_MODULE_LINK_ERR: + if (err_type >=3D LINK_ERR_NUM) { + netdev_info(netdev, "Link failed, Unknown error type: 0x%x\n", + err_type); + } else { + netdev_info(netdev, + "Link failed, error type: 0x%x: %s\n", + err_type, + g_hinic3_module_link_err[err_type]); + } + break; + default: + netdev_err(netdev, "Unknown port module type %d\n", type); + break; + } +} + static void hinic3_nic_event(struct auxiliary_device *adev, struct hinic3_event_info *event) { @@ -429,8 +467,20 @@ static void hinic3_nic_event(struct auxiliary_device *= adev, HINIC3_NIC_EVENT_LINK_UP): hinic3_link_status_change(netdev, true); break; + case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_NIC, + HINIC3_NIC_EVENT_PORT_MODULE_EVENT): + hinic3_port_module_event_handler(netdev, event); + break; case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_NIC, HINIC3_NIC_EVENT_LINK_DOWN): + case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_COMM, + HINIC3_COMM_EVENT_FAULT): + case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_COMM, + HINIC3_COMM_EVENT_PCIE_LINK_DOWN): + case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_COMM, + HINIC3_COMM_EVENT_HEART_LOST): + case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_COMM, + HINIC3_COMM_EVENT_MGMT_WATCHDOG): hinic3_link_status_change(netdev, false); break; default: diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index 52bc30cc8a0b..439f1cecc2b4 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -430,6 +430,11 @@ static int hinic3_open(struct net_device *netdev) struct hinic3_dyna_qp_params qp_params; int err; =20 + if (test_bit(HINIC3_INTF_UP, &nic_dev->flags)) { + netdev_dbg(netdev, "Netdev already open, do nothing\n"); + return 0; + } + err =3D hinic3_init_nicio_res(nic_dev); if (err) { netdev_err(netdev, "Failed to init nicio resources\n"); @@ -457,6 +462,8 @@ static int hinic3_open(struct net_device *netdev) if (err) goto err_close_channel; =20 + set_bit(HINIC3_INTF_UP, &nic_dev->flags); + return 0; =20 err_close_channel: @@ -477,6 +484,11 @@ static int hinic3_close(struct net_device *netdev) struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); struct hinic3_dyna_qp_params qp_params; =20 + if (!test_and_clear_bit(HINIC3_INTF_UP, &nic_dev->flags)) { + netdev_dbg(netdev, "Netdev already close, do nothing\n"); + return 0; + } + hinic3_vport_down(netdev); hinic3_close_channel(netdev); hinic3_uninit_qps(nic_dev, &qp_params); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index f83913e74cb5..c32eaa886e17 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -22,6 +22,7 @@ struct hinic3_nic_dev; enum hinic3_nic_event_type { HINIC3_NIC_EVENT_LINK_DOWN =3D 0, HINIC3_NIC_EVENT_LINK_UP =3D 1, + HINIC3_NIC_EVENT_PORT_MODULE_EVENT =3D 2, }; =20 struct hinic3_sq_attr { @@ -51,6 +52,23 @@ struct mag_cmd_set_port_enable { u8 rsvd1[3]; }; =20 +enum link_err_type { + LINK_ERR_MODULE_UNRECOGENIZED, + LINK_ERR_NUM, +}; + +enum port_module_event_type { + HINIC3_PORT_MODULE_CABLE_PLUGGED, + HINIC3_PORT_MODULE_CABLE_UNPLUGGED, + HINIC3_PORT_MODULE_LINK_ERR, + HINIC3_PORT_MODULE_MAX_EVENT, +}; + +struct hinic3_port_module_event { + enum port_module_event_type type; + enum link_err_type err_type; +}; + int hinic3_get_nic_feature_from_hw(struct hinic3_nic_dev *nic_dev); int hinic3_set_nic_feature_to_hw(struct hinic3_nic_dev *nic_dev); bool hinic3_test_support(struct hinic3_nic_dev *nic_dev, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 899f60588d25..ff0ce5804d53 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -16,6 +16,7 @@ (VLAN_N_VID / HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev)) =20 enum hinic3_flags { + HINIC3_INTF_UP, HINIC3_MAC_FILTER_CHANGED, HINIC3_RSS_ENABLE, HINIC3_UPDATE_MAC_FILTER, --=20 2.43.0