From: Chiqijun chiqijun@huawei.com
driver inclusion category: bugfix bugzilla: 4472
-----------------------------------------------------------------------
2.3.0.1 and later drivers and firmware add MAC reuse feature, when the driver is compatible with firmware version 2.3.0.0 and before, if the ip link command is used to configure the MAC and VLAN for the VF, it will cause the VF network anomaly.
To solve this problem, the driver obtains the function capability from the firmware when loading, and determines whether to support MAC reuse for different processing.
Signed-off-by: Chiqijun chiqijun@huawei.com Reviewed-by: Zengweiliang zengweiliang.zengweiliang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/huawei/hinic/hinic_hwdev.h | 1 + .../ethernet/huawei/hinic/hinic_mgmt_interface.h | 11 ++++ drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c | 45 +++++++++++++++-- drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h | 4 ++ drivers/net/ethernet/huawei/hinic/hinic_nic_io.c | 10 +++- drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h | 2 + drivers/net/ethernet/huawei/hinic/hinic_sriov.c | 59 ++++++++++++++-------- 7 files changed, 106 insertions(+), 26 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hwdev.h b/drivers/net/ethernet/huawei/hinic/hinic_hwdev.h index a096f91..2a81867 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hwdev.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hwdev.h @@ -319,6 +319,7 @@ struct hinic_hwdev { struct hinic_board_info board_info; #define MGMT_VERSION_MAX_LEN 32 u8 mgmt_ver[MGMT_VERSION_MAX_LEN]; + u64 fw_support_func_flag; };
int hinic_init_comm_ch(struct hinic_hwdev *hwdev); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h index 3c3be6e..8673cf5 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h @@ -690,6 +690,15 @@ struct hinic_port_rt_cmd { u8 rsvd1[6]; };
+struct fw_support_func { + u8 status; + u8 version; + u8 rsvd0[6]; + + u64 flag; + u64 rsvd; +}; + struct hinic_vf_dcb_state { u8 status; u8 version; @@ -741,6 +750,8 @@ struct hinic_set_link_follow {
int hinic_get_base_qpn(void *hwdev, u16 *global_qpn);
+int hinic_get_fw_support_func(void *hwdev); + int hinic_vf_func_init(struct hinic_hwdev *hwdev);
void hinic_vf_func_free(struct hinic_hwdev *hwdev); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c index f9e16ec..7dfedbd 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c @@ -201,6 +201,34 @@ int hinic_get_base_qpn(void *hwdev, u16 *global_qpn) return 0; }
+int hinic_get_fw_support_func(void *hwdev) +{ + struct fw_support_func support_flag = {0}; + struct hinic_hwdev *dev = hwdev; + u16 out_size = sizeof(support_flag); + int err; + + if (!hwdev) + return -EINVAL; + + err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC, + HINIC_PORT_CMD_GET_FW_SUPPORT_FLAG, + &support_flag, sizeof(support_flag), + &support_flag, &out_size, 0); + if (support_flag.status == HINIC_MGMT_CMD_UNSUPPORTED) { + nic_info(dev->dev_hdl, "Current firmware doesn't support to get function capability\n"); + support_flag.flag = 0; + } else if (support_flag.status || err || !out_size) { + nic_err(dev->dev_hdl, "Failed to get function capability, err: %d, status: 0x%x, out size: 0x%x\n", + err, support_flag.status, out_size); + return -EFAULT; + } + + dev->fw_support_func_flag = support_flag.flag; + + return 0; +} + #define HINIC_ADD_VLAN_IN_MAC 0x8000 #define HINIC_VLAN_ID_MASK 0x7FFF
@@ -352,6 +380,11 @@ int hinic_update_mac_vlan(void *hwdev, u16 old_vlan, u16 new_vlan, int vf_id) if (!vf_info->pf_set_mac) return 0;
+ if (!FW_SUPPORT_MAC_REUSE_FUNC(dev)) { + nic_info(dev->dev_hdl, "Current firmware doesn't support mac reuse\n"); + return 0; + } + func_id = hinic_glb_pf_vf_offset(dev) + (u16)vf_id; vlan_id = old_vlan; if (vlan_id) @@ -2562,9 +2595,14 @@ static int hinic_init_vf_config(struct hinic_hwdev *hwdev, u16 vf_id) vf_info = hwdev->nic_io->vf_infos + HW_VF_ID_TO_OS(vf_id); if (vf_info->pf_set_mac) { func_id = hinic_glb_pf_vf_offset(hwdev) + vf_id; - vlan_id = vf_info->pf_vlan; - if (vlan_id) - vlan_id |= HINIC_ADD_VLAN_IN_MAC; + if (FW_SUPPORT_MAC_REUSE_FUNC(hwdev)) { + vlan_id = vf_info->pf_vlan; + if (vlan_id) + vlan_id |= HINIC_ADD_VLAN_IN_MAC; + } else { + vlan_id = 0; + } + err = hinic_set_mac(hwdev, vf_info->vf_mac_addr, vlan_id, func_id); if (err) { @@ -4065,3 +4103,4 @@ int hinic_get_sfp_type(void *hwdev, u8 *data0, u8 *data1)
return 0; } + diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h index 427d469..e0979df 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h @@ -19,6 +19,10 @@ #define OS_VF_ID_TO_HW(os_vf_id) ((os_vf_id) + 1) #define HW_VF_ID_TO_OS(hw_vf_id) ((hw_vf_id) - 1)
+#define FW_SUPPORT_MAC_REUSE 0x1 +#define FW_SUPPORT_MAC_REUSE_FUNC(hwdev) \ + ((hwdev)->fw_support_func_flag & FW_SUPPORT_MAC_REUSE) + #define HINIC_VLAN_PRIORITY_SHIFT 13
#define HINIC_RSS_INDIR_SIZE 256 diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c b/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c index 1cb4e26..f2fb0bc 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c @@ -831,9 +831,17 @@ int hinic_init_nic_hwdev(void *hwdev, u16 rx_buff_len) }
/* VFs don't set port routine command report */ - if (hinic_func_type(dev) != TYPE_VF) + if (hinic_func_type(dev) != TYPE_VF) { + /* Get the fw support mac reuse flag */ + err = hinic_get_fw_support_func(hwdev); + if (err) { + nic_err(dev->dev_hdl, "Failed to get function capability\n"); + return err; + } + /* Inform mgmt to send sfp's information to driver */ err = hinic_set_port_routine_cmd_report(hwdev, true); + }
return err; } diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h b/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h index 46464b1f..d428f48 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h @@ -146,6 +146,8 @@ enum hinic_port_cmd { HINIC_PORT_CMD_SET_PORT_LINK_STATUS = 0x76, HINIC_PORT_CMD_SET_CGE_PAUSE_TIME_CFG = 0x77,
+ HINIC_PORT_CMD_GET_FW_SUPPORT_FLAG = 0x79, + HINIC_PORT_CMD_SET_PORT_REPORT = 0x7B,
HINIC_PORT_CMD_LINK_STATUS_REPORT = 0xa0, diff --git a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c index 37d0116..73ab2d7 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c @@ -266,6 +266,42 @@ int hinic_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
/*lint -save -e574 -e734*/ #ifdef IFLA_VF_MAX +static int set_hw_vf_vlan(struct hinic_sriov_info *sriov_info, + u16 cur_vlanprio, int vf, u16 vlan, u8 qos) +{ + int err = 0; + u16 old_vlan = cur_vlanprio & VLAN_VID_MASK; + + if (vlan || qos) { + if (cur_vlanprio) { + err = hinic_kill_vf_vlan(sriov_info->hwdev, + OS_VF_ID_TO_HW(vf)); + if (err) { + nic_err(&sriov_info->pdev->dev, "Failed to delete vf %d old vlan %d\n", + vf, old_vlan); + return err; + } + } + err = hinic_add_vf_vlan(sriov_info->hwdev, + OS_VF_ID_TO_HW(vf), vlan, qos); + if (err) { + nic_err(&sriov_info->pdev->dev, "Failed to add vf %d new vlan %d\n", + vf, vlan); + return err; + } + } else { + err = hinic_kill_vf_vlan(sriov_info->hwdev, OS_VF_ID_TO_HW(vf)); + if (err) { + nic_err(&sriov_info->pdev->dev, "Failed to delete vf %d vlan %d\n", + vf, old_vlan); + return err; + } + } + + return hinic_update_mac_vlan(sriov_info->hwdev, old_vlan, vlan, + OS_VF_ID_TO_HW(vf)); +} + #ifdef IFLA_VF_VLAN_INFO_MAX int hinic_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos, __be16 vlan_proto) @@ -276,7 +312,6 @@ int hinic_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos) struct hinic_nic_dev *adapter = netdev_priv(netdev); struct hinic_sriov_info *sriov_info; u16 vlanprio, cur_vlanprio; - int err = 0;
if (!FUNC_SUPPORT_SET_VF_MAC_VLAN(adapter->hwdev)) { nicif_err(adapter, drv, netdev, @@ -298,27 +333,7 @@ int hinic_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos) if (vlanprio == cur_vlanprio) return 0;
- if (vlan || qos) { - if (cur_vlanprio) - err = hinic_kill_vf_vlan(sriov_info->hwdev, - OS_VF_ID_TO_HW(vf)); - if (err) - goto out; - err = hinic_add_vf_vlan(sriov_info->hwdev, OS_VF_ID_TO_HW(vf), - vlan, qos); - } else { - err = hinic_kill_vf_vlan(sriov_info->hwdev, OS_VF_ID_TO_HW(vf)); - } - - if (err) - return err; - - err = hinic_update_mac_vlan(sriov_info->hwdev, - cur_vlanprio & VLAN_VID_MASK, vlan, - OS_VF_ID_TO_HW(vf)); - -out: - return err; + return set_hw_vf_vlan(sriov_info, cur_vlanprio, vf, vlan, qos); } #endif