[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <905df406fd870da528361f47c48067802588cfb5.1760502478.git.zhuyikai1@h-partners.com>
Date: Wed, 15 Oct 2025 15:15:27 +0800
From: Fan Gong <gongfan1@...wei.com>
To: Fan Gong <gongfan1@...wei.com>, Zhu Yikai <zhuyikai1@...artners.com>
CC: <netdev@...r.kernel.org>, <linux-kernel@...r.kernel.org>, "David S.
Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>, Jakub
Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>, Simon Horman
<horms@...nel.org>, Andrew Lunn <andrew+netdev@...n.ch>,
<linux-doc@...r.kernel.org>, Jonathan Corbet <corbet@....net>, Bjorn Helgaas
<helgaas@...nel.org>, luosifu <luosifu@...wei.com>, Xin Guo
<guoxin09@...wei.com>, Shen Chenyang <shenchenyang1@...ilicon.com>, Zhou
Shuai <zhoushuai28@...wei.com>, Wu Like <wulike1@...wei.com>, Shi Jing
<shijing34@...wei.com>, Luo Yang <luoyang82@...artners.com>, Meny Yossefi
<meny.yossefi@...wei.com>, Gur Stavi <gur.stavi@...wei.com>, Lee Trager
<lee@...ger.us>, Michael Ellerman <mpe@...erman.id.au>, Vadim Fedorenko
<vadim.fedorenko@...ux.dev>, Suman Ghosh <sumang@...vell.com>, Przemek
Kitszel <przemyslaw.kitszel@...el.com>, Joe Damato <jdamato@...tly.com>,
Christophe JAILLET <christophe.jaillet@...adoo.fr>
Subject: [PATCH net-next v01 1/9] hinic3: Add PF framework
Add support for PF framework based on the VF code.
Co-developed-by: Zhu Yikai <zhuyikai1@...artners.com>
Signed-off-by: Zhu Yikai <zhuyikai1@...artners.com>
Signed-off-by: Fan Gong <gongfan1@...wei.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
Powered by blists - more mailing lists