net/hns3: support flow control

This patch adds support for MAC PAUSE flow control and priority flow
control(PFC).

MAC PAUSE flow control features:
All user priorities(up) are mapped to tc0. It supports settings of flow
mode and pause time.

DCB features:
Up can be mapped to other tc driver permits according to business
requirement. We can config DCB information and enable PFC by
rte_eth_dev_configure interface. Besides, enabling flow control of a
priority is supported by rte_eth_dev_priority_flow_ctrl_set interface.
we can also set flow mode and pause time by
rte_eth_dev_priority_flow_ctrl_set. we do not support manual setting of
ETS, but driver equally distributes bandwidth for each tc according to
number of used tc.

In addition, flow control function by default is turned off to ensure
that app startup state is the same each time.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Wei Hu (Xavier) 2019-09-26 22:01:58 +08:00 committed by Ferruh Yigit
parent c37ca66f2b
commit 62e3ccc2b9
6 changed files with 2018 additions and 0 deletions

View File

@ -11,7 +11,9 @@ Multicast MAC filter = Y
RSS hash = Y
RSS key update = Y
RSS reta update = Y
DCB = Y
Flow director = Y
Flow control = Y
Flow API = Y
FW version = Y
Linux UIO = Y

View File

@ -27,5 +27,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_dcb.c
include $(RTE_SDK)/mk/rte.lib.mk

1642
drivers/net/hns3/hns3_dcb.c Normal file

File diff suppressed because it is too large Load Diff

166
drivers/net/hns3/hns3_dcb.h Normal file
View File

