From de24ed304737557166a19f988a4ca594ea9185af Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 3 Jul 2024 16:41:16 +0800 Subject: [PATCH 1/6] net: hns3: add ieee_setmaxrate and ieee_getmaxrate support for pf driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IALRBN CVE: NA -------------------------------------------------------- Add support for ieee_setmaxrate and ieee_getmaxrate. The minimum rate supported by the hardware is 1 Mbit/s. Signed-off-by: Jian Shen Signed-off-by: Hao Lan --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 ++ .../net/ethernet/hisilicon/hns3/hns3_dcbnl.c | 26 +++++++ .../hisilicon/hns3/hns3pf/hclge_dcb.c | 68 +++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_dcb.h | 3 + 4 files changed, 101 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 55d75a83d818..a1bd56cc25c7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -879,6 +879,10 @@ struct hnae3_dcb_ops { int (*ieee_setpfc)(struct hnae3_handle *, struct ieee_pfc *); int (*ieee_setapp)(struct hnae3_handle *h, struct dcb_app *app); int (*ieee_delapp)(struct hnae3_handle *h, struct dcb_app *app); + int (*ieee_setmaxrate)(struct hnae3_handle *h, + struct ieee_maxrate *maxrate); + int (*ieee_getmaxrate)(struct hnae3_handle *h, + struct ieee_maxrate *maxrate); /* DCBX configuration */ u8 (*getdcbx)(struct hnae3_handle *); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c index 829ad48f261d..113e68df5c96 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c @@ -104,6 +104,28 @@ static u8 hns3_dcbnl_setdcbx(struct net_device *ndev, u8 mode) return 1; } +static int hns3_dcbnl_ieee_setmaxrate(struct net_device *netdev, + struct ieee_maxrate *maxrate) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + + if (h->kinfo.dcb_ops->ieee_setmaxrate) + return h->kinfo.dcb_ops->ieee_setmaxrate(h, maxrate); + + return -EOPNOTSUPP; +} + +static int hns3_dcbnl_ieee_getmaxrate(struct net_device *netdev, + struct ieee_maxrate *maxrate) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + + if (h->kinfo.dcb_ops->ieee_getmaxrate) + return h->kinfo.dcb_ops->ieee_getmaxrate(h, maxrate); + + return -EOPNOTSUPP; +} + static const struct dcbnl_rtnl_ops hns3_dcbnl_ops = { .ieee_getets = hns3_dcbnl_ieee_getets, .ieee_setets = hns3_dcbnl_ieee_setets, @@ -111,6 +133,8 @@ static const struct dcbnl_rtnl_ops hns3_dcbnl_ops = { .ieee_setpfc = hns3_dcbnl_ieee_setpfc, .ieee_setapp = hns3_dcbnl_ieee_setapp, .ieee_delapp = hns3_dcbnl_ieee_delapp, + .ieee_setmaxrate = hns3_dcbnl_ieee_setmaxrate, + .ieee_getmaxrate = hns3_dcbnl_ieee_getmaxrate, .getdcbx = hns3_dcbnl_getdcbx, .setdcbx = hns3_dcbnl_setdcbx, }; @@ -120,6 +144,8 @@ static const struct dcbnl_rtnl_ops hns3_unic_dcbnl_ops = { .ieee_setets = hns3_dcbnl_ieee_setets, .ieee_setapp = hns3_dcbnl_ieee_setapp, .ieee_delapp = hns3_dcbnl_ieee_delapp, + .ieee_setmaxrate = hns3_dcbnl_ieee_setmaxrate, + .ieee_getmaxrate = hns3_dcbnl_ieee_getmaxrate, .getdcbx = hns3_dcbnl_getdcbx, .setdcbx = hns3_dcbnl_setdcbx, }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index d7092b401cae..3f4f6c59386f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -509,6 +509,72 @@ static u8 hclge_setdcbx(struct hnae3_handle *h, u8 mode) return 0; } +static int hclge_ieee_getmaxrate(struct hnae3_handle *h, + struct ieee_maxrate *maxrate) +{ + struct hnae3_tc_info *tc_info = &h->kinfo.tc_info; + struct hclge_vport *vport = hclge_get_vport(h); + struct hclge_dev *hdev = vport->back; + + if (!hnae3_dev_roh_supported(hdev) && + !hnae3_dev_ubl_supported(hdev->ae_dev)) + return -EOPNOTSUPP; + + memcpy(maxrate, tc_info->max_rate, sizeof(struct ieee_maxrate)); + return 0; +} + +static int hclge_check_maxrate(struct hclge_dev *hdev, + struct ieee_maxrate *maxrate) +{ + u64 max_speed = (u64)hdev->hw.mac.max_speed * TM_RATE_PORT_RATE_SCALE; + u8 i; + + for (i = 0; i < HNAE3_MAX_TC; i++) { + /* no limit */ + if (!maxrate->tc_maxrate[i]) + continue; + if (maxrate->tc_maxrate[i] < TM_RATE_PORT_RATE_SCALE || + maxrate->tc_maxrate[i] > max_speed) { + dev_err(&hdev->pdev->dev, + "invalid max_rate[%llubps]: the range is [1Mbps, %uMbps]\n", + maxrate->tc_maxrate[i] * HCLGE_BYTE_BITS, + hdev->hw.mac.max_speed); + return -EINVAL; + } + } + return 0; +} + +static int hclge_ieee_setmaxrate(struct hnae3_handle *h, + struct ieee_maxrate *maxrate) +{ + struct hnae3_tc_info *tc_info = &h->kinfo.tc_info; + struct hclge_vport *vport = hclge_get_vport(h); + struct hclge_dev *hdev = vport->back; + struct hnae3_tc_info old_tc_info; + int ret; + + if (!hnae3_dev_roh_supported(hdev) && + !hnae3_dev_ubl_supported(hdev->ae_dev)) + return -EOPNOTSUPP; + + if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || tc_info->mqprio_active) + return -EINVAL; + + ret = hclge_check_maxrate(hdev, maxrate); + if (ret) + return ret; + + memcpy(&old_tc_info, tc_info, sizeof(struct hnae3_tc_info)); + memcpy(tc_info->max_rate, maxrate, sizeof(struct ieee_maxrate)); + ret = hclge_tm_set_tc_rate_limit(hdev, tc_info); + if (ret) + memcpy(tc_info, &old_tc_info, sizeof(struct hnae3_tc_info)); + + return ret; +} + static int hclge_mqprio_qopt_check_rate(struct hclge_dev *hdev, u64 min_rate, u64 max_rate) { @@ -701,6 +767,8 @@ static const struct hnae3_dcb_ops hns3_dcb_ops = { .getdcbx = hclge_getdcbx, .setdcbx = hclge_setdcbx, .setup_tc = hclge_setup_tc, + .ieee_setmaxrate = hclge_ieee_setmaxrate, + .ieee_getmaxrate = hclge_ieee_getmaxrate, }; void hclge_dcb_ops_set(struct hclge_dev *hdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h index b04702e65689..23e35c643c15 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h @@ -12,4 +12,7 @@ void hclge_dcb_ops_set(struct hclge_dev *hdev); static inline void hclge_dcb_ops_set(struct hclge_dev *hdev) {} #endif +#define HCLGE_BYTE_BITS 8ULL +#define HCLGE_RATE_UNIT_MBPS 1000000ULL /* 1Mbps */ + #endif /* __HCLGE_DCB_H__ */ -- Gitee From 48d5679b3c5191f518d056c5a80ed29dc524162a Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 3 Jul 2024 21:45:10 +0800 Subject: [PATCH 2/6] net: hns3: merge rss tc configuration driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IALRBN CVE: NA -------------------------------------------------------- Merge hclge_comm_get_rss_tc_info() and hclge_comm_get_rss_tc_info() to a new function hclge_comm_get_rss_tc_info(), so it doesn't need to define tc arrays every where. Signed-off-by: Jian Shen Signed-off-by: Hao Lan --- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 9e89bd3d2ecc..3f5e6f0ae0b6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -2278,12 +2278,21 @@ static int hclgevf_config_gro(struct hclgevf_dev *hdev) return ret; } +static int hclgevf_init_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size) +{ + u16 tc_offset[HNAE3_MAX_TC] = {0}; + u16 tc_valid[HNAE3_MAX_TC] = {0}; + u16 tc_size[HNAE3_MAX_TC] = {0}; + + hclge_comm_get_rss_tc_info(rss_size, hdev->hw_tc_map, + tc_offset, tc_valid, tc_size); + return hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset, tc_valid, + tc_size); +} + static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) { struct hclge_comm_rss_cfg *rss_cfg = &hdev->rss_cfg; - u16 tc_offset[HCLGE_COMM_MAX_TC_NUM]; - u16 tc_valid[HCLGE_COMM_MAX_TC_NUM]; - u16 tc_size[HCLGE_COMM_MAX_TC_NUM]; int ret; if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) { @@ -2303,11 +2312,7 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) if (ret) return ret; - hclge_comm_get_rss_tc_info(rss_cfg->rss_size, hdev->hw_tc_map, - tc_offset, tc_valid, tc_size); - - return hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset, - tc_valid, tc_size); + return hclgevf_init_rss_tc_mode(hdev, rss_cfg->rss_size); } static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev) @@ -3342,9 +3347,6 @@ static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); struct hnae3_knic_private_info *kinfo = &handle->kinfo; - u16 tc_offset[HCLGE_COMM_MAX_TC_NUM]; - u16 tc_valid[HCLGE_COMM_MAX_TC_NUM]; - u16 tc_size[HCLGE_COMM_MAX_TC_NUM]; u16 cur_rss_size = kinfo->rss_size; u16 cur_tqps = kinfo->num_tqps; u32 *rss_indir; @@ -3353,10 +3355,7 @@ static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, hclgevf_update_rss_size(handle, new_tqps_num); - hclge_comm_get_rss_tc_info(kinfo->rss_size, hdev->hw_tc_map, - tc_offset, tc_valid, tc_size); - ret = hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset, - tc_valid, tc_size); + ret = hclgevf_init_rss_tc_mode(hdev, kinfo->rss_size); if (ret) return ret; -- Gitee From 3c914c6acacd3936643d66039927deb85b31a8db Mon Sep 17 00:00:00 2001 From: Hao Lan Date: Thu, 4 Jul 2024 22:45:48 +0800 Subject: [PATCH 3/6] net: hns3: fixed vf get max channels bug driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IALRBN CVE: NA -------------------------------------------------------- Currently, the queried maximum of vf channels is the maximum of channels supported by each TC. However, the actual maximum of channels is the maximum of channels supported by the device. Signed-off-by: Jian Shen Signed-off-by: Hao Lan --- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 3f5e6f0ae0b6..d5f67400c9c1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -3280,11 +3280,7 @@ static void hclgevf_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) static u32 hclgevf_get_max_channels(struct hclgevf_dev *hdev) { - struct hnae3_handle *nic = &hdev->nic; - struct hnae3_knic_private_info *kinfo = &nic->kinfo; - - return min_t(u32, hdev->rss_size_max, - hdev->num_tqps / kinfo->tc_info.num_tc); + return min_t(u32, hdev->rss_size_max, hdev->num_tqps); } /** -- Gitee From 9ebeea0c6b10efac0990e0f6fb253f30c7e01bb9 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 3 Jul 2024 22:31:18 +0800 Subject: [PATCH 4/6] net: hns3: add support to query tc map info of VF queues driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IALRBN CVE: NA -------------------------------------------------------- Modified hclge_tm_get_q_to_tc to support the query of TC map info of VF queues. Signed-off-by: Jian Shen Signed-off-by: Hao Lan --- .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 18 +++++++++++++++++- .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 5 +++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 132b6446d485..7070afe410ca 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -2039,7 +2039,23 @@ int hclge_tm_get_q_to_tc(struct hclge_dev *hdev, u16 q_id, u8 *tc_id) tc = (struct hclge_tqp_tx_queue_tc_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TQP_TX_QUEUE_TC, true); - tc->queue_id = cpu_to_le16(q_id); + if (hnae3_ae_dev_vf_multi_tcs_supported(hdev)) { + struct hnae3_queue *tqp = &hdev->htqp[q_id].q; + struct hclge_vport *vport; + + if (!hdev->htqp[q_id].alloced) { + dev_err(&hdev->pdev->dev, + "q_id %u is not alloced\n", q_id); + return -EINVAL; + } + vport = container_of(tqp->handle, struct hclge_vport, nic); + tc->queue_id = cpu_to_le16(tqp->tqp_index); + tc->func_id = (u8)vport->vport_id; + } else { + tc->queue_id = cpu_to_le16(q_id); + tc->func_id = 0; + } + ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index 58222ea1906c..b0dd6e4a5862 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -65,9 +65,10 @@ struct hclge_nq_to_qs_link_cmd { struct hclge_tqp_tx_queue_tc_cmd { __le16 queue_id; - __le16 rsvd; + u8 func_id; + u8 rsvd1; u8 tc_id; - u8 rev[3]; + u8 rsvd2[3]; }; struct hclge_pg_weight_cmd { -- Gitee From 518ea89ec98b78c749c27d6ba7792e1bdb5779ed Mon Sep 17 00:00:00 2001 From: Hao Lan Date: Thu, 4 Jul 2024 20:24:48 +0800 Subject: [PATCH 5/6] net: hns3: add support for vf multiple tcs driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IALRBN CVE: NA -------------------------------------------------------- Add ieee_setets and ieee_getets supported for vf. Configures and queries vf multi-TC parameters, including the number of vf TCs, scheduling mode, and bandwidth weight. The number of TCs, scheduling mode, and bandwidth weight configured for the vf must be the same as those configured for the pf. When multiple TCs are configured for a vf, the pf does not allow the modification of TC parameters until all vfs are configured to work in single-TC mode. Signed-off-by: Jian Shen Signed-off-by: Hao Lan --- drivers/net/ethernet/hisilicon/hns3/Makefile | 1 + .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 12 +- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 5 + .../hns3/hns3_common/hclge_comm_cmd.c | 2 + .../hns3/hns3_common/hclge_comm_cmd.h | 1 + .../hns3/hns3_common/hclge_comm_rss.c | 3 +- .../net/ethernet/hisilicon/hns3/hns3_dcbnl.c | 2 +- .../ethernet/hisilicon/hns3/hns3_debugfs.c | 5 +- .../hisilicon/hns3/hns3pf/hclge_dcb.c | 50 +++ .../hisilicon/hns3/hns3pf/hclge_dcb.h | 10 + .../hisilicon/hns3/hns3pf/hclge_main.h | 1 + .../hisilicon/hns3/hns3pf/hclge_mbx.c | 31 +- .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 187 +++++++++- .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 1 + .../hisilicon/hns3/hns3vf/hclgevf_cmd.h | 7 + .../hisilicon/hns3/hns3vf/hclgevf_dcb.c | 322 ++++++++++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_dcb.h | 24 ++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 35 +- .../hisilicon/hns3/hns3vf/hclgevf_main.h | 6 + 19 files changed, 672 insertions(+), 33 deletions(-) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.h diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index ec994681c30e..0b1f6cf39dee 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -25,6 +25,7 @@ hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlin hclgevf-$(CONFIG_HNS3_UBL) += hns3_common/hclge_comm_unic_addr.o hns3vf/hclgevf_unic_ip.o hns3vf/hclgevf_unic_guid.o \ hns3vf/hclgevf_unic_addr.o hclgevf-$(CONFIG_UB_UDMA_HNS3) += hns3vf/hclgevf_udma.o +hclgevf-$(CONFIG_HNS3_DCB) += hns3vf/hclgevf_dcb.o obj-$(CONFIG_HNS3_HCLGE) += hclge.o hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_sysfs.o hns3pf/hclge_regs.o \ diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 14e830ff1892..62ddf1d1a2e7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -7,6 +7,8 @@ #include #include +#include "hnae3.h" + enum HCLGE_MBX_OPCODE { HCLGE_MBX_RESET = 0x01, /* (VF -> PF) assert reset */ HCLGE_MBX_ASSERTING_RESET, /* (PF -> VF) PF is asserting reset */ @@ -49,6 +51,7 @@ enum HCLGE_MBX_OPCODE { 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_SET_TC = 0x30, /* (VF -> PF) set tc */ HCLGE_MBX_SET_MGUID = 0x50, /* (VF -> PF) set mc guid */ HCLGE_UNIC_MBX_SET_IP, /* (VF -> PF) set ip addr */ @@ -115,7 +118,7 @@ struct hclge_ring_chain_param { struct hclge_basic_info { u8 hw_tc_map; - u8 rsv; + u8 tc_max; __le16 mbx_api_version; __le32 pf_caps; }; @@ -243,6 +246,13 @@ struct hclge_mbx_mtu_info { __le32 mtu; }; +struct hclge_mbx_tc_info { + __le32 prio_tc_map; + u8 tc_dwrr[HNAE3_MAX_TC]; + u8 num_tc; + u8 tc_sch_mode; /* 0: sp; 1: dwrr */ +}; + #pragma pack() /* used by VF to store the received Async responses from PF */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index a1bd56cc25c7..51f59910bff2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -142,6 +142,7 @@ enum HNAE3_DEV_CAP_BITS { HNAE3_DEV_SUPPORT_TM_FLUSH_B, HNAE3_DEV_SUPPORT_VF_FAULT_B, HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B, + HNAE3_DEV_SUPPORT_VF_MULTI_TCS_B, }; #define hnae3_ae_dev_fd_supported(ae_dev) \ @@ -222,8 +223,12 @@ enum HNAE3_DEV_CAP_BITS { #define hnae3_ae_dev_gen_reg_dfx_supported(hdev) \ test_bit(HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B, (hdev)->ae_dev->caps) +#define hnae3_ae_dev_vf_multi_tcs_supported(hdev) \ + test_bit(HNAE3_DEV_SUPPORT_VF_MULTI_TCS_B, (hdev)->ae_dev->caps) + enum HNAE3_PF_CAP_BITS { HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B = 0, + HNAE3_PF_SUPPORT_VF_MULTI_TCS_B = 1, }; #define ring_ptr_move_fw(ring, p) \ ((ring)->p = ((ring)->p + 1) % (ring)->desc_num) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c index 98814708ddf3..17097947fe83 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c @@ -159,6 +159,7 @@ static const struct hclge_comm_caps_bit_map hclge_pf_cmd_caps[] = { {HCLGE_COMM_CAP_TM_FLUSH_B, HNAE3_DEV_SUPPORT_TM_FLUSH_B}, {HCLGE_COMM_CAP_VF_FAULT_B, HNAE3_DEV_SUPPORT_VF_FAULT_B}, {HCLGE_COMM_CAP_ERR_MOD_GEN_REG_B, HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B}, + {HCLGE_COMM_CAP_VF_MULTI_TCS, HNAE3_DEV_SUPPORT_VF_MULTI_TCS_B}, }; static const struct hclge_comm_caps_bit_map hclge_vf_cmd_caps[] = { @@ -172,6 +173,7 @@ static const struct hclge_comm_caps_bit_map hclge_vf_cmd_caps[] = { {HCLGE_COMM_CAP_RXD_ADV_LAYOUT_B, HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B}, {HCLGE_COMM_CAP_CQ_B, HNAE3_DEV_SUPPORT_CQ_B}, {HCLGE_COMM_CAP_GRO_B, HNAE3_DEV_SUPPORT_GRO_B}, + {HCLGE_COMM_CAP_VF_MULTI_TCS, HNAE3_DEV_SUPPORT_VF_MULTI_TCS_B}, }; static void diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h index e9bb4d4e9aaf..7fa8d2411f06 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h @@ -366,6 +366,7 @@ enum HCLGE_COMM_CAP_BITS { HCLGE_COMM_CAP_NOTIFY_PKT_B = 29, HCLGE_COMM_CAP_TM_FLUSH_B = 31, HCLGE_COMM_CAP_ERR_MOD_GEN_REG_B = 32, + HCLGE_COMM_CAP_VF_MULTI_TCS = 34, }; enum HCLGE_COMM_API_CAP_BITS { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c index b4ae2160aff4..83c0bbfbeda5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c @@ -36,11 +36,12 @@ int hclge_comm_rss_init_cfg(struct hnae3_handle *nic, struct hclge_comm_rss_cfg *rss_cfg) { u16 rss_ind_tbl_size = ae_dev->dev_specs.rss_ind_tbl_size; + struct hnae3_knic_private_info *kinfo = &nic->kinfo; int rss_algo = HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ; u16 *rss_ind_tbl; if (nic->flags & HNAE3_SUPPORT_VF) - rss_cfg->rss_size = nic->kinfo.rss_size; + rss_cfg->rss_size = kinfo->rss_size; if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) rss_algo = HCLGE_COMM_RSS_HASH_ALGO_SIMPLE; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c index 113e68df5c96..b68b40c69c3c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c @@ -158,7 +158,7 @@ void hns3_dcbnl_setup(struct hnae3_handle *handle) { struct net_device *dev = handle->kinfo.netdev; - if ((!handle->kinfo.dcb_ops) || (handle->flags & HNAE3_SUPPORT_VF)) + if (!handle->kinfo.dcb_ops) return; #ifdef CONFIG_HNS3_UBL diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index e01b5dad4448..be2272a424d2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -61,7 +61,7 @@ static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = { .name = "tm_qset", .cmd = HNAE3_DBG_CMD_TM_QSET, .dentry = HNS3_DBG_DENTRY_TM, - .buf_len = HNS3_DBG_READ_LEN, + .buf_len = HNS3_DBG_READ_LEN_1MB, .init = hns3_dbg_common_file_init, }, { @@ -419,6 +419,9 @@ static struct hns3_dbg_cap_info hns3_dbg_cap[] = { }, { .name = "support vf fault detect", .cap_bit = HNAE3_DEV_SUPPORT_VF_FAULT_B, + }, { + .name = "support vf multi tcs", + .cap_bit = HNAE3_DEV_SUPPORT_VF_MULTI_TCS_B, } }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index 3f4f6c59386f..a7f2fe7e4216 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -81,6 +81,14 @@ static int hclge_dcb_common_validate(struct hclge_dev *hdev, u8 num_tc, { int i; + /* Based on hardware limitation, VFs share the configuration of PF. */ + if (hnae3_ae_dev_vf_multi_tcs_supported(hdev) && + !bitmap_empty(hdev->vf_multi_tcs_en, HCLGE_VPORT_NUM)) { + dev_err(&hdev->pdev->dev, + "the tc resource is still being used by VF\n"); + return -EOPNOTSUPP; + } + if (num_tc > hdev->tc_max) { dev_err(&hdev->pdev->dev, "tc num checking failed, %u > tc_max(%u)\n", @@ -198,6 +206,41 @@ static int hclge_ets_validate(struct hclge_dev *hdev, struct ieee_ets *ets, return 0; } +static bool hclge_ets_not_need_config(struct hclge_dev *hdev, + struct ieee_ets *ets) +{ + u8 max_tc_id = 0; + u32 i; + + if (ets->ets_cap != hdev->tc_max) + return false; + + for (i = 0; i < HNAE3_MAX_TC; i++) { + if (ets->tc_tx_bw[i] != hdev->tm_info.pg_info[0].tc_dwrr[i]) + return false; + + if (ets->prio_tc[i] != hdev->tm_info.prio_tc[i]) + return false; + + if (hdev->tm_info.tc_info[i].tc_sch_mode == + HCLGE_SCH_MODE_SP) { + if (ets->tc_tsa[i] != IEEE_8021QAZ_TSA_STRICT) + return false; + } else { + if (ets->tc_tsa[i] != IEEE_8021QAZ_TSA_ETS) + return false; + } + + if (ets->prio_tc[i] > max_tc_id) + max_tc_id = ets->prio_tc[i]; + } + + if (max_tc_id + 1 != hdev->tm_info.num_tc) + return false; + + return true; +} + static int hclge_map_update(struct hclge_dev *hdev) { int ret; @@ -262,6 +305,9 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets) h->kinfo.tc_info.mqprio_active) return -EINVAL; + if (hclge_ets_not_need_config(hdev, ets)) + return 0; + ret = hclge_ets_validate(hdev, ets, &num_tc, &map_changed); if (ret) return ret; @@ -274,6 +320,7 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets) return ret; } + mutex_lock(&hdev->vport_lock); hclge_tm_schd_info_update(hdev, num_tc); h->kinfo.tc_info.dcb_ets_active = num_tc > 1; @@ -286,12 +333,15 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets) if (ret) goto err_out; + mutex_unlock(&hdev->vport_lock); return hclge_notify_init_up(hdev); } + mutex_unlock(&hdev->vport_lock); return hclge_tm_dwrr_cfg(hdev); err_out: + mutex_unlock(&hdev->vport_lock); if (!map_changed) return ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h index 23e35c643c15..bc7e95781828 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h @@ -6,10 +6,20 @@ #include "hclge_main.h" +struct hclge_mbx_tc_info; + #ifdef CONFIG_HNS3_DCB void hclge_dcb_ops_set(struct hclge_dev *hdev); +int hclge_mbx_set_vf_multi_tc(struct hclge_vport *vport, + struct hclge_mbx_tc_info *tc_info); #else static inline void hclge_dcb_ops_set(struct hclge_dev *hdev) {} +static inline int hclge_mbx_set_vf_multi_tc(struct hclge_vport *vport, + struct hclge_mbx_tc_info *tc_info) +{ + return -EOPNOTSUPP; +} + #endif #define HCLGE_BYTE_BITS 8ULL diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index a0d22c00b22f..535825598ad8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -968,6 +968,7 @@ struct hclge_dev { unsigned long vf_vlan_full[BITS_TO_LONGS(HCLGE_VPORT_NUM)]; unsigned long vport_config_block[BITS_TO_LONGS(HCLGE_VPORT_NUM)]; + unsigned long vf_multi_tcs_en[BITS_TO_LONGS(HCLGE_VPORT_NUM)]; struct hclge_fd_cfg fd_cfg; struct hlist_head fd_rule_list; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 66da617e7972..61e91f504a6d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -8,6 +8,8 @@ #include "hclge_comm_unic_addr.h" #include "hclge_unic_guid.h" #include "hclge_unic_ip.h" +#include "hclge_dcb.h" +#include "hclge_tm.h" #define CREATE_TRACE_POINTS #include "hclge_trace.h" @@ -196,10 +198,10 @@ static int hclge_get_ring_chain_from_mbx( return -EINVAL; for (i = 0; i < ring_num; i++) { - if (req->msg.param[i].tqp_index >= vport->nic.kinfo.rss_size) { + if (req->msg.param[i].tqp_index >= vport->nic.kinfo.num_tqps) { dev_err(&hdev->pdev->dev, "tqp index(%u) is out of range(0-%u)\n", req->msg.param[i].tqp_index, - vport->nic.kinfo.rss_size - 1U); + vport->nic.kinfo.num_tqps - 1U); return -EINVAL; } } @@ -495,6 +497,7 @@ static void hclge_get_basic_info(struct hclge_vport *vport, { struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; struct hnae3_ae_dev *ae_dev = vport->back->ae_dev; + struct hclge_dev *hdev = vport->back; struct hclge_basic_info *basic_info; unsigned int i; u32 pf_caps; @@ -506,6 +509,12 @@ static void hclge_get_basic_info(struct hclge_vport *vport, pf_caps = le32_to_cpu(basic_info->pf_caps); if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps)) hnae3_set_bit(pf_caps, HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B, 1); + if (test_bit(HNAE3_DEV_SUPPORT_VF_MULTI_TCS_B, ae_dev->caps)) { + hnae3_set_bit(pf_caps, HNAE3_PF_SUPPORT_VF_MULTI_TCS_B, 1); + basic_info->tc_max = hdev->tc_max; + } else { + basic_info->tc_max = 1; + } basic_info->pf_caps = cpu_to_le32(pf_caps); resp_msg->len = HCLGE_MBX_MAX_RESP_DATA_SIZE; @@ -1062,6 +1071,8 @@ static int hclge_mbx_vf_uninit_handler(struct hclge_mbx_ops_param *param) } #endif param->vport->mps = 0; + clear_bit(param->vport->vport_id, hdev->vf_multi_tcs_en); + hclge_tm_vport_tc_info_update(param->vport); return 0; } @@ -1101,6 +1112,21 @@ static int hclge_mbx_handle_vf_qb_handler(struct hclge_mbx_ops_param *param) return 0; } +static int hclge_mbx_set_vf_multi_tc_handler(struct hclge_mbx_ops_param *param) +{ + struct hclge_mbx_tc_info *tc_info; + int ret; + + tc_info = (struct hclge_mbx_tc_info *)param->req->msg.data; + + ret = hclge_mbx_set_vf_multi_tc(param->vport, tc_info); + if (ret) + dev_err(¶m->vport->back->pdev->dev, + "PF fail(%d) to set VF multi TCS\n", ret); + + return ret; +} + #ifdef CONFIG_HNS3_UBL static int hclge_unic_mbx_set_mc_guid_handler(struct hclge_mbx_ops_param *param) { @@ -1161,6 +1187,7 @@ static const hclge_mbx_ops_fn hclge_mbx_ops_list[HCLGE_MBX_OPCODE_MAX] = { [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, + [HCLGE_MBX_SET_TC] = hclge_mbx_set_vf_multi_tc_handler, }; static void hclge_mbx_request_handling(struct hclge_mbx_ops_param *param) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 7070afe410ca..a6495e5da4df 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -3,6 +3,7 @@ #include +#include "hclge_mbx.h" #include "hclge_cmd.h" #include "hclge_main.h" #include "hclge_tm.h" @@ -679,23 +680,34 @@ static void hclge_tm_update_kinfo_rss_size(struct hclge_vport *vport) u16 vport_max_rss_size; u16 max_rss_size; - /* TC configuration is shared by PF/VF in one port, only allow - * one tc for VF for simplicity. VF's vport_id is non zero. - */ if (vport->vport_id) { - kinfo->tc_info.max_tc = 1; - kinfo->tc_info.num_tc = 1; - vport->qs_offset = HNAE3_MAX_TC + + /* If the VF supports multiple TCs, the VF has + * HNAE3_MAX_TC qsets. If the VF does not support + * multiple TCs, the VF has only one qset. + */ + if (hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + vport->qs_offset = HNAE3_MAX_TC * vport->vport_id; + else + vport->qs_offset = HNAE3_MAX_TC + vport->vport_id - HCLGE_VF_VPORT_START_NUM; vport_max_rss_size = hdev->vf_rss_size_max; } else { - kinfo->tc_info.max_tc = hdev->tc_max; - kinfo->tc_info.num_tc = - min_t(u16, vport->alloc_tqps, hdev->tm_info.num_tc); vport->qs_offset = 0; vport_max_rss_size = hdev->pf_rss_size_max; } + if (vport->vport_id && + !test_bit(vport->vport_id, hdev->vf_multi_tcs_en)) + kinfo->tc_info.num_tc = 1; + else + kinfo->tc_info.num_tc = + min_t(u16, vport->alloc_tqps, hdev->tm_info.num_tc); + + if (vport->vport_id && !hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + kinfo->tc_info.max_tc = 1; + else + kinfo->tc_info.max_tc = hdev->tc_max; + max_rss_size = min_t(u16, vport_max_rss_size, hclge_vport_get_max_rss_size(vport)); @@ -712,7 +724,7 @@ static void hclge_tm_update_kinfo_rss_size(struct hclge_vport *vport) } } -static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport) +void hclge_tm_vport_tc_info_update(struct hclge_vport *vport) { struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; struct hclge_dev *hdev = vport->back; @@ -1180,9 +1192,28 @@ static int hclge_tm_pri_shaper_cfg(struct hclge_dev *hdev) return 0; } +int hclge_tm_vf_tc_dwrr_cfg(struct hclge_vport *vport) +{ + struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; + struct hclge_dev *hdev = vport->back; + struct hclge_pg_info *pg_info; + u8 dwrr; + int ret; + u32 i; + + for (i = 0; i < kinfo->tc_info.max_tc; i++) { + pg_info = &hdev->tm_info.pg_info[hdev->tm_info.tc_info[i].pgid]; + dwrr = i < kinfo->tc_info.num_tc ? pg_info->tc_dwrr[i] : 0; + ret = hclge_tm_qs_weight_cfg(hdev, vport->qs_offset + i, dwrr); + if (ret) + return ret; + } + + return 0; +} + static int hclge_tm_pri_tc_base_dwrr_cfg(struct hclge_dev *hdev) { - struct hclge_vport *vport = hdev->vport; struct hclge_pg_info *pg_info; u8 dwrr; int ret; @@ -1198,15 +1229,22 @@ static int hclge_tm_pri_tc_base_dwrr_cfg(struct hclge_dev *hdev) return ret; for (k = 0; k < hdev->num_alloc_vport; k++) { - struct hnae3_knic_private_info *kinfo = &vport[k].nic.kinfo; + struct hclge_vport *vport = &hdev->vport[k]; + struct hnae3_tc_info *tc_info; - if (i >= kinfo->tc_info.max_tc) + tc_info = &vport->nic.kinfo.tc_info; + if (i >= tc_info->max_tc) continue; - dwrr = i < kinfo->tc_info.num_tc ? vport[k].dwrr : 0; - ret = hclge_tm_qs_weight_cfg( - hdev, vport[k].qs_offset + i, - dwrr); + if (test_bit(vport->vport_id, hdev->vf_multi_tcs_en)) + dwrr = pg_info->tc_dwrr[i]; + else if (i < tc_info->num_tc) + dwrr = vport->dwrr; + else + dwrr = 0; + + ret = hclge_tm_qs_weight_cfg(hdev, vport->qs_offset + i, + dwrr); if (ret) return ret; } @@ -2214,3 +2252,118 @@ int hclge_tm_flush_cfg(struct hclge_dev *hdev, bool enable) return ret; } + +static int hclge_vf_prio_tc_validate(struct hclge_dev *hdev, + struct hclge_mbx_tc_info *tc_info) +{ +#define HCLGE_PRI_SHIFT 4 + + u32 prio_tc_map = 0; + u8 i; + + for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) + prio_tc_map |= + (u32)hdev->tm_info.prio_tc[i] << (i * HCLGE_PRI_SHIFT); + + if (prio_tc_map != __le32_to_cpu(tc_info->prio_tc_map)) { + dev_err(&hdev->pdev->dev, + "failed to check vf prio tc map, not match pf\n"); + return -EINVAL; + } + + return 0; +} + +static int hclge_vf_sch_mode_validate(struct hclge_dev *hdev, + struct hclge_mbx_tc_info *tc_info) +{ + struct hclge_tm_info *tm_info = &hdev->tm_info; + u8 sch_mode; + u8 i; + + if (tc_info->num_tc != tm_info->num_tc) { + dev_err(&hdev->pdev->dev, + "failed to check vf tc num %u, not match pf tc num %u\n", + tc_info->num_tc, tm_info->num_tc); + return -EINVAL; + } + + for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) { + sch_mode = tc_info->tc_sch_mode & BIT(i) ? + HCLGE_SCH_MODE_DWRR : HCLGE_SCH_MODE_SP; + if (sch_mode != tm_info->tc_info[i].tc_sch_mode) { + dev_err(&hdev->pdev->dev, + "failed to check vf tc[%u] sch mode\n", i); + return -EINVAL; + } + + if (tm_info->pg_info[0].tc_dwrr[i] != tc_info->tc_dwrr[i]) { + dev_err(&hdev->pdev->dev, + "failed to check vf tc[%u] dwrr bw %u\n", + i, tc_info->tc_dwrr[i]); + return -EINVAL; + } + } + + return 0; +} + +static int hclge_vf_tc_info_validate(struct hclge_dev *hdev, + struct hclge_mbx_tc_info *tc_info) +{ + int ret; + + ret = hclge_vf_prio_tc_validate(hdev, tc_info); + if (ret) + return ret; + + return hclge_vf_sch_mode_validate(hdev, tc_info); +} + +int hclge_mbx_set_vf_multi_tc(struct hclge_vport *vport, + struct hclge_mbx_tc_info *tc_info) +{ + struct hnae3_handle *pf_handle = &vport->back->vport[0].nic; + struct hclge_dev *hdev = vport->back; + int ret; + + if (!hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + return -EOPNOTSUPP; + + if (!pf_handle->kinfo.tc_info.dcb_ets_active) + return -EOPNOTSUPP; + + mutex_lock(&hdev->vport_lock); + if (test_bit(vport->vport_id, hdev->vf_multi_tcs_en)) { + if (tc_info->num_tc != 1) { + ret = -EINVAL; + dev_err(&hdev->pdev->dev, + "tc number (%u) != 1\n", tc_info->num_tc); + goto out; + } + } else { + ret = hclge_vf_tc_info_validate(hdev, tc_info); + if (ret) + goto out; + } + + /* need updating vf_multi_tcs_en first, because the tc_info updating + * depend on it. + */ + change_bit(vport->vport_id, hdev->vf_multi_tcs_en); + hclge_tm_vport_tc_info_update(vport); + + ret = hclge_vport_q_to_qs_map(hdev, vport); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to set vf multi tcs, reset original status\n"); + change_bit(vport->vport_id, hdev->vf_multi_tcs_en); + hclge_tm_vport_tc_info_update(vport); + goto out; + } + ret = hclge_tm_vf_tc_dwrr_cfg(vport); + +out: + mutex_unlock(&hdev->vport_lock); + return ret; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index b0dd6e4a5862..90fd23c20b45 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -289,4 +289,5 @@ int hclge_tm_flush_cfg(struct hclge_dev *hdev, bool enable); int hclge_tm_set_tc_rate_limit(struct hclge_dev *hdev, struct hnae3_tc_info *tc_info); u32 hclge_tm_rate_2_port_rate(u64 rate); +void hclge_tm_vport_tc_info_update(struct hclge_vport *vport); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h index 537b887fa0a2..dcfe369da1e6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h @@ -90,6 +90,13 @@ struct hclgevf_cfg_com_tqp_queue_cmd { u8 rsv[19]; }; +struct hclgevf_tx_ring_tx_cmd { + __le16 tqp_id; + __le16 rsv1; + u8 tc_id; + u8 rsv2[19]; +}; + struct hclgevf_cfg_tx_queue_pointer_cmd { __le16 tqp_id; __le16 tx_tail; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c new file mode 100644 index 000000000000..4e7e4279e21c --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include "hclgevf_main.h" +#include "hclgevf_dcb.h" +#include "hnae3.h" + +#define BW_PERCENT 100 + +static void hclgevf_ieee_ets_to_prio_tc_map(struct hclge_mbx_tc_info *tc_info, + struct ieee_ets *ets) +{ +#define HCLGEVF_PRI_SHIFT 4 + u32 prio_tc_map = 0; + u32 i; + + for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) + prio_tc_map |= (ets->prio_tc[i] & 0xF) << + (i * HCLGEVF_PRI_SHIFT); + + tc_info->prio_tc_map = cpu_to_le32(prio_tc_map); +} + +static u8 hclgevf_get_ets_tc_num(struct ieee_ets *ets) +{ + u8 max_tc_id = 0; + u8 i; + + for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) { + if (ets->prio_tc[i] > max_tc_id) + max_tc_id = ets->prio_tc[i]; + } + + /* return max tc number, max tc id need to plus 1 */ + return max_tc_id + 1; +} + +static int hclgevf_ieee_ets_to_mbx_tc_info(struct hclge_mbx_tc_info *tc_info, + struct ieee_ets *ets) +{ + u8 i; + + tc_info->num_tc = hclgevf_get_ets_tc_num(ets); + tc_info->tc_sch_mode = 0; + for (i = 0; i < HNAE3_MAX_TC; i++) { + switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_STRICT: + tc_info->tc_dwrr[i] = 0; + break; + case IEEE_8021QAZ_TSA_ETS: + tc_info->tc_sch_mode |= BIT(i); + tc_info->tc_dwrr[i] = ets->tc_tx_bw[i]; + break; + default: + return -EINVAL; + } + } + + hclgevf_ieee_ets_to_prio_tc_map(tc_info, ets); + + return 0; +} + +void hclgevf_update_tc_info(struct hclgevf_dev *hdev) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + u8 i; + + hdev->hw_tc_map = 0; + for (i = 0; i < kinfo->tc_info.num_tc; i++) { + hdev->hw_tc_map |= BIT(i); + kinfo->tc_info.tqp_offset[i] = i * kinfo->rss_size; + kinfo->tc_info.tqp_count[i] = kinfo->rss_size; + } + + for (i = kinfo->tc_info.num_tc; i < HNAE3_MAX_TC; i++) { + /* Set to default queue if TC is disable */ + kinfo->tc_info.tqp_offset[i] = 0; + kinfo->tc_info.tqp_count[i] = 1; + } +} + +static int hclgevf_tx_ring_tc_config_cmd(struct hclgevf_dev *hdev, u16 txq_id, + u8 tc_id) +{ + struct hclgevf_tx_ring_tx_cmd *req; + struct hclge_desc desc; + + req = (struct hclgevf_tx_ring_tx_cmd *)desc.data; + + hclgevf_cmd_setup_basic_desc(&desc, HCLGE_OPC_TQP_TX_QUEUE_TC, false); + req->tqp_id = cpu_to_le16(txq_id & HCLGEVF_RING_ID_MASK); + req->tc_id = tc_id; + + return hclgevf_cmd_send(&hdev->hw, &desc, 1); +} + +int hclgevf_tx_ring_tc_config(struct hclgevf_dev *hdev) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + u16 i, j, qid; + int ret; + + for (i = 0; i < kinfo->tc_info.num_tc; i++) { + for (j = 0; j < kinfo->tc_info.tqp_count[i]; j++) { + qid = kinfo->tc_info.tqp_offset[i] + j; + ret = hclgevf_tx_ring_tc_config_cmd(hdev, qid, i); + if (ret) + return ret; + } + } + return 0; +} + +static int hclgevf_update_rss_tc_config(struct hclgevf_dev *hdev) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + int ret; + + hclgevf_update_rss_size(&hdev->nic, kinfo->req_rss_size); + hclgevf_update_tc_info(hdev); + hclge_comm_rss_indir_init_cfg(hdev->ae_dev, &hdev->rss_cfg); + ret = hclge_comm_set_rss_indir_table(hdev->ae_dev, &hdev->hw.hw, + hdev->rss_cfg.rss_indirection_tbl); + if (ret) + return ret; + + return hclgevf_init_rss_tc_mode(hdev, kinfo->rss_size); +} + +static int hclgevf_set_vf_multi_tc(struct hclgevf_dev *hdev, struct ieee_ets *ets) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + struct hclge_vf_to_pf_msg send_msg; + struct hclge_mbx_tc_info *tc_info; + int ret; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_TC, 0); + + tc_info = (struct hclge_mbx_tc_info *)send_msg.data; + ret = hclgevf_ieee_ets_to_mbx_tc_info(tc_info, ets); + if (ret) + return ret; + + ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, NULL, 0); + if (ret) + return ret; + + kinfo->tc_info.num_tc = tc_info->num_tc; + memcpy(kinfo->tc_info.prio_tc, ets->prio_tc, + sizeof_field(struct hnae3_tc_info, prio_tc)); + memcpy(&hdev->tc_info, tc_info, sizeof(*tc_info)); + + return hclgevf_update_rss_tc_config(hdev); +} + +static int hclgevf_ets_validate(struct hclgevf_dev *hdev, struct ieee_ets *ets) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + u8 num_tc = hclgevf_get_ets_tc_num(ets); + bool has_ets_tc = false; + u32 total_ets_bw = 0; + int i; + + if (num_tc > kinfo->tc_info.max_tc || num_tc > hdev->num_tqps) { + dev_err(&hdev->pdev->dev, "failed to check ets tc num: %u\n", + num_tc); + return -EINVAL; + } + + for (i = 0; i < HNAE3_MAX_TC; i++) { + if (ets->tc_tsa[i] != IEEE_8021QAZ_TSA_STRICT && + ets->tc_tsa[i] != IEEE_8021QAZ_TSA_ETS) { + dev_err(&hdev->pdev->dev, + "failed to check ets sched type %d\n", i); + return -EINVAL; + } + if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { + if (!ets->tc_tx_bw[i] || i >= num_tc) { + dev_err(&hdev->pdev->dev, + "tc%d ets error, num_tc is %u\n", + i, num_tc); + return -EINVAL; + } + total_ets_bw += ets->tc_tx_bw[i]; + has_ets_tc = true; + } + } + + if (has_ets_tc && total_ets_bw != BW_PERCENT) + return -EINVAL; + + return 0; +} + +static bool hclgevf_compare_ieee_ets(struct hclgevf_dev *hdev, + struct ieee_ets *ets) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + u32 i; + + if (ets->ets_cap != kinfo->tc_info.max_tc) + return false; + + for (i = 0; i < HNAE3_MAX_TC; i++) { + if (ets->tc_tx_bw[i] != hdev->tc_info.tc_dwrr[i]) + return false; + if (ets->prio_tc[i] != kinfo->tc_info.prio_tc[i]) + return false; + + if (hdev->tc_info.tc_sch_mode & BIT(i)) { + if (ets->tc_tsa[i] != IEEE_8021QAZ_TSA_ETS) + return false; + } else { + if (ets->tc_tsa[i] != IEEE_8021QAZ_TSA_STRICT) + return false; + } + } + return true; +} + +static bool hclgevf_ets_not_need_config(struct hclgevf_dev *hdev, + struct ieee_ets *ets) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + u8 num_tc = hclgevf_get_ets_tc_num(ets); + + if (num_tc == kinfo->tc_info.num_tc && num_tc == 1) + return true; + + return hclgevf_compare_ieee_ets(hdev, ets); +} + +static int hclgevf_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(h); + int ret1; + int ret; + + ret = hclgevf_ets_validate(hdev, ets); + if (ret) + return -EINVAL; + + if (hclgevf_ets_not_need_config(hdev, ets)) + return 0; + + ret = hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT); + if (ret) + return ret; + ret = hclgevf_notify_client(hdev, HNAE3_UNINIT_CLIENT); + if (ret) + return ret; + + ret1 = hclgevf_set_vf_multi_tc(hdev, ets); + + ret = hclgevf_notify_client(hdev, HNAE3_INIT_CLIENT); + if (ret) + return ret; + + ret = hclgevf_notify_client(hdev, HNAE3_UP_CLIENT); + if (ret) + return ret; + return ret1; +} + +static void hclgevf_tm_info_to_ieee_ets(struct hclgevf_dev *hdev, + struct ieee_ets *ets) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + u32 i; + + memset(ets, 0, sizeof(*ets)); + ets->willing = 1; + ets->ets_cap = kinfo->tc_info.max_tc; + + for (i = 0; i < HNAE3_MAX_TC; i++) { + ets->prio_tc[i] = kinfo->tc_info.prio_tc[i]; + if (i < hdev->tc_info.num_tc) + ets->tc_tx_bw[i] = hdev->tc_info.tc_dwrr[i]; + else + ets->tc_tx_bw[i] = 0; + + if (hdev->tc_info.tc_sch_mode & BIT(i)) + ets->tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; + else + ets->tc_tsa[i] = IEEE_8021QAZ_TSA_STRICT; + } +} + +static int hclgevf_ieee_getets(struct hnae3_handle *h, struct ieee_ets *ets) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(h); + + hclgevf_tm_info_to_ieee_ets(hdev, ets); + + return 0; +} + +static u8 hclgevf_getdcbx(struct hnae3_handle *h) +{ + return DCB_CAP_DCBX_VER_IEEE; +} + +static const struct hnae3_dcb_ops hclgevf_dcb_ops = { + .ieee_getets = hclgevf_ieee_getets, + .ieee_setets = hclgevf_ieee_setets, + .getdcbx = hclgevf_getdcbx, +}; + +void hclgevf_dcb_init(struct hclgevf_dev *hdev) +{ + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + + if (!hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + return; + + memset(&hdev->tc_info, 0, sizeof(hdev->tc_info)); + hdev->tc_info.num_tc = 1; + hdev->tc_info.tc_dwrr[0] = BW_PERCENT; + hdev->tc_info.tc_sch_mode = BIT(0); + kinfo->dcb_ops = &hclgevf_dcb_ops; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.h new file mode 100644 index 000000000000..e1835a317cfb --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +// Copyright (c) 2024 Hisilicon Limited. + +#ifndef __HCLGEVF_DCB_H__ +#define __HCLGEVF_DCB_H__ + +#include "hclgevf_main.h" + +#ifdef CONFIG_HNS3_DCB +void hclgevf_dcb_init(struct hclgevf_dev *hdev); +int hclgevf_tx_ring_tc_config(struct hclgevf_dev *hdev); +void hclgevf_update_tc_info(struct hclgevf_dev *hdev); + +#else +static inline void hclgevf_dcb_init(struct hclgevf_dev *hdev) {} +static inline int hclgevf_tx_ring_tc_config(struct hclgevf_dev *hdev) +{ + return 0; +} + +static inline void hclgevf_update_tc_info(struct hclgevf_dev *hdev) {} +#endif + +#endif /* __HCLGEVF_DCB_H__ */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index d5f67400c9c1..0befe6a50da1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -17,6 +17,7 @@ #include "hclgevf_unic_guid.h" #include "hclgevf_unic_addr.h" #include "hclgevf_trace.h" +#include "hclgevf_dcb.h" #define HCLGEVF_NAME "hclgevf" @@ -191,10 +192,13 @@ static int hclgevf_get_basic_info(struct hclgevf_dev *hdev) basic_info = (struct hclge_basic_info *)resp_msg; hdev->hw_tc_map = basic_info->hw_tc_map; + hdev->nic.kinfo.tc_info.max_tc = basic_info->tc_max; hdev->mbx_api_version = le16_to_cpu(basic_info->mbx_api_version); caps = le32_to_cpu(basic_info->pf_caps); if (test_bit(HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B, &caps)) set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps); + if (!test_bit(HNAE3_PF_SUPPORT_VF_MULTI_TCS_B, &caps)) + clear_bit(HNAE3_DEV_SUPPORT_VF_MULTI_TCS_B, ae_dev->caps); return 0; } @@ -387,12 +391,12 @@ static int hclgevf_knic_setup(struct hclgevf_dev *hdev) new_tqps = kinfo->rss_size * num_tc; kinfo->num_tqps = min(new_tqps, hdev->num_tqps); - kinfo->tqp = devm_kcalloc(&hdev->pdev->dev, kinfo->num_tqps, + kinfo->tqp = devm_kcalloc(&hdev->pdev->dev, hdev->num_tqps, sizeof(struct hnae3_queue *), GFP_KERNEL); if (!kinfo->tqp) return -ENOMEM; - for (i = 0; i < kinfo->num_tqps; i++) { + for (i = 0; i < hdev->num_tqps; i++) { hdev->htqp[i].q.handle = &hdev->nic; hdev->htqp[i].q.tqp_index = i; kinfo->tqp[i] = &hdev->htqp[i].q; @@ -1421,8 +1425,10 @@ static int hclgevf_reset_tqp(struct hnae3_handle *handle) ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, &return_status, sizeof(return_status)); - if (ret || return_status == HCLGEVF_RESET_ALL_QUEUE_DONE) + if (ret) return ret; + if (return_status == HCLGEVF_RESET_ALL_QUEUE_DONE) + goto map_tc; for (i = 1; i < handle->kinfo.num_tqps; i++) { hclgevf_build_send_msg(&send_msg, HCLGE_MBX_QUEUE_RESET, 0); @@ -1431,8 +1437,14 @@ static int hclgevf_reset_tqp(struct hnae3_handle *handle) if (ret) return ret; } +map_tc: + /* restore the tc map for tx ring */ + ret = hclgevf_tx_ring_tc_config(hdev); + if (ret) + dev_err(&hdev->pdev->dev, "failed to set tqp tc, ret = %d\n", + ret); - return 0; + return ret; } static int hclgevf_set_mtu(struct hnae3_handle *handle, int new_mtu) @@ -1448,8 +1460,8 @@ static int hclgevf_set_mtu(struct hnae3_handle *handle, int new_mtu) return hclgevf_send_mbx_msg(hdev, &send_msg, true, NULL, 0); } -static int hclgevf_notify_client(struct hclgevf_dev *hdev, - enum hnae3_reset_notify_type type) +int hclgevf_notify_client(struct hclgevf_dev *hdev, + enum hnae3_reset_notify_type type) { struct hnae3_client *client = hdev->nic_client; struct hnae3_handle *handle = &hdev->nic; @@ -2197,6 +2209,8 @@ static int hclgevf_configure(struct hclgevf_dev *hdev) if (ret) return ret; + hclgevf_dcb_init(hdev); + /* get current port based vlan state from PF */ ret = hclgevf_get_port_base_vlan_filter_state(hdev); if (ret) @@ -2278,7 +2292,7 @@ static int hclgevf_config_gro(struct hclgevf_dev *hdev) return ret; } -static int hclgevf_init_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size) +int hclgevf_init_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size) { u16 tc_offset[HNAE3_MAX_TC] = {0}; u16 tc_valid[HNAE3_MAX_TC] = {0}; @@ -3313,8 +3327,7 @@ static void hclgevf_get_tqps_and_rss_info(struct hnae3_handle *handle, *max_rss_size = hdev->rss_size_max; } -static void hclgevf_update_rss_size(struct hnae3_handle *handle, - u32 new_tqps_num) +void hclgevf_update_rss_size(struct hnae3_handle *handle, u32 new_tqps_num) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); @@ -3336,6 +3349,8 @@ static void hclgevf_update_rss_size(struct hnae3_handle *handle, kinfo->rss_size = max_rss_size; kinfo->num_tqps = kinfo->tc_info.num_tc * kinfo->rss_size; + + hdev->rss_cfg.rss_size = kinfo->rss_size; } static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, @@ -3350,7 +3365,7 @@ static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, int ret; hclgevf_update_rss_size(handle, new_tqps_num); - + hclgevf_update_tc_info(hdev); ret = hclgevf_init_rss_tc_mode(hdev, kinfo->rss_size); if (ret) return ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 314f4a61cb1c..3129ea8256ea 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -12,6 +12,7 @@ #include "hnae3.h" #include "hclge_comm_rss.h" #include "hclge_comm_tqp_stats.h" +#include "hclgevf_dcb.h" #define HCLGEVF_MOD_VERSION "1.0" #define HCLGEVF_DRIVER_NAME "hclgevf" @@ -232,6 +233,7 @@ struct hclgevf_dev { unsigned long reset_pending; enum hnae3_reset_type reset_type; struct timer_list reset_timer; + struct hclge_mbx_tc_info tc_info; #define HCLGEVF_RESET_REQUESTED 0 #define HCLGEVF_RESET_PENDING 1 @@ -319,4 +321,8 @@ void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state, struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle); void hclgevf_build_send_msg(struct hclge_vf_to_pf_msg *msg, u8 code, u8 subcode); +int hclgevf_notify_client(struct hclgevf_dev *hdev, + enum hnae3_reset_notify_type type); +void hclgevf_update_rss_size(struct hnae3_handle *handle, u32 new_tqps_num); +int hclgevf_init_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size); #endif -- Gitee From b4e04c2d9237ae2f84a66cabd781733428ef40a1 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 3 Jul 2024 23:01:47 +0800 Subject: [PATCH 6/6] net: hns3: add support for vf get dscp configuration from pf driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IALRBN CVE: NA -------------------------------------------------------- The vf supports two modes DSCP and priority. After configures DSCP parameters in the pf, the pf synchronizes the DSCP parameters to the vf. When multiple TCs are configured for a vf, vf can use the dscp parameter of the pf to select a queue for data flows. The query and configuration interfaces on the vf side are not provided. The vf supports dscp only when the vf supports multi-TCs. Signed-off-by: Jian Shen Signed-off-by: Hao Lan --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 5 ++ drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + .../hns3/hns3_common/hclge_comm_cmd.h | 3 + .../hisilicon/hns3/hns3pf/hclge_dcb.c | 33 +++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 1 + .../hisilicon/hns3/hns3pf/hclge_mbx.c | 21 +++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 44 ++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 4 + .../hisilicon/hns3/hns3vf/hclgevf_dcb.c | 1 + .../hisilicon/hns3/hns3vf/hclgevf_main.c | 85 ++++++++++++++++++- .../hisilicon/hns3/hns3vf/hclgevf_main.h | 1 + .../hisilicon/hns3/hns3vf/hclgevf_mbx.c | 16 ++++ 12 files changed, 214 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 62ddf1d1a2e7..89a2e008df4e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -52,6 +52,7 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_SET_QB = 0x28, /* (VF -> PF) set queue bonding */ HCLGE_MBX_PUSH_QB_STATE, /* (PF -> VF) push qb state */ HCLGE_MBX_SET_TC = 0x30, /* (VF -> PF) set tc */ + HCLGE_MBX_EVENT_NOTIFY, /* (PF -> VF) event notify */ HCLGE_MBX_SET_MGUID = 0x50, /* (VF -> PF) set mc guid */ HCLGE_UNIC_MBX_SET_IP, /* (VF -> PF) set ip addr */ @@ -103,6 +104,10 @@ enum hclge_mbx_qb_cfg_subcode { HCLGE_MBX_QB_GET_STATE /* query whether qb enabled */ }; +enum hclge_mbx_event_notify_type { + HCLGE_MBX_DSCP_CHANGE = 0, +}; + #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/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 51f59910bff2..c0b2ff520f9e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -921,6 +921,7 @@ struct hnae3_tc_info { #define HNAE3_MAX_DSCP 64 #define HNAE3_PRIO_ID_INVALID 0xff +#define HNAE3_PRIO_ID_MAP_INVALID 0xf struct hnae3_knic_private_info { struct net_device *netdev; /* Set by KNIC client when init instance */ u16 rss_size; /* Allocated RSS queues */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h index 7fa8d2411f06..9e904d9056fb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h @@ -268,6 +268,9 @@ enum hclge_opcode_type { HCLGE_OPC_IMP_STATS_INFO = 0x7013, HCLGE_OPC_IMP_COMPAT_CFG = 0x701A, + /* dscp pri map command */ + HCLGE_OPC_DSCP_PRI_MAP = 0x7039, + /* SFP command */ HCLGE_OPC_GET_SFP_EEPROM = 0x7100, HCLGE_OPC_GET_SFP_EXIST = 0x7101, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index a7f2fe7e4216..321aa1f98c79 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -4,6 +4,7 @@ #include "hclge_main.h" #include "hclge_dcb.h" #include "hclge_tm.h" +#include "hclge_mbx.h" #include "hnae3.h" #define BW_PERCENT 100 @@ -441,12 +442,34 @@ static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc) return last_bad_ret; } +static void hclge_notify_dscp_change(struct hclge_dev *hdev) +{ + struct hclge_vport *vport; + int ret; + int i; + + if (!hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + return; + + for (i = 0; i < pci_num_vf(hdev->pdev); i++) { + vport = &hdev->vport[i + HCLGE_VF_VPORT_START_NUM]; + + if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) + continue; + + ret = hclge_mbx_event_notify(vport, BIT(HCLGE_MBX_DSCP_CHANGE)); + if (ret) + break; + } +} + static int hclge_ieee_setapp(struct hnae3_handle *h, struct dcb_app *app) { struct hclge_vport *vport = hclge_get_vport(h); struct net_device *netdev = h->kinfo.netdev; struct hclge_dev *hdev = vport->back; struct dcb_app old_app; + int ret1; int ret; if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP || @@ -484,6 +507,11 @@ static int hclge_ieee_setapp(struct hnae3_handle *h, struct dcb_app *app) else ret = dcb_ieee_delapp(netdev, &old_app); + ret1 = hclge_dscp_to_pri_map(hdev); + if (ret1) + return ret1; + hclge_notify_dscp_change(hdev); + return ret; } @@ -525,6 +553,11 @@ static int hclge_ieee_delapp(struct hnae3_handle *h, struct dcb_app *app) ret = hclge_up_to_tc_map(hdev); } + ret = hclge_dscp_to_pri_map(hdev); + if (ret) + return ret; + hclge_notify_dscp_change(hdev); + return ret; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 535825598ad8..1cfba2517d9e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -1230,4 +1230,5 @@ void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type, u8 *module_type); int hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable); int hclge_query_scc_version(struct hclge_dev *hdev, u32 *scc_version); +int hclge_mbx_event_notify(struct hclge_vport *vport, u64 event_bits); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 61e91f504a6d..da02d01d6d38 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -608,6 +608,24 @@ int hclge_push_vf_link_status(struct hclge_vport *vport) HCLGE_MBX_LINK_STAT_CHANGE, vport->vport_id); } +int hclge_mbx_event_notify(struct hclge_vport *vport, u64 event_bits) +{ + __le64 msg_data = cpu_to_le64(event_bits); + struct hclge_dev *hdev = vport->back; + u8 dest_vfid = (u8)vport->vport_id; + int ret; + + /* send this requested info to VF */ + ret = hclge_send_mbx_msg(vport, (u8 *)&msg_data, sizeof(__le64), + HCLGE_MBX_EVENT_NOTIFY, dest_vfid); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to notify vf %u event %#llx, ret = %d\n", + vport->vport_id - HCLGE_VF_VPORT_START_NUM, event_bits, + ret); + return ret; +} + static void hclge_get_link_mode(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *mbx_req) { @@ -676,6 +694,9 @@ static void hclge_notify_vf_config(struct hclge_vport *vport) struct hclge_port_base_vlan_config *vlan_cfg; int ret; + if (hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + hclge_mbx_event_notify(vport, BIT(HCLGE_MBX_DSCP_CHANGE)); + hclge_push_vf_link_status(vport); if (test_bit(HCLGE_VPORT_NEED_NOTIFY_RESET, &vport->need_notify)) { ret = hclge_inform_vf_reset(vport, HNAE3_VF_PF_FUNC_RESET); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index a6495e5da4df..a5b2bca4a5e4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -269,12 +269,18 @@ int hclge_up_to_tc_map(struct hclge_dev *hdev) static void hclge_dscp_to_prio_map_init(struct hclge_dev *hdev) { + int ret; u8 i; hdev->vport[0].nic.kinfo.tc_map_mode = HNAE3_TC_MAP_MODE_PRIO; hdev->vport[0].nic.kinfo.dscp_app_cnt = 0; for (i = 0; i < HNAE3_MAX_DSCP; i++) hdev->vport[0].nic.kinfo.dscp_prio[i] = HNAE3_PRIO_ID_INVALID; + ret = hclge_dscp_to_pri_map(hdev); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to init dscp-prio map, ret = %d\n", + ret); } int hclge_dscp_to_tc_map(struct hclge_dev *hdev) @@ -308,6 +314,40 @@ int hclge_dscp_to_tc_map(struct hclge_dev *hdev) return hclge_cmd_send(&hdev->hw, desc, HCLGE_DSCP_MAP_TC_BD_NUM); } +int hclge_dscp_to_pri_map(struct hclge_dev *hdev) +{ + struct hclge_desc desc[HCLGE_DSCP_MAP_PRI_BD_NUM]; + u8 *req0 = (u8 *)desc[0].data; + u8 *req1 = (u8 *)desc[1].data; + u8 pri_id, i, j; + + if (!hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + return 0; + + hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_DSCP_PRI_MAP, false); + desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_DSCP_PRI_MAP, false); + + /* The low 32 dscp setting use bd0, high 32 dscp setting use bd1 */ + for (i = 0; i < HNAE3_MAX_DSCP / HCLGE_DSCP_MAP_PRI_BD_NUM; i++) { + pri_id = hdev->vport[0].nic.kinfo.dscp_prio[i]; + if (pri_id == HNAE3_PRIO_ID_INVALID) + pri_id = HNAE3_PRIO_ID_MAP_INVALID; + /* Each dscp setting has 4 bits, so each byte saves two dscp + * setting + */ + req0[i >> 1] |= pri_id << HCLGE_DSCP_PRI_SHIFT(i); + + j = i + HNAE3_MAX_DSCP / HCLGE_DSCP_MAP_PRI_BD_NUM; + pri_id = hdev->vport[0].nic.kinfo.dscp_prio[j]; + if (pri_id == HNAE3_PRIO_ID_INVALID) + pri_id = HNAE3_PRIO_ID_MAP_INVALID; + req1[i >> 1] |= pri_id << HCLGE_DSCP_PRI_SHIFT(i); + } + + return hclge_cmd_send(&hdev->hw, desc, HCLGE_DSCP_MAP_PRI_BD_NUM); +} + static int hclge_tm_pg_to_pri_map_cfg(struct hclge_dev *hdev, u8 pg_id, u8 pri_bit_map) { @@ -1359,6 +1399,10 @@ static int hclge_tm_map_cfg(struct hclge_dev *hdev) ret = hclge_dscp_to_tc_map(hdev); if (ret) return ret; + + ret = hclge_dscp_to_pri_map(hdev); + if (ret) + return ret; } ret = hclge_tm_pg_to_pri_map(hdev); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index 90fd23c20b45..61c56c826513 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -30,6 +30,9 @@ enum hclge_opcode_type; #define HCLGE_TM_PF_MAX_PRI_NUM 8 #define HCLGE_TM_PF_MAX_QSET_NUM 8 +#define HCLGE_DSCP_MAP_PRI_BD_NUM 2 +#define HCLGE_DSCP_PRI_SHIFT(n) (((n) & 1) * 4) + #define HCLGE_DSCP_MAP_TC_BD_NUM 2 #define HCLGE_DSCP_TC_SHIFT(n) (((n) & 1) * 4) @@ -290,4 +293,5 @@ int hclge_tm_set_tc_rate_limit(struct hclge_dev *hdev, struct hnae3_tc_info *tc_info); u32 hclge_tm_rate_2_port_rate(u64 rate); void hclge_tm_vport_tc_info_update(struct hclge_vport *vport); +int hclge_dscp_to_pri_map(struct hclge_dev *hdev); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c index 4e7e4279e21c..1043111a6919 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_dcb.c @@ -319,4 +319,5 @@ void hclgevf_dcb_init(struct hclgevf_dev *hdev) hdev->tc_info.tc_dwrr[0] = BW_PERCENT; hdev->tc_info.tc_sch_mode = BIT(0); kinfo->dcb_ops = &hclgevf_dcb_ops; + hclgevf_get_dscp_to_pri_map(hdev); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 0befe6a50da1..9f341cb10cb4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -2226,7 +2226,11 @@ static int hclgevf_configure(struct hclgevf_dev *hdev) if (ret) return ret; - return hclgevf_get_pf_media_type(hdev); + ret = hclgevf_get_pf_media_type(hdev); + if (ret) + return ret; + + return hclgevf_get_dscp_to_pri_map(hdev); } static int hclgevf_alloc_hdev(struct hnae3_ae_dev *ae_dev) @@ -3051,6 +3055,63 @@ static void hclgevf_uninit_rxd_adv_layout(struct hclgevf_dev *hdev) hclgevf_write_dev(&hdev->hw, HCLGEVF_RXD_ADV_LAYOUT_EN_REG, 0); } +int hclgevf_get_dscp_to_pri_map(struct hclgevf_dev *hdev) +{ +#define HCLGEVF_DSCP_MAP_PRI_BD_NUM 2 +#define HCLGEVF_DSCP_PRI_SHIFT(n) (((n) & 1) * 4) +#define HCLGEVF_PRI_MASK 0xF + + struct hnae3_knic_private_info *kinfo = &hdev->nic.kinfo; + struct hclge_desc desc[HCLGEVF_DSCP_MAP_PRI_BD_NUM]; + u8 dscp_prio[HNAE3_MAX_DSCP] = {0}; + u8 *req0 = (u8 *)desc[0].data; + u8 *req1 = (u8 *)desc[1].data; + u8 dscp_app_cnt = 0; + u8 i, j; + int ret; + + if (!hnae3_ae_dev_vf_multi_tcs_supported(hdev)) + return 0; + + hclgevf_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_DSCP_PRI_MAP, true); + desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclgevf_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_DSCP_PRI_MAP, true); + + ret = hclgevf_cmd_send(&hdev->hw, desc, HCLGEVF_DSCP_MAP_PRI_BD_NUM); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get dscp pri map, ret = %d\n", ret); + return ret; + } + + /* The low 32 dscp setting use bd0, high 32 dscp setting use bd1 */ + for (i = 0; i < HNAE3_MAX_DSCP / HCLGEVF_DSCP_MAP_PRI_BD_NUM; i++) { + /* Each dscp setting has 4 bits, so each byte saves two dscp + * setting + */ + dscp_prio[i] = (req0[i >> 1] >> HCLGEVF_DSCP_PRI_SHIFT(i)) & + HCLGEVF_PRI_MASK; + + j = i + HNAE3_MAX_DSCP / HCLGEVF_DSCP_MAP_PRI_BD_NUM; + dscp_prio[j] = (req1[i >> 1] >> HCLGEVF_DSCP_PRI_SHIFT(i)) & + HCLGEVF_PRI_MASK; + } + dscp_app_cnt = 0; + for (i = 0; i < HNAE3_MAX_DSCP; i++) { + if (dscp_prio[i] >= HNAE3_MAX_USER_PRIO) + dscp_prio[i] = HNAE3_PRIO_ID_INVALID; + else + dscp_app_cnt++; + } + + kinfo->dscp_app_cnt = dscp_app_cnt; + memcpy(kinfo->dscp_prio, dscp_prio, HNAE3_MAX_DSCP); + kinfo->tc_map_mode = kinfo->dscp_app_cnt ? HNAE3_TC_MAP_MODE_DSCP : + HNAE3_TC_MAP_MODE_PRIO; + + return 0; +} + static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) { struct pci_dev *pdev = hdev->pdev; @@ -3095,6 +3156,10 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) if (ret) return ret; + ret = hclgevf_get_dscp_to_pri_map(hdev); + if (ret) + return ret; + set_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state); hclgevf_init_rxd_adv_layout(hdev); @@ -3533,6 +3598,23 @@ void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state, rtnl_unlock(); } +static int hclgevf_get_dscp_prio(struct hnae3_handle *h, u8 dscp, u8 *tc_mode, + u8 *priority) +{ + struct hnae3_knic_private_info *kinfo = &h->kinfo; + + if (dscp >= HNAE3_MAX_DSCP) + return -EINVAL; + + if (tc_mode) + *tc_mode = kinfo->tc_map_mode; + if (priority) + *priority = kinfo->dscp_prio[dscp] == HNAE3_PRIO_ID_INVALID ? 0 : + kinfo->dscp_prio[dscp]; + + return 0; +} + static const struct hnae3_ae_ops hclgevf_ops = { .init_ae_dev = hclgevf_init_ae_dev, .uninit_ae_dev = hclgevf_uninit_ae_dev, @@ -3592,6 +3674,7 @@ static const struct hnae3_ae_ops hclgevf_ops = { .get_cmdq_stat = hclgevf_get_cmdq_stat, .request_flush_qb_config = hclgevf_set_fd_qb, .query_fd_qb_state = hclgevf_query_fd_qb_state, + .get_dscp_prio = hclgevf_get_dscp_prio, #ifdef CONFIG_HNS3_UBL .add_addr = hclgevf_unic_add_addr, .rm_addr = hclgevf_unic_rm_addr, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 3129ea8256ea..92a6109672b2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -325,4 +325,5 @@ int hclgevf_notify_client(struct hclgevf_dev *hdev, enum hnae3_reset_notify_type type); void hclgevf_update_rss_size(struct hnae3_handle *handle, u32 new_tqps_num); int hclgevf_init_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size); +int hclgevf_get_dscp_to_pri_map(struct hclgevf_dev *hdev); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index 6ccf23ce2744..3d703e6c97c4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -272,6 +272,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_PUSH_VLAN_INFO: case HCLGE_MBX_PUSH_PROMISC_INFO: case HCLGE_MBX_PUSH_QB_STATE: + case HCLGE_MBX_EVENT_NOTIFY: hclgevf_handle_mbx_msg(hdev, req); break; default: @@ -310,6 +311,16 @@ static void hclgevf_parse_qb_info(struct hclgevf_dev *hdev, u16 qb_state) hdev->qb_cfg.hw_qb_en = qb_state > HCLGEVF_HW_QB_OFF; } +static int hclgevf_mbx_parse_event_info(struct hclgevf_dev *hdev, u64 events) +{ + int ret = 0; + + if (events & BIT(HCLGE_MBX_DSCP_CHANGE)) + ret = hclgevf_get_dscp_to_pri_map(hdev); + + return ret; +} + void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) { struct hclge_mbx_port_base_vlan *vlan_info; @@ -318,6 +329,7 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) enum hnae3_reset_type reset_type; u16 link_status, state; __le16 *msg_q; + u64 events; u16 opcode; u8 duplex; u32 speed; @@ -391,6 +403,10 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_PUSH_QB_STATE: hclgevf_parse_qb_info(hdev, msg_q[1]); break; + case HCLGE_MBX_EVENT_NOTIFY: + events = *(u64 *)(msg_q + 1); + hclgevf_mbx_parse_event_info(hdev, events); + break; default: dev_err(&hdev->pdev->dev, "fetched unsupported(%u) message from arq\n", -- Gitee