]> www.infradead.org Git - users/hch/misc.git/commitdiff
hinic3: Add port management
authorFan Gong <gongfan1@huawei.com>
Fri, 12 Sep 2025 06:28:29 +0000 (14:28 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 16 Sep 2025 08:49:06 +0000 (10:49 +0200)
Add port management of enable/disable/query/flush function.

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>
Link: https://patch.msgid.link/122cbde6dec03e091340bda32c8b0d7fac3a2fb4.1757653621.git.zhuyikai1@h-partners.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h

index 7012130bba1d16bb3ecf140184c88dde766b8b61..6cc0345c39e4248f6e36fa373918a8f61ce4bdda 100644 (file)
@@ -69,12 +69,27 @@ struct l2nic_cmd_set_ci_attr {
        u64                  ci_addr;
 };
 
+struct l2nic_cmd_clear_qp_resource {
+       struct mgmt_msg_head msg_head;
+       u16                  func_id;
+       u16                  rsvd1;
+};
+
 struct l2nic_cmd_force_pkt_drop {
        struct mgmt_msg_head msg_head;
        u8                   port;
        u8                   rsvd1[3];
 };
 
+struct l2nic_cmd_set_vport_state {
+       struct mgmt_msg_head msg_head;
+       u16                  func_id;
+       u16                  rsvd1;
+       /* 0--disable, 1--enable */
+       u8                   state;
+       u8                   rsvd2[3];
+};
+
 struct l2nic_cmd_set_dcb_state {
        struct mgmt_msg_head head;
        u16                  func_id;
@@ -172,6 +187,20 @@ enum l2nic_ucode_cmd {
        L2NIC_UCODE_CMD_SET_RSS_INDIR_TBL = 4,
 };
 
+/* hilink mac group command */
+enum mag_cmd {
+       MAG_CMD_GET_LINK_STATUS = 7,
+};
+
+/* firmware also use this cmd report link event to driver */
+struct mag_cmd_get_link_status {
+       struct mgmt_msg_head head;
+       u8                   port_id;
+       /* 0:link down  1:link up */
+       u8                   status;
+       u8                   rsvd0[2];
+};
+
 enum hinic3_nic_feature_cap {
        HINIC3_NIC_F_CSUM           = BIT(0),
        HINIC3_NIC_F_SCTP_CRC       = BIT(1),
index 0f8b156fa206df5df6db8abd1378ac967f139e20..0fa3c790022517c14c1470409ce30f108a3c429e 100644 (file)
@@ -327,6 +327,59 @@ static void hinic3_close_channel(struct net_device *netdev)
        hinic3_free_qp_ctxts(nic_dev);
 }
 
+static int hinic3_vport_up(struct net_device *netdev)
+{
+       struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+       bool link_status_up;
+       u16 glb_func_id;
+       int err;
+
+       glb_func_id = hinic3_global_func_id(nic_dev->hwdev);
+       err = hinic3_set_vport_enable(nic_dev->hwdev, glb_func_id, true);
+       if (err) {
+               netdev_err(netdev, "Failed to enable vport\n");
+               goto err_flush_qps_res;
+       }
+
+       err = netif_set_real_num_queues(netdev, nic_dev->q_params.num_qps,
+                                       nic_dev->q_params.num_qps);
+       if (err) {
+               netdev_err(netdev, "Failed to set real number of queues\n");
+               goto err_flush_qps_res;
+       }
+       netif_tx_start_all_queues(netdev);
+
+       err = hinic3_get_link_status(nic_dev->hwdev, &link_status_up);
+       if (!err && link_status_up)
+               netif_carrier_on(netdev);
+
+       return 0;
+
+err_flush_qps_res:
+       hinic3_flush_qps_res(nic_dev->hwdev);
+       /* wait to guarantee that no packets will be sent to host */
+       msleep(100);
+
+       return err;
+}
+
+static void hinic3_vport_down(struct net_device *netdev)
+{
+       struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+       u16 glb_func_id;
+
+       netif_carrier_off(netdev);
+       netif_tx_disable(netdev);
+
+       glb_func_id = hinic3_global_func_id(nic_dev->hwdev);
+       hinic3_set_vport_enable(nic_dev->hwdev, glb_func_id, false);
+
+       hinic3_flush_txqs(netdev);
+       /* wait to guarantee that no packets will be sent to host */
+       msleep(100);
+       hinic3_flush_qps_res(nic_dev->hwdev);
+}
+
 static int hinic3_open(struct net_device *netdev)
 {
        struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
@@ -356,8 +409,14 @@ static int hinic3_open(struct net_device *netdev)
        if (err)
                goto err_uninit_qps;
 
+       err = hinic3_vport_up(netdev);
+       if (err)
+               goto err_close_channel;
+
        return 0;
 
+err_close_channel:
+       hinic3_close_channel(netdev);
 err_uninit_qps:
        hinic3_uninit_qps(nic_dev, &qp_params);
        hinic3_free_channel_resources(netdev, &qp_params, &nic_dev->q_params);
@@ -374,6 +433,7 @@ static int hinic3_close(struct net_device *netdev)
        struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
        struct hinic3_dyna_qp_params qp_params;
 
+       hinic3_vport_down(netdev);
        hinic3_close_channel(netdev);
        hinic3_uninit_qps(nic_dev, &qp_params);
        hinic3_free_channel_resources(netdev, &qp_params, &nic_dev->q_params);
index ed70750f5ae87065957643b4b76a1d200f5618ed..9349b8a314ae6ebb49b75da433573c8b015fd0c4 100644 (file)
@@ -267,6 +267,28 @@ int hinic3_set_ci_table(struct hinic3_hwdev *hwdev, struct hinic3_sq_attr *attr)
        return 0;
 }
 
+int hinic3_flush_qps_res(struct hinic3_hwdev *hwdev)
+{
+       struct l2nic_cmd_clear_qp_resource sq_res = {};
+       struct mgmt_msg_params msg_params = {};
+       int err;
+
+       sq_res.func_id = hinic3_global_func_id(hwdev);
+
+       mgmt_msg_params_init_default(&msg_params, &sq_res, sizeof(sq_res));
+
+       err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
+                                      L2NIC_CMD_CLEAR_QP_RESOURCE,
+                                      &msg_params);
+       if (err || sq_res.msg_head.status) {
+               dev_err(hwdev->dev, "Failed to clear sq resources, err: %d, status: 0x%x\n",
+                       err, sq_res.msg_head.status);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev)
 {
        struct l2nic_cmd_force_pkt_drop pkt_drop = {};
@@ -314,3 +336,49 @@ int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state)
 
        return 0;
 }
+
+int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_up)
+{
+       struct mag_cmd_get_link_status get_link = {};
+       struct mgmt_msg_params msg_params = {};
+       int err;
+
+       get_link.port_id = hinic3_physical_port_id(hwdev);
+
+       mgmt_msg_params_init_default(&msg_params, &get_link, sizeof(get_link));
+
+       err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_HILINK,
+                                      MAG_CMD_GET_LINK_STATUS, &msg_params);
+       if (err || get_link.head.status) {
+               dev_err(hwdev->dev, "Failed to get link state, err: %d, status: 0x%x\n",
+                       err, get_link.head.status);
+               return -EIO;
+       }
+
+       *link_status_up = !!get_link.status;
+
+       return 0;
+}
+
+int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id,
+                           bool enable)
+{
+       struct l2nic_cmd_set_vport_state en_state = {};
+       struct mgmt_msg_params msg_params = {};
+       int err;
+
+       en_state.func_id = func_id;
+       en_state.state = enable ? 1 : 0;
+
+       mgmt_msg_params_init_default(&msg_params, &en_state, sizeof(en_state));
+
+       err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
+                                      L2NIC_CMD_SET_VPORT_ENABLE, &msg_params);
+       if (err || en_state.msg_head.status) {
+               dev_err(hwdev->dev, "Failed to set vport state, err: %d, status: 0x%x\n",
+                       err, en_state.msg_head.status);
+               return -EINVAL;
+       }
+
+       return 0;
+}
index 719b81e2bc2acf355cd5e37ef71a3d47a1514022..b83b567fa54253427923c1f7a45c959bd5793df9 100644 (file)
@@ -50,8 +50,12 @@ int hinic3_update_mac(struct hinic3_hwdev *hwdev, const u8 *old_mac,
 
 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_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state);
+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);
 
 #endif