Add nic_io initialization to enable NIC service, initialize function table
and negotiate activation of NIC features.
Co-developed-by: Xin Guo <guoxin09@huawei.com>
Signed-off-by: Xin Guo <guoxin09@huawei.com>
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.c | 15 +++++
.../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 24 ++++++++
.../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 2 +
.../ethernet/huawei/hinic3/hinic3_nic_io.c | 61 ++++++++++++++++++-
4 files changed, 99 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c
index 1c8eeec97629..251c4e291f75 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c
@@ -438,6 +438,18 @@ static void hinic3_uninit_comm_ch(struct hinic3_hwdev *hwdev)
free_base_mgmt_channel(hwdev);
}
+static DEFINE_IDA(hinic3_adev_ida);
+
+static int hinic3_adev_idx_alloc(void)
+{
+ return ida_alloc(&hinic3_adev_ida, GFP_KERNEL);
+}
+
+static void hinic3_adev_idx_free(int id)
+{
+ ida_free(&hinic3_adev_ida, id);
+}
+
static int init_hwdev(struct pci_dev *pdev)
{
struct hinic3_pcidev *pci_adapter = pci_get_drvdata(pdev);
@@ -453,6 +465,7 @@ static int init_hwdev(struct pci_dev *pdev)
hwdev->dev = &pci_adapter->pdev->dev;
hwdev->func_state = 0;
memset(hwdev->features, 0, sizeof(hwdev->features));
+ hwdev->dev_id = hinic3_adev_idx_alloc();
spin_lock_init(&hwdev->channel_lock);
return 0;
@@ -524,6 +537,7 @@ int hinic3_init_hwdev(struct pci_dev *pdev)
err_free_hwdev:
pci_adapter->hwdev = NULL;
+ hinic3_adev_idx_free(hwdev->dev_id);
kfree(hwdev);
return err;
@@ -539,6 +553,7 @@ void hinic3_free_hwdev(struct hinic3_hwdev *hwdev)
hinic3_free_cfg_mgmt(hwdev);
destroy_workqueue(hwdev->workq);
hinic3_free_hwif(hwdev);
+ hinic3_adev_idx_free(hwdev->dev_id);
kfree(hwdev);
}
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
index 5b1a91a18c67..d42ddf63b3a5 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
@@ -39,6 +39,12 @@ static int hinic3_feature_nego(struct hinic3_hwdev *hwdev, u8 opcode,
return 0;
}
+int hinic3_get_nic_feature_from_hw(struct hinic3_nic_dev *nic_dev)
+{
+ return hinic3_feature_nego(nic_dev->hwdev, MGMT_MSG_CMD_OP_GET,
+ &nic_dev->nic_io->feature_cap, 1);
+}
+
int hinic3_set_nic_feature_to_hw(struct hinic3_nic_dev *nic_dev)
{
return hinic3_feature_nego(nic_dev->hwdev, MGMT_MSG_CMD_OP_SET,
@@ -82,6 +88,23 @@ static int hinic3_set_function_table(struct hinic3_hwdev *hwdev, u32 cfg_bitmap,
return 0;
}
+int hinic3_init_function_table(struct hinic3_nic_dev *nic_dev)
+{
+ struct hinic3_nic_io *nic_io = nic_dev->nic_io;
+ struct l2nic_func_tbl_cfg func_tbl_cfg;
+ u32 cfg_bitmap;
+
+ func_tbl_cfg.mtu = 0x3FFF; /* default, max mtu */
+ func_tbl_cfg.rx_wqe_buf_size = nic_io->rx_buf_len;
+
+ cfg_bitmap = BIT(L2NIC_FUNC_TBL_CFG_INIT) |
+ BIT(L2NIC_FUNC_TBL_CFG_MTU) |
+ BIT(L2NIC_FUNC_TBL_CFG_RX_BUF_SIZE);
+
+ return hinic3_set_function_table(nic_dev->hwdev, cfg_bitmap,
+ &func_tbl_cfg);
+}
+
int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu)
{
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
@@ -89,6 +112,7 @@ int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu)
struct hinic3_hwdev *hwdev = nic_dev->hwdev;
func_tbl_cfg.mtu = new_mtu;
+
return hinic3_set_function_table(hwdev, BIT(L2NIC_FUNC_TBL_CFG_MTU),
&func_tbl_cfg);
}
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
index bf9ce51dc401..6b6851650a37 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
@@ -22,11 +22,13 @@ enum hinic3_nic_event_type {
HINIC3_NIC_EVENT_LINK_UP = 1,
};
+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,
enum hinic3_nic_feature_cap feature_bits);
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_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id,
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c
index 34a1f5bd5ac1..dd3e704ad3b5 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c
@@ -9,13 +9,68 @@
#include "hinic3_nic_dev.h"
#include "hinic3_nic_io.h"
+static int init_nic_io(struct hinic3_nic_io **nic_io)
+{
+ *nic_io = kzalloc(sizeof(**nic_io), GFP_KERNEL);
+ if (!(*nic_io))
+ return -ENOMEM;
+
+ return 0;
+}
+
int hinic3_init_nic_io(struct hinic3_nic_dev *nic_dev)
{
- /* Completed by later submission due to LoC limit. */
- return -EFAULT;
+ struct hinic3_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic3_nic_io *nic_io;
+ int err;
+
+ err = init_nic_io(&nic_io);
+ if (err)
+ return err;
+
+ nic_dev->nic_io = nic_io;
+
+ err = hinic3_set_func_svc_used_state(hwdev, COMM_FUNC_SVC_T_NIC, 1);
+ if (err) {
+ dev_err(hwdev->dev, "Failed to set function svc used state\n");
+ goto err_free_nicio;
+ }
+
+ err = hinic3_init_function_table(nic_dev);
+ if (err) {
+ dev_err(hwdev->dev, "Failed to init function table\n");
+ goto err_clear_func_svc_used_state;
+ }
+
+ nic_io->rx_buf_len = nic_dev->rx_buf_len;
+
+ err = hinic3_get_nic_feature_from_hw(nic_dev);
+ if (err) {
+ dev_err(hwdev->dev, "Failed to get nic features\n");
+ goto err_clear_func_svc_used_state;
+ }
+
+ nic_io->feature_cap &= HINIC3_NIC_F_ALL_MASK;
+ nic_io->feature_cap &= HINIC3_NIC_DRV_DEFAULT_FEATURE;
+ dev_dbg(hwdev->dev, "nic features: 0x%llx\n\n", nic_io->feature_cap);
+
+ return 0;
+
+err_clear_func_svc_used_state:
+ hinic3_set_func_svc_used_state(hwdev, COMM_FUNC_SVC_T_NIC, 0);
+
+err_free_nicio:
+ nic_dev->nic_io = NULL;
+ kfree(nic_io);
+
+ return err;
}
void hinic3_free_nic_io(struct hinic3_nic_dev *nic_dev)
{
- /* Completed by later submission due to LoC limit. */
+ struct hinic3_nic_io *nic_io = nic_dev->nic_io;
+
+ hinic3_set_func_svc_used_state(nic_dev->hwdev, COMM_FUNC_SVC_T_NIC, 0);
+ nic_dev->nic_io = NULL;
+ kfree(nic_io);
}
--
2.43.0
On 26/08/2025 10:05, Fan Gong wrote:
> Add nic_io initialization to enable NIC service, initialize function table
> and negotiate activation of NIC features.
>
> Co-developed-by: Xin Guo <guoxin09@huawei.com>
> Signed-off-by: Xin Guo <guoxin09@huawei.com>
> 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.c | 15 +++++
> .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 24 ++++++++
> .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 2 +
> .../ethernet/huawei/hinic3/hinic3_nic_io.c | 61 ++++++++++++++++++-
> 4 files changed, 99 insertions(+), 3 deletions(-)
[...]
> +int hinic3_init_function_table(struct hinic3_nic_dev *nic_dev)
> +{
> + struct hinic3_nic_io *nic_io = nic_dev->nic_io;
> + struct l2nic_func_tbl_cfg func_tbl_cfg;
> + u32 cfg_bitmap;
> +
> + func_tbl_cfg.mtu = 0x3FFF; /* default, max mtu */
> + func_tbl_cfg.rx_wqe_buf_size = nic_io->rx_buf_len;
func_tbl_cfg can still have garbage in rsvd field, which then will be
passed down to FW. Better to init it to 0 to avoid exposing data.
> +
> + cfg_bitmap = BIT(L2NIC_FUNC_TBL_CFG_INIT) |
> + BIT(L2NIC_FUNC_TBL_CFG_MTU) |
> + BIT(L2NIC_FUNC_TBL_CFG_RX_BUF_SIZE);
> +
> + return hinic3_set_function_table(nic_dev->hwdev, cfg_bitmap,
> + &func_tbl_cfg);
> +}
> +
[...]
> +static int init_nic_io(struct hinic3_nic_io **nic_io)
> +{
> + *nic_io = kzalloc(sizeof(**nic_io), GFP_KERNEL);
> + if (!(*nic_io))
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> int hinic3_init_nic_io(struct hinic3_nic_dev *nic_dev)
> {
> - /* Completed by later submission due to LoC limit. */
> - return -EFAULT;
> + struct hinic3_hwdev *hwdev = nic_dev->hwdev;
> + struct hinic3_nic_io *nic_io;
> + int err;
> +
> + err = init_nic_io(&nic_io);
> + if (err)
> + return err;
there is no need for init_nic_io(). you can call kzalloc() directly
in hinic3_init_nic_io() and return -ENOMEM in case of NULL return
> +
> + nic_dev->nic_io = nic_io;
> +
© 2016 - 2026 Red Hat, Inc.