Skip to content

Commit

Permalink
net: hns3: add support for configuring bandwidth of VF on the host
Browse files Browse the repository at this point in the history
This patch adds support for configuring bandwidth of VF on the host
for HNS3 drivers.

Signed-off-by: Yonglong Liu <liuyonglong@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
  • Loading branch information
Yonglong Liu authored and Jakub Kicinski committed Oct 9, 2019

Unverified

No user is associated with the committer email.
1 parent e196ec7 commit ee9e442
Showing 8 changed files with 280 additions and 2 deletions.
4 changes: 4 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hnae3.h
Original file line number Diff line number Diff line change
@@ -373,6 +373,8 @@ struct hnae3_ae_dev {
* set_vf_trust
* Enable/disable trust for specified vf, if the vf being trusted, then
* it can enable promisc mode
* set_vf_rate
* Set the max tx rate of specified vf.
*/
struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
@@ -545,6 +547,8 @@ struct hnae3_ae_ops {
int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf,
bool enable);
int (*set_vf_trust)(struct hnae3_handle *handle, int vf, bool enable);
int (*set_vf_rate)(struct hnae3_handle *handle, int vf,
int min_tx_rate, int max_tx_rate, bool force);
};

struct hnae3_dcb_ops {
14 changes: 13 additions & 1 deletion drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
Original file line number Diff line number Diff line change
@@ -1850,6 +1850,18 @@ static int hns3_nic_set_vf_link_state(struct net_device *ndev, int vf,
return h->ae_algo->ops->set_vf_link_state(h, vf, link_state);
}

static int hns3_nic_set_vf_rate(struct net_device *ndev, int vf,
int min_tx_rate, int max_tx_rate)
{
struct hnae3_handle *h = hns3_get_handle(ndev);

if (!h->ae_algo->ops->set_vf_rate)
return -EOPNOTSUPP;

return h->ae_algo->ops->set_vf_rate(h, vf, min_tx_rate, max_tx_rate,
false);
}

static const struct net_device_ops hns3_nic_netdev_ops = {
.ndo_open = hns3_nic_net_open,
.ndo_stop = hns3_nic_net_stop,
@@ -1872,7 +1884,7 @@ static const struct net_device_ops hns3_nic_netdev_ops = {
#endif
.ndo_get_vf_config = hns3_nic_get_vf_config,
.ndo_set_vf_link_state = hns3_nic_set_vf_link_state,

.ndo_set_vf_rate = hns3_nic_set_vf_rate,
};

bool hns3_is_phys_func(struct pci_dev *pdev)
2 changes: 1 addition & 1 deletion drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
Original file line number Diff line number Diff line change
@@ -244,7 +244,7 @@ enum hclge_opcode_type {
/* QCN commands */
HCLGE_OPC_QCN_MOD_CFG = 0x1A01,
HCLGE_OPC_QCN_GRP_TMPLT_CFG = 0x1A02,
HCLGE_OPC_QCN_SHAPPING_IR_CFG = 0x1A03,
HCLGE_OPC_QCN_SHAPPING_CFG = 0x1A03,
HCLGE_OPC_QCN_SHAPPING_BS_CFG = 0x1A04,
HCLGE_OPC_QCN_QSET_LINK_CFG = 0x1A05,
HCLGE_OPC_QCN_RP_STATUS_GET = 0x1A06,
79 changes: 79 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
Original file line number Diff line number Diff line change
@@ -1110,6 +1110,82 @@ static void hclge_dbg_dump_mac_tnl_status(struct hclge_dev *hdev)
}
}

static void hclge_dbg_dump_qs_shaper_single(struct hclge_dev *hdev, u16 qsid)
{
struct hclge_qs_shapping_cmd *shap_cfg_cmd;
u8 ir_u, ir_b, ir_s, bs_b, bs_s;
struct hclge_desc desc;
u32 shapping_para;
int ret;

hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG, true);

shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
shap_cfg_cmd->qs_id = cpu_to_le16(qsid);

ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"qs%u failed to get tx_rate, ret=%d\n",
qsid, ret);
return;
}

shapping_para = le32_to_cpu(shap_cfg_cmd->qs_shapping_para);
ir_b = hclge_tm_get_field(shapping_para, IR_B);
ir_u = hclge_tm_get_field(shapping_para, IR_U);
ir_s = hclge_tm_get_field(shapping_para, IR_S);
bs_b = hclge_tm_get_field(shapping_para, BS_B);
bs_s = hclge_tm_get_field(shapping_para, BS_S);

dev_info(&hdev->pdev->dev,
"qs%u ir_b:%u, ir_u:%u, ir_s:%u, bs_b:%u, bs_s:%u\n",
qsid, ir_b, ir_u, ir_s, bs_b, bs_s);
}

