* [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization
@ 2025-10-15 7:15 Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 1/9] hinic3: Add PF framework Fan Gong
` (8 more replies)
0 siblings, 9 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
This is [1/3] part of hinic3 Ethernet driver second submission.
With this patch hinic3 becomes a complete Ethernet driver with
pf and vf.
The driver parts contained in this patch:
Add support for PF framework based on the VF code.
Add PF management interfaces to communicate with HW.
Add ops to configure NIC features.
Support mac filter to unicast and multicast.
Add netdev notifier.
Fix code style of merged codes according to previous comments.
Changes:
PATCH 03 V01:
Fan Gong (9):
hinic3: Add PF framework
hinic3: Add PF management interfaces
hinic3: Add NIC configuration ops
hinic3: Add mac filter ops
hinic3: Add netdev register interfaces
hinic3: Fix netif_queue_set_napi queue_index parameter passing error
hinic3: Fix code Style(remove empty lines between error handling)
hinic3: Remove redundant defensive code
hinic3: Use array_size instead of multiplying
drivers/net/ethernet/huawei/hinic3/Makefile | 1 +
.../net/ethernet/huawei/hinic3/hinic3_cmdq.c | 3 -
.../net/ethernet/huawei/hinic3/hinic3_csr.h | 6 +
.../net/ethernet/huawei/hinic3/hinic3_eqs.c | 1 -
.../ethernet/huawei/hinic3/hinic3_filter.c | 420 ++++++++++++++++++
.../ethernet/huawei/hinic3/hinic3_hw_comm.c | 105 +++++
.../ethernet/huawei/hinic3/hinic3_hw_comm.h | 6 +
.../ethernet/huawei/hinic3/hinic3_hw_intf.h | 24 +
.../net/ethernet/huawei/hinic3/hinic3_hwdev.c | 93 +++-
.../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 55 ++-
.../net/ethernet/huawei/hinic3/hinic3_hwif.c | 89 +++-
.../net/ethernet/huawei/hinic3/hinic3_hwif.h | 23 +
.../net/ethernet/huawei/hinic3/hinic3_irq.c | 157 ++++++-
.../net/ethernet/huawei/hinic3/hinic3_lld.c | 70 ++-
.../net/ethernet/huawei/hinic3/hinic3_main.c | 266 ++++++++++-
.../net/ethernet/huawei/hinic3/hinic3_mbox.c | 57 ++-
.../net/ethernet/huawei/hinic3/hinic3_mbox.h | 2 +
.../net/ethernet/huawei/hinic3/hinic3_mgmt.c | 308 ++++++++++++-
.../net/ethernet/huawei/hinic3/hinic3_mgmt.h | 53 +++
.../huawei/hinic3/hinic3_mgmt_interface.h | 69 +++
.../huawei/hinic3/hinic3_netdev_ops.c | 380 ++++++++++++++++
.../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 286 +++++++++++-
.../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 47 ++
.../ethernet/huawei/hinic3/hinic3_nic_dev.h | 82 +++-
.../net/ethernet/huawei/hinic3/hinic3_rx.h | 20 +
.../net/ethernet/huawei/hinic3/hinic3_tx.c | 7 -
.../net/ethernet/huawei/hinic3/hinic3_tx.h | 18 +
27 files changed, 2566 insertions(+), 82 deletions(-)
create mode 100644 drivers/net/ethernet/huawei/hinic3/hinic3_filter.c
base-commit: 16a2206354d169bfd13552ad577e07ce66e439ab
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH net-next v01 1/9] hinic3: Add PF framework
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 10:29 ` Pavan Chebbi
2025-10-27 10:00 ` Simon Horman
2025-10-15 7:15 ` [PATCH net-next v01 2/9] hinic3: Add PF management interfaces Fan Gong
` (7 subsequent siblings)
8 siblings, 2 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
Add support for PF framework based on the VF code.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
.../net/ethernet/huawei/hinic3/hinic3_csr.h | 6 ++
.../ethernet/huawei/hinic3/hinic3_hw_comm.c | 51 +++++++++++
.../ethernet/huawei/hinic3/hinic3_hw_comm.h | 4 +
.../ethernet/huawei/hinic3/hinic3_hw_intf.h | 22 +++++
.../net/ethernet/huawei/hinic3/hinic3_hwdev.c | 40 ++++++++-
.../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 2 +
.../net/ethernet/huawei/hinic3/hinic3_hwif.c | 89 ++++++++++++++++++-
.../net/ethernet/huawei/hinic3/hinic3_hwif.h | 23 +++++
.../net/ethernet/huawei/hinic3/hinic3_lld.c | 65 +++++++++++++-
.../net/ethernet/huawei/hinic3/hinic3_main.c | 30 +++++--
.../net/ethernet/huawei/hinic3/hinic3_mbox.c | 42 +++++++--
.../huawei/hinic3/hinic3_mgmt_interface.h | 1 +
.../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 57 +++++++++++-
.../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 3 +
14 files changed, 412 insertions(+), 23 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_
#define HINIC3_CFG_REGS_FLAG 0x40000000
+#define HINIC3_MGMT_REGS_FLAG 0xC0000000
#define HINIC3_REGS_FLAG_MASK 0x3FFFFFFF
#define HINIC3_VF_CFG_REG_OFFSET 0x2000
@@ -24,6 +25,11 @@
#define HINIC3_FUNC_CSR_MAILBOX_RESULT_H_OFF (HINIC3_CFG_REGS_FLAG + 0x0108)
#define HINIC3_FUNC_CSR_MAILBOX_RESULT_L_OFF (HINIC3_CFG_REGS_FLAG + 0x010C)
+#define HINIC3_HOST_CSR_BASE_ADDR (HINIC3_MGMT_REGS_FLAG + 0x6000)
+#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 + 0x380)
#define HINIC3_CSR_DMA_ATTR_INDIR_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x390)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c
index 89638813df40..7a4011621dcc 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c
@@ -314,6 +314,9 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
ret = -EFAULT;
}
+ if (HINIC3_FUNC_TYPE(hwdev) != HINIC3_FUNC_TYPE_VF)
+ hinic3_set_pf_status(hwif, HINIC3_PF_STATUS_FLR_START_FLAG);
+
clr_res.func_id = hwif->attr.func_global_idx;
msg_params.buf_in = &clr_res;
msg_params.in_size = sizeof(clr_res);
@@ -337,6 +340,54 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
return ret;
}
+int hinic3_set_bdf_ctxt(struct hinic3_hwdev *hwdev, u8 bus, u8 device, u8 function)
+{
+ struct comm_cmd_bdf_info bdf_info = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ bdf_info.function_idx = hinic3_global_func_id(hwdev);
+ bdf_info.bus = bus;
+ bdf_info.device = device;
+ bdf_info.function = function;
+
+ mgmt_msg_params_init_default(&msg_params, &bdf_info, sizeof(bdf_info));
+
+ err = 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 -EIO;
+ }
+
+ return 0;
+}
+
+int hinic3_sync_time(struct hinic3_hwdev *hwdev, u64 time)
+{
+ struct comm_cmd_sync_time time_info = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ time_info.mstime = time;
+
+ mgmt_msg_params_init_default(&msg_params, &time_info,
+ sizeof(time_info));
+
+ err = 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 -EIO;
+ }
+
+ return 0;
+}
+
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..87446522e926 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, u8 bus, u8 device,
+ u8 function);
+int hinic3_sync_time(struct hinic3_hwdev *hwdev, u64 time);
+
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 = 23,
COMM_CMD_SET_CEQ_CTRL_REG = 24,
COMM_CMD_SET_DMA_ATTR = 25,
+
+ /* Commands for obtaining information */
+ COMM_CMD_SYNC_TIME = 62,
+ COMM_CMD_SEND_BDF_INFO = 64,
};
struct comm_cmd_cfg_msix_ctrl_reg {
@@ -251,6 +255,24 @@ struct comm_cmd_clear_resource {
u16 rsvd1[3];
};
+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/net/ethernet/huawei/hinic3/hinic3_hwdev.c
index 95a213133be9..697b18e6faac 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
+#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
enum hinic3_hwdev_init_state {
+ HINIC3_HWDEV_MGMT_INITED = 1,
HINIC3_HWDEV_MBOX_INITED = 2,
HINIC3_HWDEV_CMDQ_INITED = 3,
};
@@ -419,6 +422,8 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *hwdev)
goto err_clear_func_svc_used_state;
}
+ hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_ACTIVE_FLAG);
+
return 0;
err_clear_func_svc_used_state:
@@ -431,11 +436,40 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *hwdev)
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);
}
+static void hinic3_auto_sync_time_work(struct work_struct *work)
+{
+ struct delayed_work *delay = to_delayed_work(work);
+ struct hinic3_hwdev *hwdev;
+
+ hwdev = container_of(delay, struct hinic3_hwdev, sync_time_task);
+ 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) != 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) != hinic3_global_func_id(hwdev))
+ return;
+
+ cancel_delayed_work_sync(&hwdev->sync_time_task);
+}
+
static DEFINE_IDA(hinic3_adev_ida);
static int hinic3_adev_idx_alloc(void)
@@ -498,15 +532,19 @@ int hinic3_init_hwdev(struct pci_dev *pdev)
goto err_uninit_comm_ch;
}
+ hinic3_init_ppf_work(hwdev);
+
err = 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;
}
return 0;
+err_free_ppf_work:
+ hinic3_free_ppf_work(hwdev);
err_uninit_comm_ch:
hinic3_uninit_comm_ch(hwdev);
err_free_cfg_mgmt:
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/net/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 {
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..2ba1357bd080 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)
+#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)
+#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)
+#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))
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 *attr, u32 attr0, u32 attr1,
attr->pci_intf_idx = HINIC3_AF0_GET(attr0, PCI_INTF_IDX);
attr->func_type = HINIC3_AF0_GET(attr0, FUNC_TYPE);
+ attr->ppf_idx = HINIC3_AF1_GET(attr1, PPF_IDX);
attr->num_aeqs = BIT(HINIC3_AF1_GET(attr1, AEQS_PER_FUNC));
attr->num_ceqs = HINIC3_AF2_GET(attr2, CEQS_PER_FUNC);
attr->num_irqs = HINIC3_AF2_GET(attr2, IRQS_PER_FUNC);
if (attr->num_irqs > HINIC3_MAX_MSIX_ENTRY)
attr->num_irqs = HINIC3_MAX_MSIX_ENTRY;
+ attr->global_vf_id_of_pf = HINIC3_AF3_GET(attr3, GLOBAL_VF_ID_OF_PF);
+
attr->num_sq = HINIC3_AF6_GET(attr6, FUNC_MAX_SQ);
attr->msix_flex_en = 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);
}
+static void set_ppf(struct hinic3_hwdev *hwdev)
+{
+ struct hinic3_hwif *hwif = hwdev->hwif;
+ struct hinic3_func_attr *attr;
+ u32 addr, val;
+
+ if (HINIC3_IS_VF(hwdev))
+ return;
+
+ /* Read Modify Write */
+ attr = &hwif->attr;
+ addr = HINIC3_CSR_PPF_ELECTION_ADDR;
+ val = hinic3_hwif_read_reg(hwif, addr);
+ val &= ~HINIC3_PPF_ELECTION_IDX_MASK;
+ val |= HINIC3_PPF_ELECTION_SET(attr->func_global_idx, IDX);
+ hinic3_hwif_write_reg(hwif, addr, val);
+
+ /* Check PPF index */
+ val = hinic3_hwif_read_reg(hwif, addr);
+ attr->ppf_idx = 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(struct hinic3_hwif *hwif)
USEC_PER_MSEC);
}
+void hinic3_set_pf_status(struct hinic3_hwif *hwif,
+ enum hinic3_pf_status status)
+{
+ u32 attr6 = hinic3_hwif_read_reg(hwif, HINIC3_CSR_FUNC_ATTR6_ADDR);
+
+ attr6 &= ~HINIC3_AF6_PF_STATUS_MASK;
+ attr6 |= HINIC3_AF6_SET(status, PF_STATUS);
+
+ if (hwif->attr.func_type == 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 = 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 = hwdev->adapter;
@@ -378,9 +437,14 @@ int hinic3_init_hwif(struct hinic3_hwdev *hwdev)
return -ENOMEM;
hwdev->hwif = hwif;
- hwif->cfg_regs_base = (u8 __iomem *)pci_adapter->cfg_reg_base +
+ /* if function is VF, mgmt_regs_base will be NULL */
+ hwif->cfg_regs_base = pci_adapter->mgmt_reg_base ? (u8 __iomem *)pci_adapter->cfg_reg_base :
+ (u8 __iomem *)pci_adapter->cfg_reg_base +
HINIC3_VF_CFG_REG_OFFSET;
+ hwif->intr_regs_base = pci_adapter->intr_reg_base;
+ hwif->mgmt_regs_base = pci_adapter->mgmt_reg_base;
+
err = db_area_idx_init(hwif, pci_adapter->db_base_phy,
pci_adapter->db_base,
pci_adapter->db_dwqe_len);
@@ -412,7 +476,15 @@ int hinic3_init_hwif(struct hinic3_hwdev *hwdev)
goto err_free_db_area_idx;
}
+ 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);
return 0;
@@ -434,3 +506,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;
enum hinic3_func_type {
+ HINIC3_FUNC_TYPE_PF = 0,
HINIC3_FUNC_TYPE_VF = 1,
};
@@ -38,6 +39,8 @@ static_assert(sizeof(struct hinic3_func_attr) == 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 = 0x1,
};
+enum hinic3_pf_status {
+ HINIC3_PF_STATUS_INIT = 0x0,
+ HINIC3_PF_STATUS_ACTIVE_FLAG = 0x11,
+ HINIC3_PF_STATUS_FLR_START_FLAG = 0x12,
+ HINIC3_PF_STATUS_FLR_FINISH_FLAG = 0x13,
+};
+
enum hinic3_doorbell_ctrl {
ENABLE_DOORBELL = 0,
DISABLE_DOORBELL = 1,
@@ -65,6 +75,12 @@ enum hinic3_msix_auto_mask {
HINIC3_SET_MSIX_AUTO_MASK,
};
+#define HINIC3_FUNC_TYPE(hwdev) ((hwdev)->hwif->attr.func_type)
+#define HINIC3_IS_PF(hwdev) \
+ (HINIC3_FUNC_TYPE(hwdev) == HINIC3_FUNC_TYPE_PF)
+#define HINIC3_IS_VF(hwdev) \
+ (HINIC3_FUNC_TYPE(hwdev) == 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);
@@ -75,6 +91,10 @@ int hinic3_alloc_db_addr(struct hinic3_hwdev *hwdev, void __iomem **db_base,
void __iomem **dwqe_base);
void hinic3_free_db_addr(struct hinic3_hwdev *hwdev, const u8 __iomem *db_base);
+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);
@@ -86,5 +106,8 @@ void hinic3_set_msix_auto_mask_state(struct hinic3_hwdev *hwdev, u16 msix_idx,
enum hinic3_msix_auto_mask flag);
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);
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c b/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c
index 3db8241a3b0c..6ae7c9f13932 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c
@@ -5,15 +5,22 @@
#include <linux/iopoll.h>
#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"
#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
+#define HINIC3_IS_VF_DEV(pdev) ((pdev)->device == PCI_DEV_ID_HINIC3_VF)
+
#define HINIC3_EVENT_POLL_SLEEP_US 1000
#define HINIC3_EVENT_POLL_TIMEOUT_US 10000000
@@ -170,6 +177,23 @@ void hinic3_adev_event_register(struct auxiliary_device *adev,
hadev->event = event_handler;
}
+static void hinic3_sync_time_to_fw(struct hinic3_pcidev *pdev_pri)
+{
+ struct timespec64 ts;
+ u64 tv_msec;
+ int err;
+
+ ktime_get_real_ts64(&ts);
+
+ tv_msec = (u64)(ts.tv_sec * MSEC_PER_SEC + ts.tv_nsec / NSEC_PER_MSEC);
+ err = hinic3_sync_time(pdev_pri->hwdev, tv_msec);
+ if (err) {
+ dev_err(&pdev_pri->pdev->dev,
+ "Synchronize UTC time to firmware failed, errno:%d.\n",
+ err);
+ }
+}
+
void hinic3_adev_event_unregister(struct auxiliary_device *adev)
{
struct hinic3_adev *hadev;
@@ -181,8 +205,12 @@ void hinic3_adev_event_unregister(struct auxiliary_device *adev)
static int hinic3_mapping_bar(struct pci_dev *pdev,
struct hinic3_pcidev *pci_adapter)
{
- pci_adapter->cfg_reg_base = pci_ioremap_bar(pdev,
- HINIC3_VF_PCI_CFG_REG_BAR);
+ int cfg_bar;
+
+ cfg_bar = HINIC3_IS_VF_DEV(pdev) ?
+ HINIC3_VF_PCI_CFG_REG_BAR : HINIC3_PF_PCI_CFG_REG_BAR;
+
+ pci_adapter->cfg_reg_base = 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 +223,28 @@ static int hinic3_mapping_bar(struct pci_dev *pdev,
goto err_unmap_cfg_reg_base;
}
+ if (!HINIC3_IS_VF_DEV(pdev)) {
+ pci_adapter->mgmt_reg_base =
+ 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 = pci_resource_start(pdev, HINIC3_PCI_DB_BAR);
pci_adapter->db_dwqe_len = pci_resource_len(pdev, HINIC3_PCI_DB_BAR);
pci_adapter->db_base = 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;
}
return 0;
+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);
@@ -217,6 +257,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 +337,9 @@ static int hinic3_func_init(struct pci_dev *pdev,
return err;
}
+ if (HINIC3_IS_PF(pci_adapter->hwdev))
+ hinic3_sync_time_to_fw(pci_adapter);
+
err = hinic3_attach_aux_devices(pci_adapter->hwdev);
if (err)
goto err_free_hwdev;
@@ -311,6 +356,8 @@ static void hinic3_func_uninit(struct pci_dev *pdev)
{
struct hinic3_pcidev *pci_adapter = pci_get_drvdata(pdev);
+ /* 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);
@@ -331,8 +378,20 @@ static int hinic3_probe_func(struct hinic3_pcidev *pci_adapter)
if (err)
goto err_unmap_bar;
+ if (HINIC3_IS_PF(pci_adapter->hwdev)) {
+ err = hinic3_set_bdf_ctxt(pci_adapter->hwdev, pdev->bus->number,
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
+ if (err) {
+ dev_err(&pdev->dev, "Failed to set BDF info to fw\n");
+ goto err_uninit_func;
+ }
+ }
+
return 0;
+err_uninit_func:
+ hinic3_func_uninit(pdev);
err_unmap_bar:
hinic3_unmapping_bar(pci_adapter);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index 6d87d4d895ba..cecc59e9c536 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 = netdev_priv(netdev);
struct hinic3_hwdev *hwdev = nic_dev->hwdev;
+ u8 mac_addr[ETH_ALEN];
int err;
nic_dev->q_params.sq_depth = HINIC3_SQ_DEPTH;
@@ -137,16 +138,29 @@ static int hinic3_sw_init(struct net_device *netdev)
hinic3_try_to_enable_rss(netdev);
- /* 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 suspectable to migration so the device
+ * avoids offering MAC address to VFs.
+ */
+ eth_hw_addr_random(netdev);
+ } else {
+ err = 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 = 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 != HINIC3_PF_SET_VF_ALREADY) {
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..b4e151e88a13 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
@@ -82,10 +82,27 @@ 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 = mbox->hwdev;
struct hinic3_msg_channel *msg_ch;
-
- msg_ch = (src_func_id == MBOX_MGMT_FUNC_ID) ?
- &mbox->mgmt_msg : mbox->func_msg;
+ u16 id;
+
+ if (src_func_id == MBOX_MGMT_FUNC_ID) {
+ msg_ch = &mbox->mgmt_msg;
+ } else if (HINIC3_IS_VF(hwdev)) {
+ /* message from pf */
+ msg_ch = mbox->func_msg;
+ if (src_func_id != hinic3_pf_id_of_vf(hwdev) || !msg_ch)
+ return NULL;
+ } else if (src_func_id > hinic3_glb_pf_vf_offset(hwdev)) {
+ /* message from vf */
+ id = (src_func_id - 1) - hinic3_glb_pf_vf_offset(hwdev);
+ if (id >= 1)
+ return NULL;
+
+ msg_ch = &mbox->func_msg[id];
+ } else {
+ return NULL;
+ }
return (dir == MBOX_MSG_SEND) ?
&msg_ch->recv_msg : &msg_ch->resp_msg;
@@ -409,6 +426,13 @@ int hinic3_init_mbox(struct hinic3_hwdev *hwdev)
if (err)
goto err_destroy_workqueue;
+ if (HINIC3_IS_VF(hwdev)) {
+ /* VF to PF mbox message channel */
+ err = hinic3_init_func_mbox_msg_channel(hwdev);
+ if (err)
+ goto err_uninit_mgmt_msg_ch;
+ }
+
err = hinic3_init_func_mbox_msg_channel(hwdev);
if (err)
goto err_uninit_mgmt_msg_ch;
@@ -424,8 +448,8 @@ int hinic3_init_mbox(struct hinic3_hwdev *hwdev)
return 0;
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);
@@ -576,7 +600,13 @@ static void write_mbox_msg_attr(struct hinic3_mbox *mbox,
{
struct hinic3_hwif *hwif = mbox->hwdev->hwif;
u32 mbox_int, mbox_ctrl, tx_size;
+ u16 func = dst_func;
+ /* 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 != MBOX_MGMT_FUNC_ID)
+ func = 0;
tx_size = ALIGN(seg_len + MBOX_HEADER_SZ, MBOX_SEG_LEN_ALIGN) >> 2;
mbox_int = MBOX_INT_SET(dst_aeqn, DST_AEQN) |
@@ -587,7 +617,7 @@ static void write_mbox_msg_attr(struct hinic3_mbox *mbox,
mbox_ctrl = 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);
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/drivers/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 = 8,
L2NIC_CMD_CLEAR_QP_RESOURCE = 11,
L2NIC_CMD_FEATURE_NEGO = 15,
+ L2NIC_CMD_GET_MAC = 20,
L2NIC_CMD_SET_MAC = 21,
L2NIC_CMD_DEL_MAC = 22,
L2NIC_CMD_UPDATE_MAC = 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..2b93026845ff 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
@@ -117,17 +117,49 @@ int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu)
&func_tbl_cfg);
}
+#define PF_SET_VF_MAC(hwdev, status) \
+ (HINIC3_IS_VF(hwdev) && (status) == HINIC3_PF_SET_VF_ALREADY)
+
static int hinic3_check_mac_info(struct hinic3_hwdev *hwdev, u8 status,
u16 vlan_id)
{
if ((status && status != MGMT_STATUS_EXIST) ||
((vlan_id & BIT(15)) && status == MGMT_STATUS_EXIST)) {
+ if (PF_SET_VF_MAC(hwdev, status))
+ return 0;
+
return -EINVAL;
}
return 0;
}
+int hinic3_get_default_mac(struct hinic3_hwdev *hwdev, u8 *mac_addr)
+{
+ struct l2nic_cmd_set_mac mac_info = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ mac_info.func_id = hinic3_global_func_id(hwdev);
+
+ mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info));
+
+ err = 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 -EINVAL;
+ }
+
+ ether_addr_copy(mac_addr, mac_info.mac);
+
+ return 0;
+}
+
int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
u16 func_id)
{
@@ -157,9 +189,9 @@ int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
return -EIO;
}
- if (mac_info.msg_head.status == MGMT_STATUS_PF_SET_VF_ALREADY) {
+ if (PF_SET_VF_MAC(hwdev, mac_info.msg_head.status)) {
dev_warn(hwdev->dev, "PF has already set VF mac, Ignore set operation\n");
- return 0;
+ return HINIC3_PF_SET_VF_ALREADY;
}
if (mac_info.msg_head.status == MGMT_STATUS_EXIST) {
@@ -191,11 +223,17 @@ int hinic3_del_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
L2NIC_CMD_DEL_MAC, &msg_params);
- if (err) {
+ if (err || (mac_info.msg_head.status &&
+ !PF_SET_VF_MAC(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 -EIO;
+ }
+
+ if (PF_SET_VF_MAC(hwdev, mac_info.msg_head.status)) {
+ dev_warn(hwdev->dev, "PF has already set VF mac, Ignore delete operation.\n");
+ return HINIC3_PF_SET_VF_ALREADY;
}
return 0;
@@ -231,6 +269,17 @@ int hinic3_update_mac(struct hinic3_hwdev *hwdev, const u8 *old_mac,
return -EIO;
}
+ if (PF_SET_VF_MAC(hwdev, mac_info.msg_head.status)) {
+ dev_warn(hwdev->dev, "PF has already set VF MAC. Ignore update operation\n");
+ return HINIC3_PF_SET_VF_ALREADY;
+ }
+
+ if (mac_info.msg_head.status == HINIC3_MGMT_STATUS_EXIST) {
+ dev_warn(hwdev->dev,
+ "MAC is repeated. Ignore update operation\n");
+ return 0;
+ }
+
return 0;
}
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
#define HINIC3_VLAN_ID_MASK 0x7FFF
+#define HINIC3_PF_SET_VF_ALREADY 0x4
+#define HINIC3_MGMT_STATUS_EXIST 0x6
enum hinic3_nic_event_type {
HINIC3_NIC_EVENT_LINK_DOWN = 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);
+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 vlan_id,
u16 func_id);
int hinic3_del_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 2/9] hinic3: Add PF management interfaces
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 1/9] hinic3: Add PF framework Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 10:00 ` [PATCH net-next " Markus Elfring
2025-10-15 7:15 ` [PATCH net-next v01 3/9] hinic3: Add NIC configuration ops Fan Gong
` (6 subsequent siblings)
8 siblings, 1 reply; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
Add management and communication pathways between PF and HW.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
.../ethernet/huawei/hinic3/hinic3_hw_intf.h | 2 +
.../net/ethernet/huawei/hinic3/hinic3_hwdev.c | 51 ++-
.../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 37 ++-
.../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 | 308 +++++++++++++++++-
.../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 | 2 +
13 files changed, 532 insertions(+), 20 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 = 7,
MGMT_MOD_HILINK = 14,
+ /* hardware max module id */
+ MGMT_MOD_HW_MAX = 20,
};
static inline void mgmt_msg_params_init_default(struct mgmt_msg_params *msg_params,
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c
index 697b18e6faac..386f56f34866 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 *hwdev)
return 0;
}
+static int hinic3_comm_pf_to_mgmt_init(struct hinic3_hwdev *hwdev)
+{
+ int err;
+
+ if (HINIC3_IS_VF(hwdev))
+ return 0;
+
+ err = 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 *hwdev)
if (err)
return err;
- err = init_basic_attributes(hwdev);
+ err = hinic3_comm_pf_to_mgmt_init(hwdev);
if (err)
goto err_free_basic_mgmt_ch;
+ err = init_basic_attributes(hwdev);
+ if (err)
+ goto err_free_comm_pf_to_mgmt;
+
err = 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 *hwdev)
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);
@@ -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);
}
@@ -577,9 +614,21 @@ void hinic3_free_hwdev(struct hinic3_hwdev *hwdev)
void hinic3_set_api_stop(struct hinic3_hwdev *hwdev)
{
+ struct hinic3_recv_msg *recv_resp_msg;
struct hinic3_mbox *mbox;
spin_lock_bh(&hwdev->channel_lock);
+ if (HINIC3_IS_PF(hwdev) &&
+ test_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state)) {
+ recv_resp_msg = &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 == COMM_SEND_EVENT_START) {
+ complete(&recv_resp_msg->recv_done);
+ hwdev->pf_to_mgmt->event_flag = 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 = hwdev->mbox;
spin_lock(&mbox->mbox_lock);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h
index 78cface6ddd7..58c0c0b55097 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h
@@ -39,24 +39,25 @@ struct hinic3_pcidev {
};
struct hinic3_hwdev {
- struct hinic3_pcidev *adapter;
- struct pci_dev *pdev;
- struct device *dev;
- int dev_id;
- struct hinic3_hwif *hwif;
- struct hinic3_cfg_mgmt_info *cfg_mgmt;
- struct hinic3_aeqs *aeqs;
- 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;
- u64 features[COMM_MAX_FEATURE_QWORD];
- u32 wq_page_size;
- u8 max_cmdq;
- ulong func_state;
+ struct hinic3_pcidev *adapter;
+ struct pci_dev *pdev;
+ struct device *dev;
+ int dev_id;
+ struct hinic3_hwif *hwif;
+ struct hinic3_cfg_mgmt_info *cfg_mgmt;
+ struct hinic3_aeqs *aeqs;
+ struct hinic3_ceqs *ceqs;
+ struct hinic3_mbox *mbox;
+ struct hinic3_msg_pf_to_mgmt *pf_to_mgmt;
+ struct hinic3_cmdqs *cmdqs;
+ struct delayed_work sync_time_task;
+ struct workqueue_struct *workq;
+ /* protect hwdev channel init and uninit */
+ spinlock_t channel_lock;
+ u64 features[COMM_MAX_FEATURE_QWORD];
+ u32 wq_page_size;
+ u8 max_cmdq;
+ ulong func_state;
};
struct hinic3_event_info {
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index cecc59e9c536..5ac030c88085 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;
+ sema_init(&nic_dev->port_state_sem, 1);
+
nic_dev->q_params.sq_depth = HINIC3_SQ_DEPTH;
nic_dev->q_params.rq_depth = HINIC3_RQ_DEPTH;
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
index b4e151e88a13..a4be5b2984cf 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
@@ -870,6 +870,19 @@ int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
return err;
}
+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 = (u8)msg_id;
+ msg_info.status = 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, u16 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);
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, u16 cmd,
const struct mgmt_msg_params *msg_params);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c
index c38d10cd7fac..970ee0528770 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c
@@ -3,19 +3,325 @@
#include "hinic3_eqs.h"
#include "hinic3_hwdev.h"
+#include "hinic3_hwif.h"
#include "hinic3_mbox.h"
#include "hinic3_mgmt.h"
+#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 mgmt_resp_msg_handler(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt,
+ struct hinic3_recv_msg *recv_msg)
+{
+ struct device *dev = 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 != pf_to_mgmt->sync_msg_id) {
+ dev_err(dev, "msg id mismatch, 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);
+ } else if (pf_to_mgmt->event_flag == COMM_SEND_EVENT_START) {
+ pf_to_mgmt->event_flag = 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 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 = 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 = mgmt_work->pf_to_mgmt;
+ ack_cmd = pf_to_mgmt->mgmt_ack_buf;
+ memset(ack_cmd, 0, sizeof(*ack_cmd));
+ ack_cmd->status = 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 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 = MBOX_MSG_HEADER_GET(msg_header, SEG_LEN);
+ is_last = MBOX_MSG_HEADER_GET(msg_header, LAST);
+ seq_id = MBOX_MSG_HEADER_GET(msg_header, SEQID);
+ msg_id = 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 != MGMT_SEG_LEN_MAX && !is_last)
+ return -EINVAL;
+
+ if (seq_id == 0) {
+ recv_msg->seq_id = seq_id;
+ recv_msg->msg_id = msg_id;
+ } else if (seq_id != recv_msg->seq_id + 1 ||
+ msg_id != recv_msg->msg_id) {
+ return -EINVAL;
+ }
+
+ offset = seq_id * MGMT_SEG_LEN_MAX;
+ if (offset + seg_len > MGMT_MAX_PF_BUF_SIZE)
+ return -EINVAL;
+
+ msg_buff = recv_msg->msg;
+ memcpy(msg_buff + offset, seg_data, seg_len);
+ recv_msg->msg_len = offset + seg_len;
+ recv_msg->seq_id = seq_id;
+ *is_complete = !!is_last;
+
+ return 0;
+}
+
+static void 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 = kmalloc(sizeof(*mgmt_work), GFP_KERNEL);
+ if (!mgmt_work)
+ return;
+
+ if (recv_msg->msg_len) {
+ mgmt_work->msg = kmalloc(recv_msg->msg_len, GFP_KERNEL);
+ if (!mgmt_work->msg) {
+ kfree(mgmt_work);
+ return;
+ }
+ }
+
+ mgmt_work->pf_to_mgmt = pf_to_mgmt;
+ mgmt_work->msg_len = recv_msg->msg_len;
+ memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len);
+ mgmt_work->msg_id = recv_msg->msg_id;
+ mgmt_work->mod = recv_msg->mod;
+ mgmt_work->cmd = recv_msg->cmd;
+ mgmt_work->async_mgmt_to_pf = recv_msg->async_mgmt_to_pf;
+
+ INIT_WORK(&mgmt_work->work, recv_mgmt_msg_work_handler);
+ queue_work(pf_to_mgmt->workq, &mgmt_work->work);
+}
+
+static void 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 = pf_to_mgmt->hwdev;
+ const void *seg_data;
+ __le64 msg_header;
+ bool is_complete;
+ u8 dir, msg_id;
+ int err;
+
+ msg_header = *(__force __le64 *)header;
+ dir = MBOX_MSG_HEADER_GET(msg_header, DIRECTION);
+ msg_id = MBOX_MSG_HEADER_GET(msg_header, MSG_ID);
+ /* Don't need to get anything from hw when cmd is async */
+ if (dir == MBOX_MSG_RESP && (msg_id & MGMT_ASYNC_MSG_FLAG))
+ return;
+
+ seg_data = header + sizeof(msg_header);
+ err = 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 = MGMT_BOGUS_SEQ_ID;
+
+ return;
+ }
+
+ if (!is_complete)
+ return;
+
+ recv_msg->cmd = MBOX_MSG_HEADER_GET(msg_header, CMD);
+ recv_msg->mod = MBOX_MSG_HEADER_GET(msg_header, MODULE);
+ recv_msg->async_mgmt_to_pf = MBOX_MSG_HEADER_GET(msg_header, NO_ACK);
+ recv_msg->seq_id = MGMT_BOGUS_SEQ_ID;
+
+ if (dir == MBOX_MSG_RESP)
+ mgmt_resp_msg_handler(pf_to_mgmt, recv_msg);
+ else
+ init_mgmt_msg_work(pf_to_mgmt, recv_msg);
+}
+
+static int alloc_recv_msg(struct hinic3_recv_msg *recv_msg)
+{
+ recv_msg->seq_id = MGMT_BOGUS_SEQ_ID;
+
+ recv_msg->msg = 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 = pf_to_mgmt->hwdev->dev;
+ int err;
+
+ err = alloc_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
+ if (err) {
+ dev_err(dev, "Failed to allocate recv msg\n");
+ return err;
+ }
+
+ err = 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 = kzalloc(MGMT_MAX_PF_BUF_SIZE, GFP_KERNEL);
+ if (!pf_to_mgmt->mgmt_ack_buf) {
+ err = -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 = kzalloc(sizeof(*pf_to_mgmt), GFP_KERNEL);
+ if (!pf_to_mgmt)
+ return -ENOMEM;
+
+ hwdev->pf_to_mgmt = pf_to_mgmt;
+ pf_to_mgmt->hwdev = hwdev;
+ spin_lock_init(&pf_to_mgmt->sync_event_lock);
+ pf_to_mgmt->workq = create_singlethread_workqueue(HINIC3_MGMT_WQ_NAME);
+ if (!pf_to_mgmt->workq) {
+ dev_err(hwdev->dev, "Failed to initialize MGMT workqueue\n");
+ err = -ENOMEM;
+ goto err_free_pf_to_mgmt;
+ }
+
+ err = 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 = 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);
}
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) ==
- MBOX_MSG_FROM_MBOX)
+ MBOX_MSG_FROM_MBOX){
hinic3_mbox_func_aeqe_handler(hwdev, header, size);
+
+ return;
+ }
+
+ pf_to_mgmt = hwdev->pf_to_mgmt;
+ msg_header = *(__force __le64 *)header;
+
+ is_send_dir = (MBOX_MSG_HEADER_GET(msg_header, DIRECTION) ==
+ MBOX_MSG_SEND) ? true : false;
+
+ recv_msg = is_send_dir ? &pf_to_mgmt->recv_msg_from_mgmt :
+ &pf_to_mgmt->recv_resp_msg_from_mgmt;
+
+ 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 @@
#include <linux/types.h>
+#include "hinic3_mbox.h"
+#include "hinic3_hw_intf.h"
+
struct hinic3_hwdev;
+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/drivers/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 {
/* hilink mac group command */
enum mag_cmd {
+ MAG_CMD_SET_PORT_ENABLE = 6,
MAG_CMD_GET_LINK_STATUS = 7,
};
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
index 0fa3c7900225..ebac18543a1c 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 *netdev)
hinic3_free_qp_ctxts(nic_dev);
}
+static int hinic3_maybe_set_port_state(struct net_device *netdev, bool enable)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ int err;
+
+ down(&nic_dev->port_state_sem);
+ err = hinic3_set_port_enable(nic_dev->hwdev, enable);
+ up(&nic_dev->port_state_sem);
+
+ return err;
+}
+
+static void hinic3_print_link_message(struct net_device *netdev,
+ bool link_status_up)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+
+ if (nic_dev->link_status_up == link_status_up)
+ return;
+
+ nic_dev->link_status_up = link_status_up;
+
+ netdev_dbg(netdev, "Link is %s\n", (link_status_up ? "up" : "down"));
+}
+
static int hinic3_vport_up(struct net_device *netdev)
{
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
@@ -341,6 +366,12 @@ static int hinic3_vport_up(struct net_device *netdev)
goto err_flush_qps_res;
}
+ err = hinic3_maybe_set_port_state(netdev, true);
+ if (err) {
+ netdev_err(netdev, "Failed to enable port\n");
+ goto err_disable_vport;
+ }
+
err = 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);
+ hinic3_print_link_message(netdev, link_status_up);
+
return 0;
+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 2b93026845ff..1ed266d5d40c 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
@@ -362,6 +362,34 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev)
return pkt_drop.msg_head.status;
}
+int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable)
+{
+ struct mag_cmd_set_port_enable en_state = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ if (HINIC3_IS_VF(hwdev))
+ return 0;
+
+ en_state.function_id = hinic3_global_func_id(hwdev);
+ en_state.state = 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 = 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 -EIO;
+ }
+
+ return 0;
+}
+
int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state)
{
struct l2nic_cmd_set_dcb_state dcb_state = {};
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;
};
+#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 down,
+ * 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);
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_up);
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..3a9f3ccdb684 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
@@ -83,6 +83,8 @@ struct hinic3_nic_dev {
struct hinic3_intr_coal_info *intr_coalesce;
+ struct semaphore port_state_sem;
+
bool link_status_up;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 3/9] hinic3: Add NIC configuration ops
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 1/9] hinic3: Add PF framework Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 2/9] hinic3: Add PF management interfaces Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 4/9] hinic3: Add mac filter ops Fan Gong
` (5 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
Add ops to configure NIC feature(lro, vlan, csum...).
Add queue work to collect NIC data.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
.../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_hwdev.h | 9 +
.../net/ethernet/huawei/hinic3/hinic3_irq.c | 134 +++++++-
.../net/ethernet/huawei/hinic3/hinic3_main.c | 43 +++
.../huawei/hinic3/hinic3_mgmt_interface.h | 50 +++
.../huawei/hinic3/hinic3_netdev_ops.c | 318 ++++++++++++++++++
.../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 171 ++++++++++
.../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 7 +
.../ethernet/huawei/hinic3/hinic3_nic_dev.h | 45 +++
.../net/ethernet/huawei/hinic3/hinic3_rx.h | 20 ++
.../net/ethernet/huawei/hinic3/hinic3_tx.h | 18 +
13 files changed, 871 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c
index 7a4011621dcc..2d7e6809c091 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"
+static int hinic3_get_interrupt_cfg(struct hinic3_hwdev *hwdev,
+ struct hinic3_interrupt_info *info)
+{
+ struct comm_cmd_cfg_msix_ctrl_reg msix_cfg = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ msix_cfg.func_id = hinic3_global_func_id(hwdev);
+ msix_cfg.msix_index = info->msix_index;
+ msix_cfg.opcode = MGMT_MSG_CMD_OP_GET;
+
+ mgmt_msg_params_init_default(&msg_params, &msix_cfg, sizeof(msix_cfg));
+
+ err = 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 -EINVAL;
+ }
+
+ info->lli_credit_limit = msix_cfg.lli_credit_cnt;
+ info->lli_timer_cfg = msix_cfg.lli_timer_cnt;
+ info->pending_limit = msix_cfg.pending_cnt;
+ info->coalesc_timer_cfg = msix_cfg.coalesce_timer_cnt;
+ info->resend_timer_cfg = 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;
}
+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 = info.msix_index;
+
+ err = hinic3_get_interrupt_cfg(hwdev, &temp_info);
+ if (err)
+ return -EINVAL;
+
+ info.lli_credit_limit = temp_info.lli_credit_limit;
+ info.lli_timer_cfg = temp_info.lli_timer_cfg;
+
+ if (!info.interrupt_coalesc_set) {
+ info.pending_limit = temp_info.pending_limit;
+ info.coalesc_timer_cfg = temp_info.coalesc_timer_cfg;
+ info.resend_timer_cfg = 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_flag)
{
struct comm_cmd_func_reset func_reset = {};
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h
index 87446522e926..a3c3f0bfd442 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 {
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_flag);
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/net/ethernet/huawei/hinic3/hinic3_hwdev.c
index 386f56f34866..575a539f271b 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 *hwdev)
for (q_id = 0; q_id < ceqs->num_ceqs; q_id++) {
eq = &ceqs->ceq[q_id];
info.msix_index = eq->msix_entry_idx;
- err = hinic3_set_interrupt_cfg_direct(hwdev, &info);
+ err = 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_hwdev.h b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h
index 58c0c0b55097..3bed3215bbbc 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 = 1
};
+enum hinic3_fault_err_level {
+ HINIC3_FAULT_LEVEL_SERIOUS_FLR = 3,
+};
+
+enum hinic3_fault_source_type {
+ HINIC3_FAULT_SRC_HW_PHY_FAULT = 9,
+ HINIC3_FAULT_SRC_TX_TIMEOUT = 22,
+};
+
#define HINIC3_SRV_EVENT_TYPE(svc, type) (((svc) << 16) | (type))
/* driver-specific data of pci_dev */
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
index a69b361225e9..ac79b8bf9b56 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
@@ -10,6 +10,9 @@
#include "hinic3_rx.h"
#include "hinic3_tx.h"
+#define HINIC3_RX_RATE_THRESH 50000
+#define HINIC3_AVG_PKT_SMALL 256U
+
static int hinic3_poll(struct napi_struct *napi, int budget)
{
struct hinic3_irq_cfg *irq_cfg =
@@ -92,7 +95,7 @@ static int hinic3_request_irq(struct hinic3_irq_cfg *irq_cfg, u16 q_id)
info.coalesc_timer_cfg =
nic_dev->intr_coalesce[q_id].coalesce_timer_cfg;
info.resend_timer_cfg = nic_dev->intr_coalesce[q_id].resend_timer_cfg;
- err = hinic3_set_interrupt_cfg_direct(nic_dev->hwdev, &info);
+ err = 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 +120,132 @@ static void hinic3_release_irq(struct hinic3_irq_cfg *irq_cfg)
free_irq(irq_cfg->irq_id, irq_cfg);
}
+static int set_interrupt_moder(struct net_device *netdev, u16 q_id,
+ u8 coalesc_timer_cfg, u8 pending_limit)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_interrupt_info info = {};
+ int err;
+
+ if (coalesc_timer_cfg == nic_dev->rxqs[q_id].last_coalesc_timer_cfg &&
+ pending_limit == nic_dev->rxqs[q_id].last_pending_limit)
+ return 0;
+
+ if (q_id >= nic_dev->q_params.num_qps)
+ return 0;
+
+ info.interrupt_coalesc_set = 1;
+ info.coalesc_timer_cfg = coalesc_timer_cfg;
+ info.pending_limit = pending_limit;
+ info.msix_index = nic_dev->q_params.irq_cfg[q_id].msix_entry_idx;
+ info.resend_timer_cfg =
+ nic_dev->intr_coalesce[q_id].resend_timer_cfg;
+
+ err = 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 = coalesc_timer_cfg;
+ nic_dev->rxqs[q_id].last_pending_limit = pending_limit;
+ }
+
+ return err;
+}
+
+static void calc_coal_para(struct hinic3_intr_coal_info *q_coal, u64 rx_rate,
+ u8 *coalesc_timer_cfg, u8 *pending_limit)
+{
+ if (rx_rate < q_coal->pkt_rate_low) {
+ *coalesc_timer_cfg = q_coal->rx_usecs_low;
+ *pending_limit = q_coal->rx_pending_limit_low;
+ } else if (rx_rate > q_coal->pkt_rate_high) {
+ *coalesc_timer_cfg = q_coal->rx_usecs_high;
+ *pending_limit = q_coal->rx_pending_limit_high;
+ } else {
+ *coalesc_timer_cfg =
+ (u8)((rx_rate - q_coal->pkt_rate_low) *
+ (q_coal->rx_usecs_high - q_coal->rx_usecs_low) /
+ (q_coal->pkt_rate_high - q_coal->pkt_rate_low) +
+ q_coal->rx_usecs_low);
+
+ *pending_limit =
+ (u8)((rx_rate - q_coal->pkt_rate_low) *
+ (q_coal->rx_pending_limit_high - q_coal->rx_pending_limit_low) /
+ (q_coal->pkt_rate_high - q_coal->pkt_rate_low) +
+ q_coal->rx_pending_limit_low);
+ }
+}
+
+static void update_queue_coal(struct net_device *netdev, u16 qid,
+ u64 rx_rate, u64 avg_pkt_size, u64 tx_rate)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_intr_coal_info *q_coal;
+ u8 coalesc_timer_cfg, pending_limit;
+
+ q_coal = &nic_dev->intr_coalesce[qid];
+
+ if (rx_rate > HINIC3_RX_RATE_THRESH &&
+ avg_pkt_size > HINIC3_AVG_PKT_SMALL) {
+ calc_coal_para(q_coal, rx_rate, &coalesc_timer_cfg,
+ &pending_limit);
+ } else {
+ coalesc_timer_cfg = 3;
+ pending_limit = q_coal->rx_pending_limit_low;
+ }
+
+ set_interrupt_moder(netdev, qid, coalesc_timer_cfg, pending_limit);
+}
+
+static void hinic3_auto_moderation_work(struct work_struct *work)
+{
+ u64 rx_packets, rx_bytes, rx_pkt_diff, rx_rate, avg_pkt_size;
+ u64 tx_packets, tx_bytes, tx_pkt_diff, tx_rate;
+ struct hinic3_nic_dev *nic_dev;
+ struct delayed_work *delay;
+ struct net_device *netdev;
+ unsigned long period;
+ u16 qid;
+
+ delay = to_delayed_work(work);
+ nic_dev = container_of(delay, struct hinic3_nic_dev, moderation_task);
+ period = (unsigned long)(jiffies - nic_dev->last_moder_jiffies);
+ netdev = nic_dev->netdev;
+
+ queue_delayed_work(nic_dev->workq, &nic_dev->moderation_task,
+ HINIC3_MODERATONE_DELAY);
+
+ for (qid = 0; qid < nic_dev->q_params.num_qps; qid++) {
+ rx_packets = nic_dev->rxqs[qid].rxq_stats.packets;
+ rx_bytes = nic_dev->rxqs[qid].rxq_stats.bytes;
+ tx_packets = nic_dev->txqs[qid].txq_stats.packets;
+ tx_bytes = nic_dev->txqs[qid].txq_stats.bytes;
+
+ rx_pkt_diff =
+ rx_packets - nic_dev->rxqs[qid].last_moder_packets;
+ avg_pkt_size = rx_pkt_diff ?
+ ((unsigned long)(rx_bytes -
+ nic_dev->rxqs[qid].last_moder_bytes)) /
+ rx_pkt_diff : 0;
+
+ rx_rate = rx_pkt_diff * HZ / period;
+ tx_pkt_diff =
+ tx_packets - nic_dev->txqs[qid].last_moder_packets;
+ tx_rate = tx_pkt_diff * HZ / period;
+
+ update_queue_coal(netdev, qid, rx_rate, avg_pkt_size,
+ tx_rate);
+
+ nic_dev->rxqs[qid].last_moder_packets = rx_packets;
+ nic_dev->rxqs[qid].last_moder_bytes = rx_bytes;
+ nic_dev->txqs[qid].last_moder_packets = tx_packets;
+ nic_dev->txqs[qid].last_moder_bytes = tx_bytes;
+ }
+
+ nic_dev->last_moder_jiffies = jiffies;
+}
+
int hinic3_qps_irq_init(struct net_device *netdev)
{
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
@@ -157,6 +286,9 @@ int hinic3_qps_irq_init(struct net_device *netdev)
HINIC3_MSIX_ENABLE);
}
+ INIT_DELAYED_WORK(&nic_dev->moderation_task,
+ hinic3_auto_moderation_work);
+
return 0;
err_release_irqs:
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index 5ac030c88085..baedf1589a49 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 *netdev)
hinic3_free_txqs(netdev);
}
+static void hinic3_periodic_work_handler(struct work_struct *work)
+{
+ struct delayed_work *delay = to_delayed_work(work);
+ struct hinic3_nic_dev *nic_dev;
+
+ nic_dev = 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)
{
@@ -121,8 +137,23 @@ static int hinic3_init_nic_dev(struct net_device *netdev,
nic_dev->rx_buf_len = HINIC3_RX_BUF_LEN;
nic_dev->lro_replenish_thld = HINIC3_LRO_REPLENISH_THLD;
+ nic_dev->vlan_bitmap = kzalloc(HINIC3_VLAN_BITMAP_SIZE(nic_dev),
+ GFP_KERNEL);
+ if (!nic_dev->vlan_bitmap)
+ return -ENOMEM;
+
nic_dev->nic_svc_cap = hwdev->cfg_mgmt->cap.nic_svc_cap;
+ nic_dev->workq = 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;
+ }
+
+ INIT_DELAYED_WORK(&nic_dev->periodic_work,
+ hinic3_periodic_work_handler);
+
return 0;
}
@@ -229,6 +260,13 @@ static int hinic3_set_default_hw_feature(struct net_device *netdev)
return err;
}
+ err = 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;
}
@@ -329,6 +367,7 @@ static int hinic3_nic_probe(struct auxiliary_device *adev,
if (err)
goto err_uninit_sw;
+ queue_delayed_work(nic_dev->workq, &nic_dev->periodic_work, HZ);
netif_carrier_off(netdev);
err = register_netdev(netdev);
@@ -368,12 +407,16 @@ static void hinic3_nic_remove(struct auxiliary_device *adev)
netdev = nic_dev->netdev;
unregister_netdev(netdev);
+ cancel_delayed_work_sync(&nic_dev->periodic_work);
+ destroy_workqueue(nic_dev->workq);
+
hinic3_update_nic_feature(nic_dev, 0);
hinic3_set_nic_feature_to_hw(nic_dev);
hinic3_sw_uninit(netdev);
hinic3_free_nic_io(nic_dev);
+ kfree(nic_dev->vlan_bitmap);
free_netdev(netdev);
}
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
index 3a6d3ee534d0..68dfdfa1b1ba 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
@@ -56,6 +56,31 @@ struct l2nic_cmd_update_mac {
u8 new_mac[ETH_ALEN];
};
+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;
+ u8 vlan_offload;
+ u8 vd1[5];
+};
+
+/* set vlan filter */
+struct l2nic_cmd_set_vlan_filter {
+ struct mgmt_msg_head msg_head;
+ u16 func_id;
+ u8 resvd[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 +127,26 @@ struct l2nic_cmd_set_dcb_state {
u8 rsvd[7];
};
+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 +207,16 @@ enum l2nic_cmd {
L2NIC_CMD_SET_VPORT_ENABLE = 6,
L2NIC_CMD_SET_SQ_CI_ATTR = 8,
L2NIC_CMD_CLEAR_QP_RESOURCE = 11,
+ L2NIC_CMD_CFG_RX_LRO = 13,
+ L2NIC_CMD_CFG_LRO_TIMER = 14,
L2NIC_CMD_FEATURE_NEGO = 15,
L2NIC_CMD_GET_MAC = 20,
L2NIC_CMD_SET_MAC = 21,
L2NIC_CMD_DEL_MAC = 22,
L2NIC_CMD_UPDATE_MAC = 23,
+ L2NIC_CMD_CFG_FUNC_VLAN = 25,
+ L2NIC_CMD_SET_VLAN_FILTER_EN = 26,
+ L2NIC_CMD_SET_RX_VLAN_OFFLOAD = 27,
L2NIC_CMD_CFG_RSS = 60,
L2NIC_CMD_CFG_RSS_HASH_KEY = 63,
L2NIC_CMD_CFG_RSS_HASH_ENGINE = 64,
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
index ebac18543a1c..0cc2fcf3efa5 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
@@ -12,6 +12,15 @@
#include "hinic3_rx.h"
#include "hinic3_tx.h"
+#define HINIC3_LRO_DEFAULT_COAL_PKT_SIZE 32
+#define HINIC3_LRO_DEFAULT_TIME_LIMIT 16
+
+#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.
*/
@@ -384,6 +393,9 @@ static int hinic3_vport_up(struct net_device *netdev)
if (!err && link_status_up)
netif_carrier_on(netdev);
+ queue_delayed_work(nic_dev->workq, &nic_dev->moderation_task,
+ HINIC3_MODERATONE_DELAY);
+
hinic3_print_link_message(netdev, link_status_up);
return 0;
@@ -406,6 +418,8 @@ static void hinic3_vport_down(struct net_device *netdev)
netif_carrier_off(netdev);
netif_tx_disable(netdev);
+ cancel_delayed_work_sync(&nic_dev->moderation_task);
+
glb_func_id = hinic3_global_func_id(nic_dev->hwdev);
hinic3_set_vport_enable(nic_dev->hwdev, glb_func_id, false);
@@ -476,6 +490,162 @@ static int hinic3_close(struct net_device *netdev)
return 0;
}
+#define SET_FEATURES_OP_STR(op) ((op) ? "Enable" : "Disable")
+
+static int 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 = wanted_features ^ features;
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_hwdev *hwdev = 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 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 = wanted_features ^ features;
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_hwdev *hwdev = 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 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 = wanted_features ^ features;
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_hwdev *hwdev = nic_dev->hwdev;
+ bool en = !!(wanted_features & NETIF_F_LRO);
+ int err;
+
+ if (!(changed & NETIF_F_LRO))
+ return 0;
+
+ err = 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 |= NETIF_F_LRO;
+ }
+
+ return err;
+}
+
+static int set_feature_rx_cvlan(struct net_device *netdev,
+ netdev_features_t wanted_features,
+ netdev_features_t features,
+ netdev_features_t *failed_features)
+{
+ bool en = !!(wanted_features & NETIF_F_HW_VLAN_CTAG_RX);
+ netdev_features_t changed = wanted_features ^ features;
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_hwdev *hwdev = nic_dev->hwdev;
+ int err;
+
+ if (!(changed & NETIF_F_HW_VLAN_CTAG_RX))
+ return 0;
+
+ err = hinic3_set_rx_vlan_offload(hwdev, en);
+ if (err) {
+ dev_err(hwdev->dev, "%s rxvlan failed\n",
+ SET_FEATURES_OP_STR(en));
+ *failed_features |= NETIF_F_HW_VLAN_CTAG_RX;
+ }
+
+ return err;
+}
+
+static int set_feature_vlan_filter(struct net_device *netdev,
+ netdev_features_t wanted_features,
+ netdev_features_t features,
+ netdev_features_t *failed_features)
+{
+ bool en = !!(wanted_features & NETIF_F_HW_VLAN_CTAG_FILTER);
+ netdev_features_t changed = wanted_features ^ features;
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_hwdev *hwdev = nic_dev->hwdev;
+ int err;
+
+ if (!(changed & NETIF_F_HW_VLAN_CTAG_FILTER))
+ return 0;
+
+ err = hinic3_set_vlan_fliter(hwdev, en);
+ if (err) {
+ dev_err(hwdev->dev, "%s rx vlan filter failed\n",
+ SET_FEATURES_OP_STR(en));
+ *failed_features |= 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 = 0;
+ int err;
+
+ err = set_feature_rx_csum(netdev, wanted, curr, &failed) |
+ set_feature_tso(netdev, wanted, curr, &failed) |
+ set_feature_lro(netdev, wanted, curr, &failed) |
+ set_feature_rx_cvlan(netdev, wanted, curr, &failed) |
+ set_feature_vlan_filter(netdev, wanted, curr, &failed);
+ if (err) {
+ netdev->features = wanted ^ failed;
+ return -EIO;
+ }
+
+ 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 = features;
+
+ /* If Rx checksum is disabled, then LRO should also be disabled */
+ if (!(features_tmp & NETIF_F_RXCSUM))
+ features_tmp &= ~NETIF_F_LRO;
+
+ return features_tmp;
+}
+
+int hinic3_set_hw_features(struct net_device *netdev)
+{
+ netdev_features_t wanted, curr;
+
+ wanted = netdev->features;
+ /* fake current features so all wanted are enabled */
+ curr = ~wanted;
+
+ return hinic3_set_features(netdev, curr, wanted);
+}
+
static int hinic3_change_mtu(struct net_device *netdev, int new_mtu)
{
int err;
@@ -517,11 +687,159 @@ static int hinic3_set_mac_addr(struct net_device *netdev, void *addr)
return 0;
}
+static int hinic3_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ unsigned long *vlan_bitmap = nic_dev->vlan_bitmap;
+ u32 column, row;
+ u16 func_id;
+ int err;
+
+ column = VID_COL(nic_dev, vid);
+ row = VID_LINE(nic_dev, vid);
+
+ func_id = hinic3_global_func_id(nic_dev->hwdev);
+
+ err = 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 = netdev_priv(netdev);
+ unsigned long *vlan_bitmap = nic_dev->vlan_bitmap;
+ u32 column, row;
+ u16 func_id;
+ int err;
+
+ column = VID_COL(nic_dev, vid);
+ row = VID_LINE(nic_dev, vid);
+
+ func_id = hinic3_global_func_id(nic_dev->hwdev);
+ err = hinic3_del_vlan(nic_dev->hwdev, vid, func_id);
+ if (err) {
+ netdev_err(netdev, "Failed to delete vlan\n");
+ 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 txqueue)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic3_io_queue *sq;
+ bool hw_err = false;
+ u16 sw_pi, hw_ci;
+ u8 q_id;
+
+ HINIC3_NIC_STATS_INC(nic_dev, netdev_tx_timeout);
+ netdev_err(netdev, "Tx timeout\n");
+
+ for (q_id = 0; q_id < nic_dev->q_params.num_qps; q_id++) {
+ if (!netif_xmit_stopped(netdev_get_tx_queue(netdev, q_id)))
+ continue;
+
+ sq = nic_dev->txqs[q_id].sq;
+ sw_pi = hinic3_get_sq_local_pi(sq);
+ hw_ci = 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",
+ q_id, sw_pi, hw_ci, hinic3_get_sq_local_ci(sq),
+ nic_dev->q_params.irq_cfg[q_id].napi.state);
+
+ if (sw_pi != hw_ci)
+ hw_err = true;
+ }
+
+ if (hw_err)
+ 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 = 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 = 0;
+ packets = 0;
+ dropped = 0;
+ for (i = 0; i < nic_dev->max_qps; i++) {
+ if (!nic_dev->txqs)
+ break;
+
+ txq = &nic_dev->txqs[i];
+ txq_stats = &txq->txq_stats;
+ do {
+ start = u64_stats_fetch_begin(&txq_stats->syncp);
+ bytes += txq_stats->bytes;
+ packets += txq_stats->packets;
+ dropped += txq_stats->dropped;
+ } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
+ }
+ stats->tx_packets = packets;
+ stats->tx_bytes = bytes;
+ stats->tx_dropped = dropped;
+
+ bytes = 0;
+ packets = 0;
+ errors = 0;
+ dropped = 0;
+ for (i = 0; i < nic_dev->max_qps; i++) {
+ if (!nic_dev->rxqs)
+ break;
+
+ rxq = &nic_dev->rxqs[i];
+ rxq_stats = &rxq->rxq_stats;
+ do {
+ start = u64_stats_fetch_begin(&rxq_stats->syncp);
+ bytes += rxq_stats->bytes;
+ packets += rxq_stats->packets;
+ errors += rxq_stats->csum_errors +
+ rxq_stats->other_errors;
+ dropped += rxq_stats->dropped;
+ } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
+ }
+ stats->rx_packets = packets;
+ stats->rx_bytes = bytes;
+ stats->rx_errors = errors;
+ stats->rx_dropped = dropped;
+}
+
static const struct net_device_ops hinic3_netdev_ops = {
.ndo_open = hinic3_open,
.ndo_stop = hinic3_close,
+ .ndo_set_features = hinic3_ndo_set_features,
+ .ndo_fix_features = hinic3_fix_features,
.ndo_change_mtu = hinic3_change_mtu,
.ndo_set_mac_address = hinic3_set_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_vlan_rx_add_vid = hinic3_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = hinic3_vlan_rx_kill_vid,
+ .ndo_tx_timeout = hinic3_tx_timeout,
+ .ndo_get_stats64 = hinic3_get_stats64,
.ndo_start_xmit = 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 1ed266d5d40c..fb2437bce1ed 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"
+#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)
{
@@ -57,6 +60,136 @@ bool hinic3_test_support(struct hinic3_nic_dev *nic_dev,
return (nic_dev->nic_io->feature_cap & feature_bits) == feature_bits;
}
+static int hinic3_set_rx_lro(struct hinic3_hwdev *hwdev, u8 ipv4_en, u8 ipv6_en,
+ u8 lro_max_pkt_len)
+{
+ struct l2nic_cmd_lro_config lro_cfg = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ lro_cfg.func_id = hinic3_global_func_id(hwdev);
+ lro_cfg.opcode = MGMT_MSG_CMD_OP_SET;
+ lro_cfg.lro_ipv4_en = ipv4_en;
+ lro_cfg.lro_ipv6_en = ipv6_en;
+ lro_cfg.lro_max_pkt_len = lro_max_pkt_len;
+
+ mgmt_msg_params_init_default(&msg_params, &lro_cfg,
+ sizeof(lro_cfg));
+
+ err = 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 -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hinic3_set_rx_lro_timer(struct hinic3_hwdev *hwdev, u32 timer_value)
+{
+ struct l2nic_cmd_lro_timer lro_timer = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ lro_timer.opcode = MGMT_MSG_CMD_OP_SET;
+ lro_timer.timer = timer_value;
+
+ mgmt_msg_params_init_default(&msg_params, &lro_timer,
+ sizeof(lro_timer));
+
+ err = 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 -EINVAL;
+ }
+
+ 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 = lro_en ? 1 : 0;
+ ipv6_en = lro_en ? 1 : 0;
+
+ dev_dbg(hwdev->dev, "Set LRO max coalesce packet size to %uK\n",
+ lro_max_pkt_len);
+
+ err = 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 = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ vlan_cfg.func_id = hinic3_global_func_id(hwdev);
+ vlan_cfg.vlan_offload = en;
+
+ mgmt_msg_params_init_default(&msg_params, &vlan_cfg,
+ sizeof(vlan_cfg));
+
+ err = 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 -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic3_set_vlan_fliter(struct hinic3_hwdev *hwdev, u32 vlan_filter_ctrl)
+{
+ struct l2nic_cmd_set_vlan_filter vlan_filter;
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ vlan_filter.func_id = hinic3_global_func_id(hwdev);
+ vlan_filter.vlan_filter_ctrl = vlan_filter_ctrl;
+
+ mgmt_msg_params_init_default(&msg_params, &vlan_filter,
+ sizeof(vlan_filter));
+
+ err = 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 -EINVAL;
+ }
+
+ return 0;
+}
+
void hinic3_update_nic_feature(struct hinic3_nic_dev *nic_dev, u64 feature_cap)
{
nic_dev->nic_io->feature_cap = feature_cap;
@@ -362,6 +495,44 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev)
return pkt_drop.msg_head.status;
}
+static int hinic3_config_vlan(struct hinic3_hwdev *hwdev,
+ u8 opcode, u16 vlan_id, u16 func_id)
+{
+ struct l2nic_cmd_vlan_config vlan_info = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ vlan_info.opcode = opcode;
+ vlan_info.func_id = func_id;
+ vlan_info.vlan_id = vlan_id;
+
+ mgmt_msg_params_init_default(&msg_params, &vlan_info,
+ sizeof(vlan_info));
+
+ err = 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 == MGMT_MSG_CMD_OP_ADD ? "add" : "delete",
+ err, vlan_info.msg_head.status);
+ return -EINVAL;
+ }
+
+ 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 = {};
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
index d4326937db48..bb7c2a67dd4b 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);
+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_fliter(struct hinic3_hwdev *hwdev, u32 vlan_filter_ctrl);
+
int hinic3_init_function_table(struct hinic3_nic_dev *nic_dev);
int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu);
@@ -78,5 +83,7 @@ int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable);
int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_up);
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);
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
index 3a9f3ccdb684..b628294b375c 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
@@ -4,15 +4,42 @@
#ifndef _HINIC3_NIC_DEV_H_
#define _HINIC3_NIC_DEV_H_
+#include <linux/if_vlan.h>
#include <linux/netdevice.h>
#include "hinic3_hw_cfg.h"
+#include "hinic3_hwdev.h"
#include "hinic3_mgmt_interface.h"
+#define HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev) (sizeof(*(nic_dev)->vlan_bitmap))
+#define HINIC3_VLAN_BITMAP_SIZE(nic_dev) \
+ (VLAN_N_VID / HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev))
+#define HINIC3_MODERATONE_DELAY HZ
+
enum hinic3_flags {
HINIC3_RSS_ENABLE,
};
+enum hinic3_event_work_flags {
+ HINIC3_EVENT_WORK_TX_TIMEOUT,
+};
+
+#define HINIC3_NIC_STATS_INC(nic_dev, field) \
+do { \
+ u64_stats_update_begin(&(nic_dev)->stats.syncp); \
+ (nic_dev)->stats.field++; \
+ u64_stats_update_end(&(nic_dev)->stats.syncp); \
+} while (0)
+
+struct hinic3_nic_stats {
+ u64 netdev_tx_timeout;
+
+ /* Subdivision statistics show in private tool */
+ u64 tx_carrier_off_drop;
+ u64 tx_invalid_qid;
+ struct u64_stats_sync syncp;
+};
+
enum hinic3_rss_hash_type {
HINIC3_RSS_HASH_ENGINE_TYPE_XOR = 0,
HINIC3_RSS_HASH_ENGINE_TYPE_TOEP = 1,
@@ -55,6 +82,15 @@ struct hinic3_intr_coal_info {
u8 pending_limit;
u8 coalesce_timer_cfg;
u8 resend_timer_cfg;
+
+ u64 pkt_rate_low;
+ u8 rx_usecs_low;
+ u8 rx_pending_limit_low;
+ u64 pkt_rate_high;
+ u8 rx_usecs_high;
+ u8 rx_pending_limit_high;
+
+ u8 user_set_intr_coal_flag;
};
struct hinic3_nic_dev {
@@ -66,12 +102,14 @@ 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;
struct hinic3_dyna_txrxq_params q_params;
struct hinic3_txq *txqs;
struct hinic3_rxq *rxqs;
+ struct hinic3_nic_stats stats;
enum hinic3_rss_hash_type rss_hash_type;
struct hinic3_rss_type rss_type;
@@ -82,13 +120,20 @@ struct hinic3_nic_dev {
struct msix_entry *qps_msix_entries;
struct hinic3_intr_coal_info *intr_coalesce;
+ unsigned long last_moder_jiffies;
+ struct workqueue_struct *workq;
+ struct delayed_work periodic_work;
+ struct delayed_work moderation_task;
struct semaphore port_state_sem;
+ /* flag bits defined by hinic3_event_work_flags */
+ unsigned long event_flag;
bool link_status_up;
};
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);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.h
index 44ae841a3648..9ab9fa03d80b 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)
+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;
+ struct hinic3_rxq_stats rxq_stats;
u32 cons_idx;
u32 delta;
@@ -80,6 +95,11 @@ struct hinic3_rxq {
struct device *dev; /* device for DMA mapping */
dma_addr_t cqe_start_paddr;
+
+ u64 last_moder_packets;
+ u64 last_moder_bytes;
+ u8 last_coalesc_timer_cfg;
+ u8 last_pending_limit;
} ____cacheline_aligned;
struct hinic3_dyna_rxq_res {
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.h
index 7e1b872ba752..7df7f3fe8061 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;
};
+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,10 @@ struct hinic3_txq {
struct hinic3_tx_info *tx_info;
struct hinic3_io_queue *sq;
+
+ struct hinic3_txq_stats txq_stats;
+ u64 last_moder_packets;
+ u64 last_moder_bytes;
} ____cacheline_aligned;
struct hinic3_dyna_txq_res {
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 4/9] hinic3: Add mac filter ops
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
` (2 preceding siblings ...)
2025-10-15 7:15 ` [PATCH net-next v01 3/9] hinic3: Add NIC configuration ops Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 5/9] hinic3: Add netdev register interfaces Fan Gong
` (4 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
Add ops to support unicast and multicast to filter mac address and
forward packages.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
drivers/net/ethernet/huawei/hinic3/Makefile | 1 +
.../ethernet/huawei/hinic3/hinic3_filter.c | 420 ++++++++++++++++++
.../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 | 32 ++
8 files changed, 516 insertions(+)
diff --git a/drivers/net/ethernet/huawei/hinic3/Makefile b/drivers/net/ethernet/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) += hinic3.o
hinic3-objs := 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/net/ethernet/huawei/hinic3/hinic3_filter.c
new file mode 100644
index 000000000000..cb1d1637cb38
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_filter.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "hinic3_hwif.h"
+#include "hinic3_nic_dev.h"
+#include "hinic3_nic_cfg.h"
+
+static int hinic3_uc_sync(struct net_device *netdev, u8 *addr)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+
+ return hinic3_set_mac(nic_dev->hwdev, addr, 0,
+ hinic3_global_func_id(nic_dev->hwdev));
+}
+
+static int hinic3_uc_unsync(struct net_device *netdev, u8 *addr)
+{
+ struct hinic3_nic_dev *nic_dev = 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 = 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 == HINIC3_MAC_HW_SYNCED)
+ hinic3_uc_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 == HINIC3_MAC_HW_SYNCED)
+ hinic3_uc_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 = netdev_priv(netdev);
+ struct hinic3_mac_filter *f;
+
+ f = 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 = 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 = netdev_priv(netdev);
+
+ set_bit(HINIC3_MAC_FILTER_CHANGED, &nic_dev->flags);
+
+ if (f->state == HINIC3_MAC_WAIT_HW_SYNC) {
+ /* have not added to hw, delete it directly */
+ list_del(&f->list);
+ kfree(f);
+ return;
+ }
+
+ f->state = 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 = kzalloc(sizeof(*f), GFP_ATOMIC);
+ if (!f)
+ return NULL;
+
+ *f = *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 == HINIC3_MAC_HW_SYNCED)
+ f->state = 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 = hinic3_find_mac(filter_list, f->addr);
+ if (tmp && tmp->state == HINIC3_MAC_HW_SYNCED)
+ tmp->state = 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)
+{
+ struct hinic3_mac_filter *ftmp;
+ struct hinic3_mac_filter *f;
+ int err, add_count = 0;
+
+ if (!list_empty(del_list)) {
+ list_for_each_entry_safe(f, ftmp, del_list, list) {
+ /* ignore errors when deleting mac */
+ hinic3_uc_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) {
+ err = hinic3_uc_sync(netdev, f->addr);
+ if (err) {
+ netdev_err(netdev, "Failed to add mac\n");
+ return err;
+ }
+
+ add_count++;
+ list_del(&f->list);
+ kfree(f);
+ }
+ }
+
+ return add_count;
+}
+
+static int hinic3_mac_filter_sync(struct net_device *netdev,
+ struct list_head *mac_filter_list, bool uc)
+{
+ struct hinic3_nic_dev *nic_dev = 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 = 0, add_count;
+
+ 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 != HINIC3_MAC_WAIT_HW_UNSYNC)
+ continue;
+
+ f->state = 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 != HINIC3_MAC_WAIT_HW_SYNC)
+ continue;
+
+ fclone = hinic3_mac_filter_entry_clone(f);
+ if (!fclone) {
+ err = -ENOMEM;
+ break;
+ }
+
+ f->state = HINIC3_MAC_HW_SYNCED;
+ list_add_tail(&fclone->list, &tmp_add_list);
+ }
+
+ if (err) {
+ 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");
+
+ hinic3_cleanup_filter_list(&tmp_del_list);
+ hinic3_cleanup_filter_list(&tmp_add_list);
+ goto err_out;
+ }
+
+ add_count = hinic3_mac_filter_sync_hw(netdev, &tmp_del_list,
+ &tmp_add_list);
+ if (!list_empty(&tmp_add_list)) {
+ /* 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 != HINIC3_MAC_HW_SYNCED)
+ continue;
+
+ fclone = hinic3_mac_filter_entry_clone(f);
+ if (!fclone)
+ break;
+
+ f->state = HINIC3_MAC_WAIT_HW_SYNC;
+ list_add_tail(&fclone->list, &tmp_del_list);
+ }
+ }
+
+ hinic3_cleanup_filter_list(&tmp_add_list);
+ hinic3_mac_filter_sync_hw(netdev, &tmp_del_list, &tmp_add_list);
+
+ /* need to enter promiscuous/allmulti mode */
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ return add_count;
+
+err_out:
+ return err;
+}
+
+static void hinic3_mac_filter_sync_all(struct net_device *netdev)
+{
+ struct hinic3_nic_dev *nic_dev = 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 = 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 = 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 = hinic3_find_mac(filter_list, ha->addr);
+ if (!filter)
+ hinic3_add_filter(netdev, filter_list, ha->addr);
+ else if (filter->state == HINIC3_MAC_WAIT_HW_UNSYNC)
+ filter->state = 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 = false;
+
+ netif_addr_lock_bh(netdev);
+ netdev_hw_addr_list_for_each(ha, src_list)
+ if (ether_addr_equal(ha->addr, f->addr)) {
+ found = true;
+ break;
+ }
+ netif_addr_unlock_bh(netdev);
+
+ if (found)
+ continue;
+
+ hinic3_del_filter(netdev, f);
+ }
+}
+
+static void update_mac_filter(struct net_device *netdev)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(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);
+ }
+}
+
+static void sync_rx_mode_to_hw(struct net_device *netdev, int promisc_en,
+ int allmulti_en)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ u32 rx_mod = HINIC3_DEFAULT_RX_MODE;
+ int err;
+
+ rx_mod |= (promisc_en ? L2NIC_RX_MODE_PROMISC : 0);
+ rx_mod |= (allmulti_en ? L2NIC_RX_MODE_MC_ALL : 0);
+
+ if (promisc_en != 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 !=
+ test_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state))
+ netdev_dbg(netdev, "%s all_multi mode\n",
+ allmulti_en ? "Enter" : "Left");
+
+ err = hinic3_set_rx_mode(nic_dev->hwdev, rx_mod);
+ 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 = 0, allmulti_en = 0;
+ struct hinic3_nic_dev *nic_dev;
+ struct net_device *netdev;
+
+ nic_dev = container_of(work, struct hinic3_nic_dev, rx_mode_work);
+ netdev = nic_dev->netdev;
+
+ update_mac_filter(netdev);
+
+ hinic3_mac_filter_sync_all(netdev);
+
+ if (hinic3_test_support(nic_dev, HINIC3_NIC_F_PROMISC))
+ promisc_en = !!(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 = !!(netdev->flags & IFF_ALLMULTI) ||
+ test_bit(HINIC3_ALLMULTI_FORCE_ON,
+ &nic_dev->rx_mod_state);
+
+ if (promisc_en != test_bit(HINIC3_HW_PROMISC_ON, &nic_dev->rx_mod_state) ||
+ allmulti_en != test_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state))
+ 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 baedf1589a49..6b8cca66f0e9 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
@@ -154,6 +154,10 @@ static int hinic3_init_nic_dev(struct net_device *netdev,
INIT_DELAYED_WORK(&nic_dev->periodic_work,
hinic3_periodic_work_handler);
+ 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;
}
@@ -220,6 +224,7 @@ static void hinic3_sw_uninit(struct net_device *netdev)
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
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);
@@ -408,6 +413,7 @@ static void hinic3_nic_remove(struct auxiliary_device *adev)
unregister_netdev(netdev);
cancel_delayed_work_sync(&nic_dev->periodic_work);
+ cancel_work_sync(&nic_dev->rx_mode_work);
destroy_workqueue(nic_dev->workq);
hinic3_update_nic_feature(nic_dev, 0);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
index 68dfdfa1b1ba..a69778b09c83 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];
};
+/* *
+ * 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 = 5,
L2NIC_CMD_SET_VPORT_ENABLE = 6,
+ L2NIC_CMD_SET_RX_MODE = 7,
L2NIC_CMD_SET_SQ_CI_ATTR = 8,
L2NIC_CMD_CLEAR_QP_RESOURCE = 11,
L2NIC_CMD_CFG_RX_LRO = 13,
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
index 0cc2fcf3efa5..e749bc09c493 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
@@ -828,6 +828,20 @@ static void hinic3_get_stats64(struct net_device *netdev,
stats->rx_dropped = dropped;
}
+static void hinic3_nic_set_rx_mode(struct net_device *netdev)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+
+ if (netdev_uc_count(netdev) != nic_dev->netdev_uc_cnt ||
+ netdev_mc_count(netdev) != nic_dev->netdev_mc_cnt) {
+ set_bit(HINIC3_UPDATE_MAC_FILTER, &nic_dev->flags);
+ nic_dev->netdev_uc_cnt = netdev_uc_count(netdev);
+ nic_dev->netdev_mc_cnt = netdev_mc_count(netdev);
+ }
+
+ queue_work(nic_dev->workq, &nic_dev->rx_mode_work);
+}
+
static const struct net_device_ops hinic3_netdev_ops = {
.ndo_open = hinic3_open,
.ndo_stop = hinic3_close,
@@ -840,6 +854,7 @@ static const struct net_device_ops hinic3_netdev_ops = {
.ndo_vlan_rx_kill_vid = hinic3_vlan_rx_kill_vid,
.ndo_tx_timeout = hinic3_tx_timeout,
.ndo_get_stats64 = hinic3_get_stats64,
+ .ndo_set_rx_mode = hinic3_nic_set_rx_mode,
.ndo_start_xmit = 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 fb2437bce1ed..7bfd7967967d 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
@@ -495,6 +495,30 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev)
return pkt_drop.msg_head.status;
}
+int hinic3_set_rx_mode(struct hinic3_hwdev *hwdev, u32 enable)
+{
+ struct l2nic_rx_mode_config rx_mode_cfg = {};
+ struct mgmt_msg_params msg_params = {};
+ int err;
+
+ rx_mode_cfg.func_id = hinic3_global_func_id(hwdev);
+ rx_mode_cfg.rx_mode = enable;
+
+ mgmt_msg_params_init_default(&msg_params, &rx_mode_cfg,
+ sizeof(rx_mode_cfg));
+
+ err = 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 -EINVAL;
+ }
+
+ 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 bb7c2a67dd4b..2c129de241eb 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 enable);
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 b628294b375c..508e3f047d19 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
@@ -17,7 +17,9 @@
#define HINIC3_MODERATONE_DELAY HZ
enum hinic3_flags {
+ HINIC3_MAC_FILTER_CHANGED,
HINIC3_RSS_ENABLE,
+ HINIC3_UPDATE_MAC_FILTER,
};
enum hinic3_event_work_flags {
@@ -40,6 +42,26 @@ struct hinic3_nic_stats {
struct u64_stats_sync syncp;
};
+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_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 = 0,
HINIC3_RSS_HASH_ENGINE_TYPE_TOEP = 1,
@@ -125,8 +147,15 @@ struct hinic3_nic_dev {
struct workqueue_struct *workq;
struct delayed_work periodic_work;
struct delayed_work moderation_task;
+ struct work_struct rx_mode_work;
struct semaphore port_state_sem;
+ 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;
@@ -137,4 +166,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);
+void hinic3_set_rx_mode_work(struct work_struct *work);
+void hinic3_clean_mac_list_filter(struct net_device *netdev);
+
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 5/9] hinic3: Add netdev register interfaces
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
` (3 preceding siblings ...)
2025-10-15 7:15 ` [PATCH net-next v01 4/9] hinic3: Add mac filter ops Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 20:10 ` Jakub Kicinski
2025-10-15 7:15 ` [PATCH net-next v01 6/9] hinic3: Fix netif_queue_set_napi queue_index parameter passing error Fan Gong
` (3 subsequent siblings)
8 siblings, 1 reply; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
Add netdev notifier to accept netdev event.
Refine port event type to change link status.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
.../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 9 +
.../net/ethernet/huawei/hinic3/hinic3_irq.c | 2 +
.../net/ethernet/huawei/hinic3/hinic3_main.c | 181 +++++++++++++++++-
.../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, 220 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h
index 3bed3215bbbc..84b56af74aec 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 = 1
};
+enum hinic3_comm_event_type {
+ HINIC3_COMM_EVENT_PCIE_LINK_DOWN = 0,
+ HINIC3_COMM_EVENT_HEART_LOST = 1,
+ HINIC3_COMM_EVENT_FAULT = 2,
+ HINIC3_COMM_EVENT_SRIOV_STATE_CHANGE = 3,
+ HINIC3_COMM_EVENT_CARD_REMOVE = 4,
+ HINIC3_COMM_EVENT_MGMT_WATCHDOG = 5,
+};
+
enum hinic3_fault_err_level {
HINIC3_FAULT_LEVEL_SERIOUS_FLR = 3,
};
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
index ac79b8bf9b56..6898aa34b4e1 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
@@ -212,6 +212,8 @@ static void hinic3_auto_moderation_work(struct work_struct *work)
nic_dev = container_of(delay, struct hinic3_nic_dev, moderation_task);
period = (unsigned long)(jiffies - nic_dev->last_moder_jiffies);
netdev = nic_dev->netdev;
+ if (!test_bit(HINIC3_INTF_UP, &nic_dev->flags))
+ return;
queue_delayed_work(nic_dev->workq, &nic_dev->moderation_task,
HINIC3_MODERATONE_DELAY);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index 6b8cca66f0e9..b9b6cb825357 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
@@ -29,6 +29,66 @@
#define HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG 25
#define HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG 7
+#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)
+
+static int hinic3_netdev_event(struct notifier_block *notifier,
+ unsigned long event, void *ptr);
+
+/* used for netdev notifier register/unregister */
+static DEFINE_MUTEX(hinic3_netdev_notifiers_mutex);
+static int hinic3_netdev_notifiers_ref_cnt;
+static struct notifier_block hinic3_netdev_notifier = {
+ .notifier_call = hinic3_netdev_event,
+};
+
+static u16 hinic3_get_vlan_depth(struct net_device *netdev)
+{
+ u16 vlan_depth = 0;
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+ while (is_vlan_dev(netdev)) {
+ netdev = 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 = netdev_notifier_info_to_dev(ptr);
+ u16 vlan_depth;
+
+ if (!is_vlan_dev(ndev))
+ return NOTIFY_DONE;
+
+ dev_hold(ndev);
+
+ switch (event) {
+ case NETDEV_REGISTER:
+ vlan_depth = hinic3_get_vlan_depth(ndev);
+ if (vlan_depth == HINIC3_MAX_VLAN_DEPTH_OFFLOAD_SUPPORT) {
+ ndev->vlan_features &= (~HINIC3_VLAN_CLEAR_OFFLOAD);
+ } else if (vlan_depth > HINIC3_MAX_VLAN_DEPTH_OFFLOAD_SUPPORT) {
+ ndev->hw_features &= (~HINIC3_VLAN_CLEAR_OFFLOAD);
+ ndev->features &= (~HINIC3_VLAN_CLEAR_OFFLOAD);
+ }
+
+ break;
+
+ default:
+ break;
+ };
+
+ dev_put(ndev);
+
+ return NOTIFY_DONE;
+}
+
static void init_intr_coal_param(struct net_device *netdev)
{
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
@@ -161,6 +221,14 @@ static int hinic3_init_nic_dev(struct net_device *netdev,
return 0;
}
+static void hinic3_free_nic_dev(struct net_device *netdev)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+
+ destroy_workqueue(nic_dev->workq);
+ kfree(nic_dev->vlan_bitmap);
+}
+
static int hinic3_sw_init(struct net_device *netdev)
{
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
@@ -238,6 +306,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 = netdev_priv(netdev);
+ netdev_features_t hw_features = 0;
+ netdev_features_t vlan_fts = 0;
netdev_features_t cso_fts = 0;
netdev_features_t tso_fts = 0;
netdev_features_t dft_fts;
@@ -250,7 +320,29 @@ static void netdev_feature_init(struct net_device *netdev)
if (hinic3_test_support(nic_dev, HINIC3_NIC_F_TSO))
tso_fts |= NETIF_F_TSO | NETIF_F_TSO6;
- netdev->features |= 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 |= 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 |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
+ if (hinic3_test_support(nic_dev, HINIC3_NIC_F_VXLAN_OFFLOAD))
+ tso_fts |= 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 |= NETIF_F_LRO;
+
+ netdev->features |= dft_fts | cso_fts | tso_fts | vlan_fts;
+ netdev->vlan_features |= dft_fts | cso_fts | tso_fts;
+ hw_features |= netdev->hw_features | netdev->features;
+ netdev->hw_features = hw_features;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
+ netdev->hw_enc_features |= dft_fts;
+ if (hinic3_test_support(nic_dev, HINIC3_NIC_F_VXLAN_OFFLOAD))
+ netdev->hw_enc_features |= cso_fts | tso_fts | NETIF_F_TSO_ECN;
}
static int hinic3_set_default_hw_feature(struct net_device *netdev)
@@ -275,6 +367,36 @@ static int hinic3_set_default_hw_feature(struct net_device *netdev)
return 0;
}
+static void hinic3_register_notifier(struct net_device *netdev)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ int err;
+
+ mutex_lock(&hinic3_netdev_notifiers_mutex);
+ hinic3_netdev_notifiers_ref_cnt++;
+ if (hinic3_netdev_notifiers_ref_cnt == 1) {
+ err = 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 == 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)
{
@@ -297,6 +419,42 @@ static void hinic3_link_status_change(struct net_device *netdev,
}
}
+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] = { "Unrecognized module" };
+ struct hinic3_port_module_event *module_event;
+ enum port_module_event_type type;
+ enum link_err_type err_type;
+
+ module_event = (struct hinic3_port_module_event *)event->event_data;
+ type = module_event->type;
+ err_type = 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 == HINIC3_PORT_MODULE_CABLE_PLUGGED ?
+ "plugged" : "unplugged");
+ break;
+ case HINIC3_PORT_MODULE_LINK_ERR:
+ if (err_type >= 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)
{
@@ -310,8 +468,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:
@@ -359,7 +529,7 @@ static int hinic3_nic_probe(struct auxiliary_device *adev,
err = hinic3_init_nic_io(nic_dev);
if (err)
- goto err_free_netdev;
+ goto err_free_nic_dev;
err = hinic3_sw_init(netdev);
if (err)
@@ -372,6 +542,8 @@ static int hinic3_nic_probe(struct auxiliary_device *adev,
if (err)
goto err_uninit_sw;
+ hinic3_register_notifier(netdev);
+
queue_delayed_work(nic_dev->workq, &nic_dev->periodic_work, HZ);
netif_carrier_off(netdev);
@@ -382,6 +554,7 @@ static int hinic3_nic_probe(struct auxiliary_device *adev,
return 0;
err_uninit_nic_feature:
+ hinic3_unregister_notifier();
hinic3_update_nic_feature(nic_dev, 0);
hinic3_set_nic_feature_to_hw(nic_dev);
@@ -390,7 +563,8 @@ static int hinic3_nic_probe(struct auxiliary_device *adev,
err_free_nic_io:
hinic3_free_nic_io(nic_dev);
-
+err_free_nic_dev:
+ hinic3_free_nic_dev(netdev);
err_free_netdev:
free_netdev(netdev);
@@ -411,6 +585,7 @@ static void hinic3_nic_remove(struct auxiliary_device *adev)
netdev = nic_dev->netdev;
unregister_netdev(netdev);
+ hinic3_unregister_notifier();
cancel_delayed_work_sync(&nic_dev->periodic_work);
cancel_work_sync(&nic_dev->rx_mode_work);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
index e749bc09c493..f2a6cdab3d37 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
@@ -435,6 +435,11 @@ static int hinic3_open(struct net_device *netdev)
struct hinic3_dyna_qp_params qp_params;
int err;
+ if (test_bit(HINIC3_INTF_UP, &nic_dev->flags)) {
+ netdev_dbg(netdev, "Netdev already open, do nothing\n");
+ return 0;
+ }
+
err = hinic3_init_nicio_res(nic_dev);
if (err) {
netdev_err(netdev, "Failed to init nicio resources\n");
@@ -462,6 +467,8 @@ static int hinic3_open(struct net_device *netdev)
if (err)
goto err_close_channel;
+ set_bit(HINIC3_INTF_UP, &nic_dev->flags);
+
return 0;
err_close_channel:
@@ -482,6 +489,11 @@ static int hinic3_close(struct net_device *netdev)
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
struct hinic3_dyna_qp_params qp_params;
+ 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 2c129de241eb..d7a299fb2d51 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 = 0,
HINIC3_NIC_EVENT_LINK_UP = 1,
+ HINIC3_NIC_EVENT_PORT_MODULE_EVENT = 2,
};
struct hinic3_sq_attr {
@@ -51,6 +52,23 @@ struct mag_cmd_set_port_enable {
u8 rsvd1[3];
};
+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 508e3f047d19..d3ea31faf333 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
@@ -17,6 +17,7 @@
#define HINIC3_MODERATONE_DELAY HZ
enum hinic3_flags {
+ HINIC3_INTF_UP,
HINIC3_MAC_FILTER_CHANGED,
HINIC3_RSS_ENABLE,
HINIC3_UPDATE_MAC_FILTER,
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 6/9] hinic3: Fix netif_queue_set_napi queue_index parameter passing error
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
` (4 preceding siblings ...)
2025-10-15 7:15 ` [PATCH net-next v01 5/9] hinic3: Add netdev register interfaces Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 7/9] hinic3: Fix code Style(remove empty lines between error handling) Fan Gong
` (2 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
Incorrectly transmitted interrupt number instead of queue number
when using netif_queue_set_napi. Besides, move this to appropriate
code location.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
.../net/ethernet/huawei/hinic3/hinic3_irq.c | 21 ++++++++++---------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
index 6898aa34b4e1..d2c131f2c43a 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
@@ -46,21 +46,12 @@ static void qp_add_napi(struct hinic3_irq_cfg *irq_cfg)
struct hinic3_nic_dev *nic_dev = netdev_priv(irq_cfg->netdev);
netif_napi_add(nic_dev->netdev, &irq_cfg->napi, hinic3_poll);
- netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id,
- NETDEV_QUEUE_TYPE_RX, &irq_cfg->napi);
- netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id,
- NETDEV_QUEUE_TYPE_TX, &irq_cfg->napi);
napi_enable(&irq_cfg->napi);
}
static void qp_del_napi(struct hinic3_irq_cfg *irq_cfg)
{
napi_disable(&irq_cfg->napi);
- netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id,
- NETDEV_QUEUE_TYPE_RX, NULL);
- netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id,
- NETDEV_QUEUE_TYPE_TX, NULL);
- netif_stop_subqueue(irq_cfg->netdev, irq_cfg->irq_id);
netif_napi_del(&irq_cfg->napi);
}
@@ -281,6 +272,11 @@ int hinic3_qps_irq_init(struct net_device *netdev)
goto err_release_irqs;
}
+ netif_queue_set_napi(irq_cfg->netdev, q_id,
+ NETDEV_QUEUE_TYPE_RX, &irq_cfg->napi);
+ netif_queue_set_napi(irq_cfg->netdev, q_id,
+ NETDEV_QUEUE_TYPE_TX, &irq_cfg->napi);
+
hinic3_set_msix_auto_mask_state(nic_dev->hwdev,
irq_cfg->msix_entry_idx,
HINIC3_SET_MSIX_AUTO_MASK);
@@ -317,12 +313,17 @@ void hinic3_qps_irq_uninit(struct net_device *netdev)
for (q_id = 0; q_id < nic_dev->q_params.num_qps; q_id++) {
irq_cfg = &nic_dev->q_params.irq_cfg[q_id];
- qp_del_napi(irq_cfg);
hinic3_set_msix_state(nic_dev->hwdev, irq_cfg->msix_entry_idx,
HINIC3_MSIX_DISABLE);
hinic3_set_msix_auto_mask_state(nic_dev->hwdev,
irq_cfg->msix_entry_idx,
HINIC3_CLR_MSIX_AUTO_MASK);
hinic3_release_irq(irq_cfg);
+ qp_del_napi(irq_cfg);
+
+ netif_queue_set_napi(irq_cfg->netdev, q_id,
+ NETDEV_QUEUE_TYPE_RX, NULL);
+ netif_queue_set_napi(irq_cfg->netdev, q_id,
+ NETDEV_QUEUE_TYPE_TX, NULL);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 7/9] hinic3: Fix code Style(remove empty lines between error handling)
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
` (5 preceding siblings ...)
2025-10-15 7:15 ` [PATCH net-next v01 6/9] hinic3: Fix netif_queue_set_napi queue_index parameter passing error Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 8/9] hinic3: Remove redundant defensive code Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 9/9] hinic3: Use array_size instead of multiplying Fan Gong
8 siblings, 0 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
Fix code style of removing empty lines between the actions on the
error handling path.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c | 3 ---
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c | 1 -
drivers/net/ethernet/huawei/hinic3/hinic3_lld.c | 5 -----
drivers/net/ethernet/huawei/hinic3/hinic3_main.c | 4 ----
drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c | 2 --
drivers/net/ethernet/huawei/hinic3/hinic3_tx.c | 1 -
6 files changed, 16 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c
index ef539d1b69a3..86720bb119e9 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c
@@ -878,14 +878,11 @@ int hinic3_cmdqs_init(struct hinic3_hwdev *hwdev)
}
hinic3_free_db_addr(hwdev, cmdqs->cmdqs_db_base);
-
err_destroy_cmdq_wq:
destroy_cmdq_wq(hwdev, cmdqs);
-
err_free_cmdqs:
dma_pool_destroy(cmdqs->cmd_buf_pool);
kfree(cmdqs);
-
err_out:
return err;
}
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
index 01686472985b..55bfbe568fdc 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
@@ -686,7 +686,6 @@ int hinic3_aeqs_init(struct hinic3_hwdev *hwdev, u16 num_aeqs,
}
destroy_workqueue(aeqs->workq);
-
err_free_aeqs:
kfree(aeqs);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c b/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c
index 6ae7c9f13932..67b509b98d4c 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c
@@ -247,7 +247,6 @@ static int hinic3_mapping_bar(struct pci_dev *pdev,
iounmap(pci_adapter->mgmt_reg_base);
err_unmap_intr_reg_base:
iounmap(pci_adapter->intr_reg_base);
-
err_unmap_cfg_reg_base:
iounmap(pci_adapter->cfg_reg_base);
@@ -302,10 +301,8 @@ static int hinic3_pci_init(struct pci_dev *pdev)
err_release_regions:
pci_clear_master(pdev);
pci_release_regions(pdev);
-
err_disable_device:
pci_disable_device(pdev);
-
err_free_pci_adapter:
pci_set_drvdata(pdev, NULL);
mutex_destroy(&pci_adapter->pdev_mutex);
@@ -394,7 +391,6 @@ static int hinic3_probe_func(struct hinic3_pcidev *pci_adapter)
hinic3_func_uninit(pdev);
err_unmap_bar:
hinic3_unmapping_bar(pci_adapter);
-
err_out:
dev_err(&pdev->dev, "PCIe device probe function failed\n");
@@ -427,7 +423,6 @@ static int hinic3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_uninit_pci:
hinic3_pci_uninit(pdev);
-
err_out:
dev_err(&pdev->dev, "PCIe device probe failed\n");
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index b9b6cb825357..3ed149440b1f 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
@@ -154,7 +154,6 @@ static int hinic3_alloc_txrxqs(struct net_device *netdev)
err_free_rxqs:
hinic3_free_rxqs(netdev);
-
err_free_txqs:
hinic3_free_txqs(netdev);
@@ -557,17 +556,14 @@ static int hinic3_nic_probe(struct auxiliary_device *adev,
hinic3_unregister_notifier();
hinic3_update_nic_feature(nic_dev, 0);
hinic3_set_nic_feature_to_hw(nic_dev);
-
err_uninit_sw:
hinic3_sw_uninit(netdev);
-
err_free_nic_io:
hinic3_free_nic_io(nic_dev);
err_free_nic_dev:
hinic3_free_nic_dev(netdev);
err_free_netdev:
free_netdev(netdev);
-
err_unregister_adev_event:
hinic3_adev_event_unregister(adev);
dev_err(&pdev->dev, "NIC service probe failed\n");
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
index a4be5b2984cf..721c46d94442 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
@@ -452,10 +452,8 @@ int hinic3_init_mbox(struct hinic3_hwdev *hwdev)
hinic3_uninit_func_mbox_msg_channel(hwdev);
err_uninit_mgmt_msg_ch:
uninit_mgmt_msg_channel(mbox);
-
err_destroy_workqueue:
destroy_workqueue(mbox->workq);
-
err_free_mbox:
kfree(mbox);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c
index 92c43c05e3f2..59045b231ebe 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c
@@ -582,7 +582,6 @@ static netdev_tx_t hinic3_send_one_skb(struct sk_buff *skb,
err_drop_pkt:
dev_kfree_skb_any(skb);
-
err_out:
return NETDEV_TX_OK;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 8/9] hinic3: Remove redundant defensive code
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
` (6 preceding siblings ...)
2025-10-15 7:15 ` [PATCH net-next v01 7/9] hinic3: Fix code Style(remove empty lines between error handling) Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 9/9] hinic3: Use array_size instead of multiplying Fan Gong
8 siblings, 0 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
According to comment of patch 03, check codes that were merged and
remove redundant defensive codes.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
drivers/net/ethernet/huawei/hinic3/hinic3_tx.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c
index 59045b231ebe..6e2981488175 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_tx.c
@@ -19,16 +19,10 @@
int hinic3_alloc_txqs(struct net_device *netdev)
{
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
- struct hinic3_hwdev *hwdev = nic_dev->hwdev;
u16 q_id, num_txqs = nic_dev->max_qps;
struct pci_dev *pdev = nic_dev->pdev;
struct hinic3_txq *txq;
- if (!num_txqs) {
- dev_err(hwdev->dev, "Cannot allocate zero size txqs\n");
- return -EINVAL;
- }
-
nic_dev->txqs = kcalloc(num_txqs, sizeof(*nic_dev->txqs), GFP_KERNEL);
if (!nic_dev->txqs)
return -ENOMEM;
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v01 9/9] hinic3: Use array_size instead of multiplying
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
` (7 preceding siblings ...)
2025-10-15 7:15 ` [PATCH net-next v01 8/9] hinic3: Remove redundant defensive code Fan Gong
@ 2025-10-15 7:15 ` Fan Gong
8 siblings, 0 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-15 7:15 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai
Cc: netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
According to comment of patch 03, check codes that were merged and
use array_size instead of multiplying.
Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
index 7bfd7967967d..5ab6f3e9fe06 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
@@ -23,7 +23,8 @@ static int hinic3_feature_nego(struct hinic3_hwdev *hwdev, u8 opcode,
feature_nego.func_id = hinic3_global_func_id(hwdev);
feature_nego.opcode = opcode;
if (opcode == MGMT_MSG_CMD_OP_SET)
- memcpy(feature_nego.s_feature, s_feature, size * sizeof(u64));
+ memcpy(feature_nego.s_feature, s_feature,
+ array_size(size, sizeof(u64)));
mgmt_msg_params_init_default(&msg_params, &feature_nego,
sizeof(feature_nego));
@@ -37,7 +38,8 @@ static int hinic3_feature_nego(struct hinic3_hwdev *hwdev, u8 opcode,
}
if (opcode == MGMT_MSG_CMD_OP_GET)
- memcpy(s_feature, feature_nego.s_feature, size * sizeof(u64));
+ memcpy(s_feature, feature_nego.s_feature,
+ array_size(size, sizeof(u64)));
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next 2/9] hinic3: Add PF management interfaces
2025-10-15 7:15 ` [PATCH net-next v01 2/9] hinic3: Add PF management interfaces Fan Gong
@ 2025-10-15 10:00 ` Markus Elfring
2025-10-15 16:46 ` Simon Horman
2025-10-16 8:55 ` Fan Gong
0 siblings, 2 replies; 18+ messages in thread
From: Markus Elfring @ 2025-10-15 10:00 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai, netdev
Cc: linux-doc, LKML, Andrew Lunn, Bjorn Helgaas, Christophe Jaillet,
Jonathan Corbet, David S. Miller, Eric Dumazet, Gur Stavi,
Jakub Kicinski, Joe Damato, Lee Trager, luosifu, luoyang82,
Meny Yossefi, Michael Ellerman, Paolo Abeni, Przemek Kitszel,
Shen Chenyang, Shi Jing, Simon Horman, Suman Ghosh,
Vadim Fedorenko, Wu Like, Xin Guo, Zhou Shuai
> To: Fan Gong …
Please reconsider the distribution of recipient information between message fields
once more.
…
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c
> @@ -3,19 +3,325 @@
…
> +static void mgmt_resp_msg_handler(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt,
> + struct hinic3_recv_msg *recv_msg)
> +{
…
> + spin_lock(&pf_to_mgmt->sync_event_lock);
> + if (recv_msg->msg_id != pf_to_mgmt->sync_msg_id) {
…
> + }
> + spin_unlock(&pf_to_mgmt->sync_event_lock);
> +}
…
Will development interests grow to apply a call like “scoped_guard(spinlock, &pf_to_mgmt->sync_event_lock)”?
https://elixir.bootlin.com/linux/v6.17.1/source/include/linux/spinlock.h#L565-L567
Regards,
Markus
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v01 1/9] hinic3: Add PF framework
2025-10-15 7:15 ` [PATCH net-next v01 1/9] hinic3: Add PF framework Fan Gong
@ 2025-10-15 10:29 ` Pavan Chebbi
2025-10-27 10:00 ` Simon Horman
1 sibling, 0 replies; 18+ messages in thread
From: Pavan Chebbi @ 2025-10-15 10:29 UTC (permalink / raw)
To: Fan Gong
Cc: Zhu Yikai, netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
[-- Attachment #1: Type: text/plain, Size: 7067 bytes --]
On Wed, Oct 15, 2025 at 12:48 PM Fan Gong <gongfan1@huawei.com> wrote:
>
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c
> @@ -314,6 +314,9 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
> ret = -EFAULT;
> }
>
> + if (HINIC3_FUNC_TYPE(hwdev) != HINIC3_FUNC_TYPE_VF)
Is this check needed? Other places hinic3_set_pf_status() is called
without checking. I see the function has an internal check for PF.
> + hinic3_set_pf_status(hwif, HINIC3_PF_STATUS_FLR_START_FLAG);
> +
> clr_res.func_id = hwif->attr.func_global_idx;
> msg_params.buf_in = &clr_res;
> msg_params.in_size = sizeof(clr_res);
> @@ -337,6 +340,54 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
> return ret;
> }
>
> +int hinic3_set_bdf_ctxt(struct hinic3_hwdev *hwdev, u8 bus, u8 device, u8 function)
You could just send *bdf_info as a parameter with values pre-set,
makes it look better
> +{
> + struct comm_cmd_bdf_info bdf_info = {};
> + struct mgmt_msg_params msg_params = {};
> + int err;
> +
> + bdf_info.function_idx = hinic3_global_func_id(hwdev);
> + bdf_info.bus = bus;
> + bdf_info.device = device;
> + bdf_info.function = function;
> +
> + mgmt_msg_params_init_default(&msg_params, &bdf_info, sizeof(bdf_info));
> +
> + err = 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 -EIO;
> + }
> +
> + return 0;
> +}
<-->
> +static void set_ppf(struct hinic3_hwdev *hwdev)
Any particular reason why this function does not have hinic3 prefix?
> +{
> + struct hinic3_hwif *hwif = hwdev->hwif;
> + struct hinic3_func_attr *attr;
> + u32 addr, val;
> +
> + if (HINIC3_IS_VF(hwdev))
> + return;
> +
> + /* Read Modify Write */
> + attr = &hwif->attr;
> + addr = HINIC3_CSR_PPF_ELECTION_ADDR;
> + val = hinic3_hwif_read_reg(hwif, addr);
> + val &= ~HINIC3_PPF_ELECTION_IDX_MASK;
> + val |= HINIC3_PPF_ELECTION_SET(attr->func_global_idx, IDX);
> + hinic3_hwif_write_reg(hwif, addr, val);
> +
> + /* Check PPF index */
> + val = hinic3_hwif_read_reg(hwif, addr);
> + attr->ppf_idx = HINIC3_PPF_ELECTION_GET(val, IDX);
> +}
> +
<-->
> +int hinic3_get_default_mac(struct hinic3_hwdev *hwdev, u8 *mac_addr)
> +{
> + struct l2nic_cmd_set_mac mac_info = {};
> + struct mgmt_msg_params msg_params = {};
> + int err;
> +
> + mac_info.func_id = hinic3_global_func_id(hwdev);
> +
> + mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info));
> +
> + err = 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 -EINVAL;
EINVAL looks odd. I see other places it is -EIO.
> + }
> +
> + ether_addr_copy(mac_addr, mac_info.mac);
> +
> + return 0;
> +}
> +
> int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
> u16 func_id)
> {
> @@ -157,9 +189,9 @@ int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
> return -EIO;
> }
>
> - if (mac_info.msg_head.status == MGMT_STATUS_PF_SET_VF_ALREADY) {
> + if (PF_SET_VF_MAC(hwdev, mac_info.msg_head.status)) {
> dev_warn(hwdev->dev, "PF has already set VF mac, Ignore set operation\n");
> - return 0;
> + return HINIC3_PF_SET_VF_ALREADY;
> }
>
> if (mac_info.msg_head.status == MGMT_STATUS_EXIST) {
> @@ -191,11 +223,17 @@ int hinic3_del_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
>
> err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
> L2NIC_CMD_DEL_MAC, &msg_params);
> - if (err) {
> + if (err || (mac_info.msg_head.status &&
> + !PF_SET_VF_MAC(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 -EIO;
> + }
> +
> + if (PF_SET_VF_MAC(hwdev, mac_info.msg_head.status)) {
> + dev_warn(hwdev->dev, "PF has already set VF mac, Ignore delete operation.\n");
> + return HINIC3_PF_SET_VF_ALREADY;
> }
>
> return 0;
> @@ -231,6 +269,17 @@ int hinic3_update_mac(struct hinic3_hwdev *hwdev, const u8 *old_mac,
> return -EIO;
> }
>
> + if (PF_SET_VF_MAC(hwdev, mac_info.msg_head.status)) {
> + dev_warn(hwdev->dev, "PF has already set VF MAC. Ignore update operation\n");
> + return HINIC3_PF_SET_VF_ALREADY;
> + }
> +
> + if (mac_info.msg_head.status == HINIC3_MGMT_STATUS_EXIST) {
> + dev_warn(hwdev->dev,
> + "MAC is repeated. Ignore update operation\n");
> + return 0;
> + }
> +
> return 0;
> }
>
> 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
>
> #define HINIC3_VLAN_ID_MASK 0x7FFF
> +#define HINIC3_PF_SET_VF_ALREADY 0x4
> +#define HINIC3_MGMT_STATUS_EXIST 0x6
>
> enum hinic3_nic_event_type {
> HINIC3_NIC_EVENT_LINK_DOWN = 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);
>
> +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 vlan_id,
> u16 func_id);
> int hinic3_del_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
> --
> 2.43.0
>
>
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next 2/9] hinic3: Add PF management interfaces
2025-10-15 10:00 ` [PATCH net-next " Markus Elfring
@ 2025-10-15 16:46 ` Simon Horman
2025-10-16 8:55 ` Fan Gong
1 sibling, 0 replies; 18+ messages in thread
From: Simon Horman @ 2025-10-15 16:46 UTC (permalink / raw)
To: Markus Elfring
Cc: Fan Gong, Zhu Yikai, netdev, linux-doc, LKML, Andrew Lunn,
Bjorn Helgaas, Christophe Jaillet, Jonathan Corbet,
David S. Miller, Eric Dumazet, Gur Stavi, Jakub Kicinski,
Joe Damato, Lee Trager, luosifu, luoyang82, Meny Yossefi,
Michael Ellerman, Paolo Abeni, Przemek Kitszel, Shen Chenyang,
Shi Jing, Suman Ghosh, Vadim Fedorenko, Wu Like, Xin Guo,
Zhou Shuai
On Wed, Oct 15, 2025 at 12:00:33PM +0200, Markus Elfring wrote:
> > To: Fan Gong …
>
> Please reconsider the distribution of recipient information between message fields
> once more.
>
>
> …
> > +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c
> > @@ -3,19 +3,325 @@
> …
> > +static void mgmt_resp_msg_handler(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt,
> > + struct hinic3_recv_msg *recv_msg)
> > +{
> …
> > + spin_lock(&pf_to_mgmt->sync_event_lock);
> > + if (recv_msg->msg_id != pf_to_mgmt->sync_msg_id) {
> …
> > + }
> > + spin_unlock(&pf_to_mgmt->sync_event_lock);
> > +}
> …
>
> Will development interests grow to apply a call like “scoped_guard(spinlock, &pf_to_mgmt->sync_event_lock)”?
> https://elixir.bootlin.com/linux/v6.17.1/source/include/linux/spinlock.h#L565-L567
Hi Markus, all.
It's up to the developer. But there is a still a weak preference
for open-coding, as is done above, in Networking code. So in the
absence of some other motivation (I have not reviewed this code)
I would suggest leaving this as-is.
https://docs.kernel.org/process/maintainer-netdev.html#using-device-managed-and-cleanup-h-constructs
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v01 5/9] hinic3: Add netdev register interfaces
2025-10-15 7:15 ` [PATCH net-next v01 5/9] hinic3: Add netdev register interfaces Fan Gong
@ 2025-10-15 20:10 ` Jakub Kicinski
0 siblings, 0 replies; 18+ messages in thread
From: Jakub Kicinski @ 2025-10-15 20:10 UTC (permalink / raw)
To: Fan Gong
Cc: Zhu Yikai, netdev, linux-kernel, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
On Wed, 15 Oct 2025 15:15:31 +0800 Fan Gong wrote:
> +static int hinic3_netdev_event(struct notifier_block *notifier,
> + unsigned long event, void *ptr);
please reorder the code to avoid the fwd declaration
> +/* used for netdev notifier register/unregister */
> +static DEFINE_MUTEX(hinic3_netdev_notifiers_mutex);
> +static int hinic3_netdev_notifiers_ref_cnt;
> +static struct notifier_block hinic3_netdev_notifier = {
> + .notifier_call = hinic3_netdev_event,
> +};
> +
> +static u16 hinic3_get_vlan_depth(struct net_device *netdev)
> +{
> + u16 vlan_depth = 0;
> +
> +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
> + while (is_vlan_dev(netdev)) {
> + netdev = 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 = netdev_notifier_info_to_dev(ptr);
> + u16 vlan_depth;
> +
> + if (!is_vlan_dev(ndev))
> + return NOTIFY_DONE;
> +
> + dev_hold(ndev);
please use netdev_hold()
> + switch (event) {
> + case NETDEV_REGISTER:
> + vlan_depth = hinic3_get_vlan_depth(ndev);
> + if (vlan_depth == HINIC3_MAX_VLAN_DEPTH_OFFLOAD_SUPPORT) {
> + ndev->vlan_features &= (~HINIC3_VLAN_CLEAR_OFFLOAD);
> + } else if (vlan_depth > HINIC3_MAX_VLAN_DEPTH_OFFLOAD_SUPPORT) {
> + ndev->hw_features &= (~HINIC3_VLAN_CLEAR_OFFLOAD);
> + ndev->features &= (~HINIC3_VLAN_CLEAR_OFFLOAD);
> + }
> +
> + break;
> +
> + default:
> + break;
> + };
unnecessary semicolon
> + dev_put(ndev);
--
pw-bot: cr
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next 2/9] hinic3: Add PF management interfaces
2025-10-15 10:00 ` [PATCH net-next " Markus Elfring
2025-10-15 16:46 ` Simon Horman
@ 2025-10-16 8:55 ` Fan Gong
2025-10-16 10:26 ` [net-next " Markus Elfring
1 sibling, 1 reply; 18+ messages in thread
From: Fan Gong @ 2025-10-16 8:55 UTC (permalink / raw)
To: markus.elfring
Cc: andrew+netdev, christophe.jaillet, corbet, davem, edumazet,
gongfan1, guoxin09, gur.stavi, helgaas, horms, jdamato, kuba, lee,
linux-doc, linux-kernel, luosifu, luoyang82, meny.yossefi, mpe,
netdev, pabeni, przemyslaw.kitszel, shenchenyang1, shijing34,
sumang, vadim.fedorenko, wulike1, zhoushuai28, zhuyikai1
On 10/15/2025 6:00 PM, Markus Elfring wrote:
>> To: Fan Gong …
>
> Please reconsider the distribution of recipient information between message fields
> once more.
Hi Markus. Thanks for your comment.
I can't quite understand "the distribution of recipient information between message
fields". Can you explain this further?
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [net-next 2/9] hinic3: Add PF management interfaces
2025-10-16 8:55 ` Fan Gong
@ 2025-10-16 10:26 ` Markus Elfring
2025-10-16 12:46 ` [PATCH net-next " Fan Gong
0 siblings, 1 reply; 18+ messages in thread
From: Markus Elfring @ 2025-10-16 10:26 UTC (permalink / raw)
To: Fan Gong, Zhu Yikai, netdev
Cc: linux-doc, LKML, Andrew Lunn, Bjorn Helgaas, Christophe Jaillet,
David S. Miller, Eric Dumazet, Gur Stavi, Jakub Kicinski,
Joe Damato, Jonathan Corbet, Lee Trager, luosifu, luoyang82,
Meny Yossefi, Michael Ellerman, Paolo Abeni, Przemek Kitszel,
Shen Chenyang, Shi Jing, Simon Horman, Suman Ghosh,
Vadim Fedorenko, Wu Like, Xin Guo, Zhou Shuai
> I can't quite understand "the distribution of recipient information between message
> fields". Can you explain this further?
Can it occasionally be more desirable to specify other recipients
in the field “To” (instead of “Cc”)?
Regards,
Markus
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next 2/9] hinic3: Add PF management interfaces
2025-10-16 10:26 ` [net-next " Markus Elfring
@ 2025-10-16 12:46 ` Fan Gong
0 siblings, 0 replies; 18+ messages in thread
From: Fan Gong @ 2025-10-16 12:46 UTC (permalink / raw)
To: markus.elfring
Cc: andrew+netdev, christophe.jaillet, corbet, davem, edumazet,
gongfan1, guoxin09, gur.stavi, helgaas, horms, jdamato, kuba, lee,
linux-doc, linux-kernel, luosifu, luoyang82, meny.yossefi, mpe,
netdev, pabeni, przemyslaw.kitszel, shenchenyang1, shijing34,
sumang, vadim.fedorenko, wulike1, zhoushuai28, zhuyikai1
On 10/16/2025 6:26 PM, Markus Elfring wrote:
>
> Can it occasionally be more desirable to specify other recipients
> in the field “To” (instead of “Cc”)?
>
> Regards,
> Markus
Thanks for your suggesion. We will adopt your suggestion in next
version.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v01 1/9] hinic3: Add PF framework
2025-10-15 7:15 ` [PATCH net-next v01 1/9] hinic3: Add PF framework Fan Gong
2025-10-15 10:29 ` Pavan Chebbi
@ 2025-10-27 10:00 ` Simon Horman
1 sibling, 0 replies; 18+ messages in thread
From: Simon Horman @ 2025-10-27 10:00 UTC (permalink / raw)
To: Fan Gong
Cc: Zhu Yikai, netdev, linux-kernel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Andrew Lunn, linux-doc,
Jonathan Corbet, Bjorn Helgaas, luosifu, Xin Guo, Shen Chenyang,
Zhou Shuai, Wu Like, Shi Jing, Luo Yang, Meny Yossefi, Gur Stavi,
Lee Trager, Michael Ellerman, Vadim Fedorenko, Suman Ghosh,
Przemek Kitszel, Joe Damato, Christophe JAILLET
On Wed, Oct 15, 2025 at 03:15:27PM +0800, Fan Gong wrote:
> Add support for PF framework based on the VF code.
>
> Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
> Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
> Signed-off-by: Fan Gong <gongfan1@huawei.com>
...
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
> index 979f47ca77f9..2b93026845ff 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
> @@ -117,17 +117,49 @@ int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu)
> &func_tbl_cfg);
> }
>
> +#define PF_SET_VF_MAC(hwdev, status) \
> + (HINIC3_IS_VF(hwdev) && (status) == HINIC3_PF_SET_VF_ALREADY)
> +
nit: I think the above could be a function rather than a macro.
...
> @@ -157,9 +189,9 @@ int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
> return -EIO;
> }
>
> - if (mac_info.msg_head.status == MGMT_STATUS_PF_SET_VF_ALREADY) {
> + if (PF_SET_VF_MAC(hwdev, mac_info.msg_head.status)) {
> dev_warn(hwdev->dev, "PF has already set VF mac, Ignore set operation\n");
> - return 0;
> + return HINIC3_PF_SET_VF_ALREADY;
It seems to me that this custom return value can be propagated up
and returned by the probe function. If so, this doesn't seem desirable.
And, overall, I would recommend against the custom calling convention
that custom return values imply.
> }
>
> if (mac_info.msg_head.status == MGMT_STATUS_EXIST) {
...
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2025-10-27 10:00 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-15 7:15 [PATCH net-next v01 0/9] net: hinic3: Add a driver for Huawei 3rd gen NIC - PF initialization Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 1/9] hinic3: Add PF framework Fan Gong
2025-10-15 10:29 ` Pavan Chebbi
2025-10-27 10:00 ` Simon Horman
2025-10-15 7:15 ` [PATCH net-next v01 2/9] hinic3: Add PF management interfaces Fan Gong
2025-10-15 10:00 ` [PATCH net-next " Markus Elfring
2025-10-15 16:46 ` Simon Horman
2025-10-16 8:55 ` Fan Gong
2025-10-16 10:26 ` [net-next " Markus Elfring
2025-10-16 12:46 ` [PATCH net-next " Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 3/9] hinic3: Add NIC configuration ops Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 4/9] hinic3: Add mac filter ops Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 5/9] hinic3: Add netdev register interfaces Fan Gong
2025-10-15 20:10 ` Jakub Kicinski
2025-10-15 7:15 ` [PATCH net-next v01 6/9] hinic3: Fix netif_queue_set_napi queue_index parameter passing error Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 7/9] hinic3: Fix code Style(remove empty lines between error handling) Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 8/9] hinic3: Remove redundant defensive code Fan Gong
2025-10-15 7:15 ` [PATCH net-next v01 9/9] hinic3: Use array_size instead of multiplying Fan Gong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).