From 274e8e310c46db5cf2e04f41960adf1696b5374b Mon Sep 17 00:00:00 2001
From: Jian Shen <shenjian15@huawei.com>
Date: Wed, 30 Nov 2022 18:23:33 +0800
Subject: [PATCH 186/283] net: hns3: add queue bonding mode support for VF

driver inclusion
category: feature
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8EN3D

----------------------------------------------------------------------

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>
Signed-off-by: Xiaodong Li <lixiaodong67@huawei.com>

 Conflicts:
	drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
	drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
	drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
---
 .../net/ethernet/hisilicon/hns3/hclge_mbx.h   |  6 ++
 .../hisilicon/hns3/hns3pf/hclge_main.c        | 50 ++++++++++++-
 .../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      |  8 ++
 .../hisilicon/hns3/hns3vf/hclgevf_mbx.c       | 17 +++++
 7 files changed, 193 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
index 05a1b789c9ab..cb6e3c40471a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
@@ -79,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 5fcae2b54ac7..c6bebf2a9e31 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -4565,6 +4565,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;
@@ -4593,6 +4594,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);
 	}
@@ -4601,10 +4607,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))
@@ -4616,17 +4645,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)
@@ -11392,6 +11439,7 @@ static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable)
 
 	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 65c7b8a534aa..4924aaad757d 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -1005,6 +1005,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 ec84f81fff92..305f11c854bf 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
@@ -822,6 +822,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)
 {
@@ -1031,6 +1061,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,
@@ -1055,6 +1091,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 d03d6c22b051..8bd2d8019425 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -472,6 +472,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;
@@ -2328,6 +2396,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:
@@ -3328,6 +3398,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
 		goto err_config;
 	}
 
+	hclgevf_get_pf_qb_caps(hdev);
+
 	set_bit(HCLGEVF_STATE_SERVICE_INITED, &hdev->state);
 
 	hdev->last_reset_time = jiffies;
@@ -3769,6 +3841,8 @@ static const struct hnae3_ae_ops hclgevf_ops = {
 	.get_link_mode = hclgevf_get_link_mode,
 	.set_promisc_mode = hclgevf_set_promisc_mode,
 	.request_update_promisc_mode = hclgevf_request_update_promisc_mode,
+	.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 97e9834c6de5..a8366fbf394a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -272,6 +272,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;
@@ -338,6 +343,9 @@ struct hclgevf_dev {
 	u32 flag;
 	unsigned long serv_processed_cnt;
 	unsigned long last_serv_processed;
+
+	struct hclgevf_qb_cfg qb_cfg;
+	struct devlink *devlink;
 };
 
 static inline bool hclgevf_is_reset_pending(struct hclgevf_dev *hdev)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
index 5e43289d714a..ccd45b3c532d 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
@@ -281,6 +281,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:
@@ -306,6 +307,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)
 {
 	enum hnae3_reset_type reset_type;
@@ -375,6 +389,9 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
 		case HCLGE_MBX_PUSH_PROMISC_INFO:
 			hclgevf_parse_promisc_info(hdev, 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",
-- 
2.34.1