static void hclge_dbg_dump_qs_shaper_all(struct hclge_dev *hdev)
{
struct hnae3_knic_private_info *kinfo;
struct hclge_vport *vport;
int vport_id, i;

for (vport_id = 0; vport_id <= pci_num_vf(hdev->pdev); vport_id++) {
vport = &hdev->vport[vport_id];
kinfo = &vport->nic.kinfo;

dev_info(&hdev->pdev->dev, "qs cfg of vport%d:\n", vport_id);

for (i = 0; i < kinfo->num_tc; i++) {
u16 qsid = vport->qs_offset + i;

hclge_dbg_dump_qs_shaper_single(hdev, qsid);
}
}
}

static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev,
const char *cmd_buf)
{
#define HCLGE_MAX_QSET_NUM 1024

u16 qsid;
int ret;

ret = kstrtou16(cmd_buf, 0, &qsid);
if (ret) {
hclge_dbg_dump_qs_shaper_all(hdev);
return;
}

if (qsid >= HCLGE_MAX_QSET_NUM) {
dev_err(&hdev->pdev->dev, "qsid(%u) out of range[0-1023]\n",
qsid);
return;
}

hclge_dbg_dump_qs_shaper_single(hdev, qsid);
}

int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
{
#define DUMP_REG "dump reg"
@@ -1145,6 +1221,9 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
&cmd_buf[sizeof("dump ncl_config")]);
} else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) {
hclge_dbg_dump_mac_tnl_status(hdev);
} else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) {
hclge_dbg_dump_qs_shaper(hdev,
&cmd_buf[sizeof("dump qs shaper")]);
} else {
dev_info(&hdev->pdev->dev, "unknown command\n");
return -EINVAL;
130 changes: 130 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
Original file line number Diff line number Diff line change
@@ -1184,6 +1184,35 @@ static void hclge_parse_link_mode(struct hclge_dev *hdev, u8 speed_ability)
hclge_parse_backplane_link_mode(hdev, speed_ability);
}

static u32 hclge_get_max_speed(u8 speed_ability)
{
if (speed_ability & HCLGE_SUPPORT_100G_BIT)
return HCLGE_MAC_SPEED_100G;

if (speed_ability & HCLGE_SUPPORT_50G_BIT)
return HCLGE_MAC_SPEED_50G;

if (speed_ability & HCLGE_SUPPORT_40G_BIT)
return HCLGE_MAC_SPEED_40G;

if (speed_ability & HCLGE_SUPPORT_25G_BIT)
return HCLGE_MAC_SPEED_25G;

if (speed_ability & HCLGE_SUPPORT_10G_BIT)
return HCLGE_MAC_SPEED_10G;

if (speed_ability & HCLGE_SUPPORT_1G_BIT)
return HCLGE_MAC_SPEED_1G;

if (speed_ability & HCLGE_SUPPORT_100M_BIT)
return HCLGE_MAC_SPEED_100M;

if (speed_ability & HCLGE_SUPPORT_10M_BIT)
return HCLGE_MAC_SPEED_10M;

return HCLGE_MAC_SPEED_1G;
}

static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
{
struct hclge_cfg_param_cmd *req;
@@ -1354,6 +1383,8 @@ static int hclge_configure(struct hclge_dev *hdev)

hclge_parse_link_mode(hdev, cfg.speed_ability);

hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability);

if ((hdev->tc_max > HNAE3_MAX_TC) ||
(hdev->tc_max < 1)) {
dev_warn(&hdev->pdev->dev, "TC num = %d.\n",
@@ -2890,6 +2921,8 @@ static int hclge_get_vf_config(struct hnae3_handle *handle, int vf,
ivf->linkstate = vport->vf_info.link_state;
ivf->spoofchk = vport->vf_info.spoofchk;
ivf->trusted = vport->vf_info.trusted;
ivf->min_tx_rate = 0;
ivf->max_tx_rate = vport->vf_info.max_tx_rate;
ether_addr_copy(ivf->mac, vport->vf_info.mac);

return 0;
@@ -9520,6 +9553,97 @@ static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable)
return 0;
}

static void hclge_reset_vf_rate(struct hclge_dev *hdev)
{
int ret;
int vf;

/* reset vf rate to default value */
for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) {
struct hclge_vport *vport = &hdev->vport[vf];

vport->vf_info.max_tx_rate = 0;
ret = hclge_tm_qs_shaper_cfg(vport, vport->vf_info.max_tx_rate);
if (ret)
dev_err(&hdev->pdev->dev,
"vf%d failed to reset to default, ret=%d\n",
vf - HCLGE_VF_VPORT_START_NUM, ret);
}
}

static int hclge_vf_rate_param_check(struct hclge_dev *hdev, int vf,
int min_tx_rate, int max_tx_rate)
{
if (min_tx_rate != 0 ||
max_tx_rate < 0 || max_tx_rate > hdev->hw.mac.max_speed) {
dev_err(&hdev->pdev->dev,
"min_tx_rate:%d [0], max_tx_rate:%d [0, %u]\n",
min_tx_rate, max_tx_rate, hdev->hw.mac.max_speed);
return -EINVAL;
}

return 0;
}

static int hclge_set_vf_rate(struct hnae3_handle *handle, int vf,
int min_tx_rate, int max_tx_rate, bool force)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
int ret;

