From: Jian Shen shenjian15@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
For device version V3, the hardware supports queue bonding mode. VF can not enable queue bond mode unless PF enables it. So VF needs to query whether PF support queue bonding mode when initializing, and query whether PF enables queue bonding mode periodically. For the resource limited, to avoid a VF occupy to many FD rule space, only trust VF is allowed to enable queue bonding mode.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Jian Shen shenjian15@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 8 ++ .../hisilicon/hns3/hns3pf/hclge_main.c | 51 ++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 2 + .../hisilicon/hns3/hns3pf/hclge_mbx.c | 37 ++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 74 +++++++++++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_main.h | 6 ++ .../hisilicon/hns3/hns3vf/hclgevf_mbx.c | 17 +++++ 7 files changed, 194 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index abcd7877f7d2..0de9b83c9d4e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -47,6 +47,8 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_VF_UNINIT, /* (VF -> PF) vf is unintializing */ HCLGE_MBX_HANDLE_VF_TBL, /* (VF -> PF) store/clear hw table */ HCLGE_MBX_GET_RING_VECTOR_MAP, /* (VF -> PF) get ring-to-vector map */ + HCLGE_MBX_SET_QB = 0x28, /* (VF -> PF) set queue bonding */ + HCLGE_MBX_PUSH_QB_STATE, /* (PF -> VF) push qb state */
HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ @@ -77,6 +79,12 @@ enum hclge_mbx_tbl_cfg_subcode { HCLGE_MBX_VPORT_LIST_CLEAR, };
+enum hclge_mbx_qb_cfg_subcode { + HCLGE_MBX_QB_CHECK_CAPS = 0, /* query whether support qb */ + HCLGE_MBX_QB_ENABLE, /* request pf enable qb */ + HCLGE_MBX_QB_GET_STATE /* query whether qb enabled */ +}; + #define HCLGE_MBX_MAX_MSG_SIZE 14 #define HCLGE_MBX_MAX_RESP_DATA_SIZE 8U #define HCLGE_MBX_MAX_RING_CHAIN_PARAM_NUM 4 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 3c5f244b7be9..18f9dd7fc4bb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4608,6 +4608,7 @@ static int hclge_sync_pf_qb_mode(struct hclge_dev *hdev) struct hnae3_handle *handle = &vport->nic; bool request_enable = true; int ret; + u16 i;
if (!test_and_clear_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state)) return 0; @@ -4636,6 +4637,11 @@ static int hclge_sync_pf_qb_mode(struct hclge_dev *hdev) clear_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); hdev->fd_active_type = HCLGE_FD_RULE_NONE; } + + for (i = 1; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } } else { set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); } @@ -4644,10 +4650,33 @@ static int hclge_sync_pf_qb_mode(struct hclge_dev *hdev) return ret; }
+static int hclge_sync_vf_qb_mode(struct hclge_vport *vport) +{ + struct hclge_dev *hdev = vport->back; + bool request_enable = false; + int ret; + + if (!test_and_clear_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state)) + return 0; + + if (vport->vf_info.trusted && vport->vf_info.request_qb_en && + test_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state)) + request_enable = true; + + ret = hclge_set_fd_qb(hdev, vport->vport_id, request_enable); + if (ret) + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + vport->vf_info.qb_en = request_enable ? 1 : 0; + + return ret; +} + static int hclge_disable_fd_qb_mode(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = hdev->ae_dev; + struct hclge_vport *vport; int ret; + u16 i;
if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps) || !test_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state)) @@ -4659,17 +4688,35 @@ static int hclge_disable_fd_qb_mode(struct hclge_dev *hdev)
clear_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state);
+ for (i = 1; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } + return 0; }
static void hclge_sync_fd_qb_mode(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = hdev->ae_dev; + struct hclge_vport *vport; + int ret; + u16 i;
if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps)) return;
- hclge_sync_pf_qb_mode(hdev); + ret = hclge_sync_pf_qb_mode(hdev); + if (ret) + return; + + for (i = 1; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + + ret = hclge_sync_vf_qb_mode(vport); + if (ret) + return; + } }
static void hclge_periodic_service_task(struct hclge_dev *hdev) @@ -12072,6 +12119,8 @@ static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable) return 0;
vport->vf_info.trusted = new_trusted; + + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); hclge_task_schedule(hdev, 0);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index ff62beeb80d4..d8c97430ab7b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -1048,6 +1048,8 @@ struct hclge_vf_info { u32 spoofchk; u32 max_tx_rate; u32 trusted; + u8 request_qb_en; + u8 qb_en; u8 request_uc_en; u8 request_mc_en; u8 request_bc_en; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 4d943f9c483b..700a074ef753 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -831,6 +831,36 @@ static void hclge_handle_vf_tbl(struct hclge_vport *vport, } }
+static void hclge_handle_vf_qb(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req, + struct hclge_respond_to_vf_msg *resp_msg) +{ + struct hclge_dev *hdev = vport->back; + + if (mbx_req->msg.subcode == HCLGE_MBX_QB_CHECK_CAPS) { + struct hnae3_handle *handle = &hdev->vport[0].nic; + + resp_msg->data[0] = test_bit(HNAE3_PFLAG_FD_QB_ENABLE, + &handle->supported_pflags); + resp_msg->len = sizeof(u8); + } else if (mbx_req->msg.subcode == HCLGE_MBX_QB_ENABLE) { + vport->vf_info.request_qb_en = mbx_req->msg.data[0]; + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } else if (mbx_req->msg.subcode == HCLGE_MBX_QB_GET_STATE) { + u16 msg_data = vport->vf_info.qb_en; + int ret; + + ret = hclge_send_mbx_msg(vport, (u8 *)&msg_data, + sizeof(msg_data), + HCLGE_MBX_PUSH_QB_STATE, + vport->vport_id); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to inform qb state to vport %u, ret = %d\n", + vport->vport_id, ret); + } +} + static int hclge_mbx_map_ring_to_vector_handler(struct hclge_mbx_ops_param *param) { @@ -1040,6 +1070,12 @@ static int hclge_mbx_handle_vf_tbl_handler(struct hclge_mbx_ops_param *param) return 0; }
+static int hclge_mbx_handle_vf_qb_handler(struct hclge_mbx_ops_param *param) +{ + hclge_handle_vf_qb(param->vport, param->req, param->resp_msg); + return 0; +} + static const hclge_mbx_ops_fn hclge_mbx_ops_list[HCLGE_MBX_OPCODE_MAX] = { [HCLGE_MBX_RESET] = hclge_mbx_reset_handler, [HCLGE_MBX_SET_UNICAST] = hclge_mbx_set_unicast_handler, @@ -1064,6 +1100,7 @@ static const hclge_mbx_ops_fn hclge_mbx_ops_list[HCLGE_MBX_OPCODE_MAX] = { [HCLGE_MBX_VF_UNINIT] = hclge_mbx_vf_uninit_handler, [HCLGE_MBX_HANDLE_VF_TBL] = hclge_mbx_handle_vf_tbl_handler, [HCLGE_MBX_GET_RING_VECTOR_MAP] = hclge_mbx_get_ring_vector_map_handler, + [HCLGE_MBX_SET_QB] = hclge_mbx_handle_vf_qb_handler, [HCLGE_MBX_GET_VF_FLR_STATUS] = hclge_mbx_get_vf_flr_status_handler, [HCLGE_MBX_PUSH_LINK_STATUS] = hclge_mbx_push_link_status_handler, [HCLGE_MBX_NCSI_ERROR] = hclge_mbx_ncsi_error_handler, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 0aa9beefd1c7..9b1882f3a3fa 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -354,6 +354,74 @@ static int hclgevf_knic_setup(struct hclgevf_dev *hdev) return 0; }
+static void hclgevf_update_fd_qb_state(struct hclgevf_dev *hdev) +{ + struct hnae3_handle *handle = &hdev->nic; + struct hclge_vf_to_pf_msg send_msg; + int ret; + + if (!hdev->qb_cfg.pf_support_qb || + !test_bit(HNAE3_PFLAG_FD_QB_ENABLE, &handle->priv_flags)) + return; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_QB, + HCLGE_MBX_QB_GET_STATE); + ret = hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + if (ret) + dev_err(&hdev->pdev->dev, "failed to get qb state, ret = %d", + ret); +} + +static void hclgevf_get_pf_qb_caps(struct hclgevf_dev *hdev) +{ + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); + struct hclge_vf_to_pf_msg send_msg; + u8 resp_msg; + int ret; + + if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps)) + return; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_QB, + HCLGE_MBX_QB_CHECK_CAPS); + ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, &resp_msg, + sizeof(resp_msg)); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get qb caps from PF, ret = %d", ret); + return; + } + + hdev->qb_cfg.pf_support_qb = resp_msg > 0; +} + +static void hclgevf_set_fd_qb(struct hnae3_handle *handle) +{ +#define HCLGEVF_QB_MBX_STATE_OFFSET 0 + + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hclge_vf_to_pf_msg send_msg; + u8 resp_msg; + int ret; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_QB, + HCLGE_MBX_QB_ENABLE); + send_msg.data[HCLGEVF_QB_MBX_STATE_OFFSET] = + test_bit(HNAE3_PFLAG_FD_QB_ENABLE, &handle->priv_flags) ? 1 : 0; + ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, &resp_msg, + sizeof(resp_msg)); + if (ret) + dev_err(&hdev->pdev->dev, "failed to set qb state, ret = %d", + ret); +} + +static bool hclgevf_query_fd_qb_state(struct hnae3_handle *handle) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + + return hdev->qb_cfg.hw_qb_en; +} + static void hclgevf_request_link_info(struct hclgevf_dev *hdev) { struct hclge_vf_to_pf_msg send_msg; @@ -1901,6 +1969,8 @@ static void hclgevf_periodic_service_task(struct hclgevf_dev *hdev)
hclgevf_sync_promisc_mode(hdev);
+ hclgevf_update_fd_qb_state(hdev); + hdev->last_serv_processed = jiffies;
out: @@ -2939,6 +3009,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) goto err_config; }
+ hclgevf_get_pf_qb_caps(hdev); + hclgevf_init_rxd_adv_layout(hdev);
set_bit(HCLGEVF_STATE_SERVICE_INITED, &hdev->state); @@ -3323,6 +3395,8 @@ static const struct hnae3_ae_ops hclgevf_ops = { .set_promisc_mode = hclgevf_set_promisc_mode, .request_update_promisc_mode = hclgevf_request_update_promisc_mode, .get_cmdq_stat = hclgevf_get_cmdq_stat, + .request_flush_qb_config = hclgevf_set_fd_qb, + .query_fd_qb_state = hclgevf_query_fd_qb_state, };
static struct hnae3_ae_algo ae_algovf = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index a73f2bf3a56a..ad59f6a61254 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -206,6 +206,11 @@ struct hclgevf_mac_table_cfg { struct list_head mc_mac_list; };
+struct hclgevf_qb_cfg { + bool pf_support_qb; + bool hw_qb_en; +}; + struct hclgevf_dev { struct pci_dev *pdev; struct hnae3_ae_dev *ae_dev; @@ -274,6 +279,7 @@ struct hclgevf_dev { unsigned long serv_processed_cnt; unsigned long last_serv_processed;
+ struct hclgevf_qb_cfg qb_cfg; struct devlink *devlink; };
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index 85c2a634c8f9..6ccf23ce2744 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -271,6 +271,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_LINK_STAT_MODE: case HCLGE_MBX_PUSH_VLAN_INFO: case HCLGE_MBX_PUSH_PROMISC_INFO: + case HCLGE_MBX_PUSH_QB_STATE: hclgevf_handle_mbx_msg(hdev, req); break; default: @@ -296,6 +297,19 @@ static void hclgevf_parse_promisc_info(struct hclgevf_dev *hdev, "Promisc mode is closed by host for being untrusted.\n"); }
+static void hclgevf_parse_qb_info(struct hclgevf_dev *hdev, u16 qb_state) +{ +#define HCLGEVF_HW_QB_ON 1 +#define HCLGEVF_HW_QB_OFF 0 + + if (qb_state > HCLGEVF_HW_QB_ON) { + dev_warn(&hdev->pdev->dev, "Invalid state, ignored.\n"); + return; + } + + hdev->qb_cfg.hw_qb_en = qb_state > HCLGEVF_HW_QB_OFF; +} + void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) { struct hclge_mbx_port_base_vlan *vlan_info; @@ -374,6 +388,9 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_PUSH_PROMISC_INFO: hclgevf_parse_promisc_info(hdev, le16_to_cpu(msg_q[1])); break; + case HCLGE_MBX_PUSH_QB_STATE: + hclgevf_parse_qb_info(hdev, msg_q[1]); + break; default: dev_err(&hdev->pdev->dev, "fetched unsupported(%u) message from arq\n",