@ -0,0 +1,166 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2018-2019 Hisilicon Limited.
*/
#ifndef _HNS3_DCB_H_
#define _HNS3_DCB_H_
/* MAC Pause */
#define HNS3_TX_MAC_PAUSE_EN_MSK BIT(0)
#define HNS3_RX_MAC_PAUSE_EN_MSK BIT(1)
#define HNS3_DEFAULT_PAUSE_TRANS_GAP 0x18
#define HNS3_DEFAULT_PAUSE_TRANS_TIME 0xFFFF
/* SP or DWRR */
#define HNS3_DCB_TX_SCHD_DWRR_MSK BIT(0)
#define HNS3_DCB_TX_SCHD_SP_MSK (0xFE)
enum hns3_shap_bucket {
HNS3_DCB_SHAP_C_BUCKET = 0,
HNS3_DCB_SHAP_P_BUCKET,
};
struct hns3_priority_weight_cmd {
uint8_t pri_id;
uint8_t dwrr;
};
struct hns3_qs_weight_cmd {
uint16_t qs_id;
uint8_t dwrr;
};
struct hns3_pg_weight_cmd {
uint8_t pg_id;
uint8_t dwrr;
};
struct hns3_ets_tc_weight_cmd {
uint8_t tc_weight[HNS3_MAX_TC_NUM];
uint8_t weight_offset;
uint8_t rsvd[15];
};
struct hns3_qs_to_pri_link_cmd {
uint16_t qs_id;
uint16_t rsvd;
uint8_t priority;
#define HNS3_DCB_QS_PRI_LINK_VLD_MSK BIT(0)
uint8_t link_vld;
};
struct hns3_nq_to_qs_link_cmd {
uint16_t nq_id;
uint16_t rsvd;
#define HNS3_DCB_Q_QS_LINK_VLD_MSK BIT(10)
uint16_t qset_id;
};
#define HNS3_DCB_SHAP_IR_B_MSK GENMASK(7, 0)
#define HNS3_DCB_SHAP_IR_B_LSH 0
#define HNS3_DCB_SHAP_IR_U_MSK GENMASK(11, 8)
#define HNS3_DCB_SHAP_IR_U_LSH 8
#define HNS3_DCB_SHAP_IR_S_MSK GENMASK(15, 12)
#define HNS3_DCB_SHAP_IR_S_LSH 12
#define HNS3_DCB_SHAP_BS_B_MSK GENMASK(20, 16)
#define HNS3_DCB_SHAP_BS_B_LSH 16
#define HNS3_DCB_SHAP_BS_S_MSK GENMASK(25, 21)
#define HNS3_DCB_SHAP_BS_S_LSH 21
struct hns3_pri_shapping_cmd {
uint8_t pri_id;
uint8_t rsvd[3];
uint32_t pri_shapping_para;
};
struct hns3_pg_shapping_cmd {
uint8_t pg_id;
uint8_t rsvd[3];
uint32_t pg_shapping_para;
};
#define HNS3_BP_GRP_NUM 32
#define HNS3_BP_SUB_GRP_ID_S 0
#define HNS3_BP_SUB_GRP_ID_M GENMASK(4, 0)
#define HNS3_BP_GRP_ID_S 5
#define HNS3_BP_GRP_ID_M GENMASK(9, 5)
struct hns3_bp_to_qs_map_cmd {
uint8_t tc_id;
uint8_t rsvd[2];
uint8_t qs_group_id;
uint32_t qs_bit_map;
uint32_t rsvd1;
};
struct hns3_pfc_en_cmd {
uint8_t tx_rx_en_bitmap;
uint8_t pri_en_bitmap;
};
struct hns3_port_shapping_cmd {
uint32_t port_shapping_para;
};
struct hns3_cfg_pause_param_cmd {
uint8_t mac_addr[RTE_ETHER_ADDR_LEN];
uint8_t pause_trans_gap;
uint8_t rsvd;
uint16_t pause_trans_time;
uint8_t rsvd1[6];
/* extra mac address to do double check for pause frame */
uint8_t mac_addr_extra[RTE_ETHER_ADDR_LEN];
uint16_t rsvd2;
};
struct hns3_pg_to_pri_link_cmd {
uint8_t pg_id;
uint8_t rsvd1[3];
uint8_t pri_bit_map;
};
enum hns3_shaper_level {
HNS3_SHAPER_LVL_PRI = 0,
HNS3_SHAPER_LVL_PG = 1,
HNS3_SHAPER_LVL_PORT = 2,
HNS3_SHAPER_LVL_QSET = 3,
HNS3_SHAPER_LVL_CNT = 4,
HNS3_SHAPER_LVL_VF = 0,
HNS3_SHAPER_LVL_PF = 1,
};
struct hns3_shaper_parameter {
uint32_t ir_b; /* IR_B parameter of IR shaper */
uint32_t ir_u; /* IR_U parameter of IR shaper */
uint32_t ir_s; /* IR_S parameter of IR shaper */
};
#define hns3_dcb_set_field(dest, string, val) \
hns3_set_field((dest), \
(HNS3_DCB_SHAP_##string##_MSK), \
(HNS3_DCB_SHAP_##string##_LSH), val)
#define hns3_dcb_get_field(src, string) \
hns3_get_field((src), (HNS3_DCB_SHAP_##string##_MSK), \
(HNS3_DCB_SHAP_##string##_LSH))
int hns3_pause_addr_cfg(struct hns3_hw *hw, const uint8_t *mac_addr);
int hns3_dcb_configure(struct hns3_adapter *hns);
int hns3_dcb_init(struct hns3_hw *hw);
int hns3_dcb_init_hw(struct hns3_hw *hw);
int hns3_dcb_info_init(struct hns3_hw *hw);
int
hns3_fc_enable(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf);
int
hns3_dcb_pfc_enable(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *pfc_conf);
void hns3_tc_queue_mapping_cfg(struct hns3_hw *hw);
int hns3_dcb_cfg_update(struct hns3_adapter *hns);
#endif /* _HNS3_DCB_H_ */

View File

@ -24,6 +24,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
#include "hns3_regs.h"
#include "hns3_dcb.h"
#define HNS3_DEFAULT_PORT_CONF_BURST_SIZE 32
#define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM 1
@ -2504,6 +2505,12 @@ hns3_init_hardware(struct hns3_adapter *hns)
goto err_mac_init;
}
ret = hns3_dcb_init(hw);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init dcb: %d", ret);
goto err_mac_init;
}
ret = hns3_init_fd_config(hns);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init flow director: %d", ret);
@ -2627,11 +2634,200 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
hw->adapter_state = HNS3_NIC_CLOSED;
}
static int
hns3_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
{
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
fc_conf->pause_time = pf->pause_time;
/* return fc current mode */
switch (hw->current_mode) {
case HNS3_FC_FULL:
fc_conf->mode = RTE_FC_FULL;
break;
case HNS3_FC_TX_PAUSE:
fc_conf->mode = RTE_FC_TX_PAUSE;
break;
case HNS3_FC_RX_PAUSE:
fc_conf->mode = RTE_FC_RX_PAUSE;
break;
case HNS3_FC_NONE:
default:
fc_conf->mode = RTE_FC_NONE;
break;
}
return 0;
}
static void
hns3_get_fc_mode(struct hns3_hw *hw, enum rte_eth_fc_mode mode)
{
switch (mode) {
case RTE_FC_NONE:
hw->requested_mode = HNS3_FC_NONE;
break;
case RTE_FC_RX_PAUSE:
hw->requested_mode = HNS3_FC_RX_PAUSE;
break;
case RTE_FC_TX_PAUSE:
hw->requested_mode = HNS3_FC_TX_PAUSE;
break;
case RTE_FC_FULL:
hw->requested_mode = HNS3_FC_FULL;
break;
default:
hw->requested_mode = HNS3_FC_NONE;
hns3_warn(hw, "fc_mode(%u) exceeds member scope and is "
"configured to RTE_FC_NONE", mode);
break;
}
}
static int
hns3_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
{
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
int ret;
if (fc_conf->high_water || fc_conf->low_water ||
fc_conf->send_xon || fc_conf->mac_ctrl_frame_fwd) {
hns3_err(hw, "Unsupported flow control settings specified, "
"high_water(%u), low_water(%u), send_xon(%u) and "
"mac_ctrl_frame_fwd(%u) must be set to '0'",
fc_conf->high_water, fc_conf->low_water,
fc_conf->send_xon, fc_conf->mac_ctrl_frame_fwd);
return -EINVAL;
}
if (fc_conf->autoneg) {
hns3_err(hw, "Unsupported fc auto-negotiation setting.");
return -EINVAL;
}
if (!fc_conf->pause_time) {
hns3_err(hw, "Invalid pause time %d setting.",
fc_conf->pause_time);
return -EINVAL;
}
if (!(hw->current_fc_status == HNS3_FC_STATUS_NONE ||
hw->current_fc_status == HNS3_FC_STATUS_MAC_PAUSE)) {
hns3_err(hw, "PFC is enabled. Cannot set MAC pause. "
"current_fc_status = %d", hw->current_fc_status);
return -EOPNOTSUPP;
}
hns3_get_fc_mode(hw, fc_conf->mode);
if (hw->requested_mode == hw->current_mode &&
pf->pause_time == fc_conf->pause_time)
return 0;
rte_spinlock_lock(&hw->lock);
ret = hns3_fc_enable(dev, fc_conf);
rte_spinlock_unlock(&hw->lock);
return ret;
}
static int
hns3_priority_flow_ctrl_set(struct rte_eth_dev *dev,
struct rte_eth_pfc_conf *pfc_conf)
{
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
uint8_t priority;
int ret;
if (!hns3_dev_dcb_supported(hw)) {
hns3_err(hw, "This port does not support dcb configurations.");
return -EOPNOTSUPP;
}
if (pfc_conf->fc.high_water || pfc_conf->fc.low_water ||
pfc_conf->fc.send_xon || pfc_conf->fc.mac_ctrl_frame_fwd) {
hns3_err(hw, "Unsupported flow control settings specified, "
"high_water(%u), low_water(%u), send_xon(%u) and "
"mac_ctrl_frame_fwd(%u) must be set to '0'",
pfc_conf->fc.high_water, pfc_conf->fc.low_water,
pfc_conf->fc.send_xon,
pfc_conf->fc.mac_ctrl_frame_fwd);
return -EINVAL;
}
if (pfc_conf->fc.autoneg) {
hns3_err(hw, "Unsupported fc auto-negotiation setting.");
return -EINVAL;
}
if (pfc_conf->fc.pause_time == 0) {
hns3_err(hw, "Invalid pause time %d setting.",
pfc_conf->fc.pause_time);
return -EINVAL;
}
if (!(hw->current_fc_status == HNS3_FC_STATUS_NONE ||
hw->current_fc_status == HNS3_FC_STATUS_PFC)) {
hns3_err(hw, "MAC pause is enabled. Cannot set PFC."
"current_fc_status = %d", hw->current_fc_status);
return -EOPNOTSUPP;
}
priority = pfc_conf->priority;
hns3_get_fc_mode(hw, pfc_conf->fc.mode);
if (hw->dcb_info.pfc_en & BIT(priority) &&
hw->requested_mode == hw->current_mode &&
pfc_conf->fc.pause_time == pf->pause_time)
return 0;
rte_spinlock_lock(&hw->lock);
ret = hns3_dcb_pfc_enable(dev, pfc_conf);
rte_spinlock_unlock(&hw->lock);
return ret;
}
static int
hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
{
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
enum rte_eth_rx_mq_mode mq_mode = dev->data->dev_conf.rxmode.mq_mode;
int i;
rte_spinlock_lock(&hw->lock);
if ((uint32_t)mq_mode & ETH_MQ_RX_DCB_FLAG)
dcb_info->nb_tcs = pf->local_max_tc;
else
dcb_info->nb_tcs = 1;
for (i = 0; i < HNS3_MAX_USER_PRIO; i++)
dcb_info->prio_tc[i] = hw->dcb_info.prio_tc[i];
for (i = 0; i < dcb_info->nb_tcs; i++)
dcb_info->tc_bws[i] = hw->dcb_info.pg_info[0].tc_dwrr[i];
for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
dcb_info->tc_queue.tc_rxq[0][i].base =
hw->tc_queue[i].tqp_offset;
dcb_info->tc_queue.tc_txq[0][i].base =
hw->tc_queue[i].tqp_offset;
dcb_info->tc_queue.tc_rxq[0][i].nb_queue =
hw->tc_queue[i].tqp_count;
dcb_info->tc_queue.tc_txq[0][i].nb_queue =
hw->tc_queue[i].tqp_count;
}
rte_spinlock_unlock(&hw->lock);
return 0;
}
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_close = hns3_dev_close,
.mtu_set = hns3_dev_mtu_set,
.dev_infos_get = hns3_dev_infos_get,
.fw_version_get = hns3_fw_version_get,
.flow_ctrl_get = hns3_flow_ctrl_get,
.flow_ctrl_set = hns3_flow_ctrl_set,
.priority_flow_ctrl_set = hns3_priority_flow_ctrl_set,
.mac_addr_add = hns3_add_mac_addr,
.mac_addr_remove = hns3_remove_mac_addr,
.mac_addr_set = hns3_set_default_mac_addr,
@ -2642,13 +2838,17 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.reta_update = hns3_dev_rss_reta_update,
.reta_query = hns3_dev_rss_reta_query,
.filter_ctrl = hns3_dev_filter_ctrl,
.get_dcb_info = hns3_get_dcb_info,
};
static int
hns3_dev_init(struct rte_eth_dev *eth_dev)
{
struct rte_device *dev = eth_dev->device;
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
uint16_t device_id = pci_dev->id.device_id;
int ret;
PMD_INIT_FUNC_TRACE();
@ -2668,6 +2868,12 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
return 0;
hw->adapter_state = HNS3_NIC_UNINITIALIZED;
if (device_id == HNS3_DEV_ID_25GE_RDMA ||
device_id == HNS3_DEV_ID_50GE_RDMA ||
device_id == HNS3_DEV_ID_100G_RDMA_MACSEC)
hns3_set_bit(hw->flag, HNS3_DEV_SUPPORT_DCB_B, 1);
hns->is_vf = false;
hw->data = eth_dev->data;

View File

@ -14,6 +14,7 @@ if arch_subdir != 'x86' and arch_subdir != 'arm' or not dpdk_conf.get('RTE_ARCH_
endif
sources = files('hns3_cmd.c',
'hns3_dcb.c',
'hns3_ethdev.c',
'hns3_fdir.c',
'hns3_flow.c',