ret = hclge_vf_rate_param_check(hdev, vf, min_tx_rate, max_tx_rate);
if (ret)
return ret;

vport = hclge_get_vf_vport(hdev, vf);
if (!vport)
return -EINVAL;

if (!force && max_tx_rate == vport->vf_info.max_tx_rate)
return 0;

ret = hclge_tm_qs_shaper_cfg(vport, max_tx_rate);
if (ret)
return ret;

vport->vf_info.max_tx_rate = max_tx_rate;

return 0;
}

static int hclge_resume_vf_rate(struct hclge_dev *hdev)
{
struct hnae3_handle *handle = &hdev->vport->nic;
struct hclge_vport *vport;
int ret;
int vf;

/* resume the vf max_tx_rate after reset */
for (vf = 0; vf < pci_num_vf(hdev->pdev); vf++) {
vport = hclge_get_vf_vport(hdev, vf);
if (!vport)
return -EINVAL;

/* zero means max rate, after reset, firmware already set it to
* max rate, so just continue.
*/
if (!vport->vf_info.max_tx_rate)
continue;

ret = hclge_set_vf_rate(handle, vf, 0,
vport->vf_info.max_tx_rate, true);
if (ret) {
dev_err(&hdev->pdev->dev,
"vf%d failed to resume tx_rate:%u, ret=%d\n",
vf, vport->vf_info.max_tx_rate, ret);
return ret;
}
}

return 0;
}

static void hclge_reset_vport_state(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
@@ -9623,6 +9747,10 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
if (ret)
return ret;

ret = hclge_resume_vf_rate(hdev);
if (ret)
return ret;

dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
HCLGE_DRIVER_NAME);

@@ -9634,6 +9762,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
struct hclge_dev *hdev = ae_dev->priv;
struct hclge_mac *mac = &hdev->hw.mac;

hclge_reset_vf_rate(hdev);
hclge_misc_affinity_teardown(hdev);
hclge_state_uninit(hdev);

@@ -10360,6 +10489,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.set_vf_link_state = hclge_set_vf_link_state,
.set_vf_spoofchk = hclge_set_vf_spoofchk,
.set_vf_trust = hclge_set_vf_trust,
.set_vf_rate = hclge_set_vf_rate,
};

static struct hnae3_ae_algo ae_algo = {
2 changes: 2 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
Original file line number Diff line number Diff line change
@@ -258,6 +258,7 @@ struct hclge_mac {
u8 support_autoneg;
u8 speed_type; /* 0: sfp speed, 1: active speed */
u32 speed;
u32 max_speed;
u32 speed_ability; /* speed ability supported by current media */
u32 module_type; /* sub media type, e.g. kr/cr/sr/lr */
u32 fec_mode; /* active fec mode */
@@ -889,6 +890,7 @@ struct hclge_vf_info {
int link_state;
u8 mac[ETH_ALEN];
u32 spoofchk;
u32 max_tx_rate;
u32 trusted;
u16 promisc_enable;
};
43 changes: 43 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
Original file line number Diff line number Diff line change
@@ -511,6 +511,49 @@ static int hclge_tm_qs_bp_cfg(struct hclge_dev *hdev, u8 tc, u8 grp_id,
return hclge_cmd_send(&hdev->hw, &desc, 1);
}

int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate)
{
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
struct hclge_qs_shapping_cmd *shap_cfg_cmd;
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
u8 ir_b, ir_u, ir_s;
u32 shaper_para;
int ret, i;

if (!max_tx_rate)
max_tx_rate = HCLGE_ETHER_MAX_RATE;

ret = hclge_shaper_para_calc(max_tx_rate, HCLGE_SHAPER_LVL_QSET,
&ir_b, &ir_u, &ir_s);
if (ret)
return ret;

shaper_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s,
HCLGE_SHAPER_BS_U_DEF,
HCLGE_SHAPER_BS_S_DEF);

for (i = 0; i < kinfo->num_tc; i++) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG,
false);

shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
shap_cfg_cmd->qs_id = cpu_to_le16(vport->qs_offset + i);
shap_cfg_cmd->qs_shapping_para = cpu_to_le32(shaper_para);

ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"vf%d, qs%u failed to set tx_rate:%d, ret=%d\n",
vport->vport_id, shap_cfg_cmd->qs_id,
max_tx_rate, ret);
return ret;
}
}

return 0;
}

static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport)
{
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
8 changes: 8 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
Original file line number Diff line number Diff line change
@@ -96,6 +96,12 @@ struct hclge_pg_shapping_cmd {
__le32 pg_shapping_para;
};

struct hclge_qs_shapping_cmd {
__le16 qs_id;
u8 rsvd[2];
__le32 qs_shapping_para;
};

#define HCLGE_BP_GRP_NUM 32
#define HCLGE_BP_SUB_GRP_ID_S 0
#define HCLGE_BP_SUB_GRP_ID_M GENMASK(4, 0)
@@ -154,4 +160,6 @@ int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx);
int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr);
int hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats);
int hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats);
int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate);

#endif

0 comments on commit ee9e442

Please sign in to comment.