Commit de9c8a6a authored by David S. Miller's avatar David S. Miller

Merge branch 'hns3-dcb'

Yunsheng Lin says:

====================
Add support for DCB feature in hns3 driver

The patchset contains some enhancement related to DCB before
adding support for DCB feature.

This patchset depends on the following patchset:
https://patchwork.ozlabs.org/cover/815646/
https://patchwork.ozlabs.org/cover/816145/

High Level Architecture:

                   [ lldpad ]
                       |
                       |
                       |
                 [ hns3_dcbnl ]
                       |
                       |
                       |
                 [ hclge_dcb ]
                   /      \
                /            \
             /                  \
     [ hclge_main ]        [ hclge_tm ]

Current patch-set support following functionality:
   Use of lldptool to configure the tc schedule mode, tc
   bandwidth(if schedule mode is ETS), prio_tc_map and
   PFC parameter.

V3: Drop mqprio support

V2: Fix for not defining variables in local loop.

V1: Initial Submit.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6ade97da 9df8f79a
......@@ -103,4 +103,13 @@ config HNS3_ENET
family of SoCs. This module depends upon HNAE3 driver to access the HNAE3
devices and their associated operations.
config HNS3_DCB
bool "Hisilicon HNS3 Data Center Bridge Support"
default n
depends on HNS3 && HNS3_HCLGE && DCB
---help---
Say Y here if you want to use Data Center Bridging (DCB) in the HNS3 driver.
If unsure, say N.
endif # NET_VENDOR_HISILICON
......@@ -28,6 +28,7 @@
*/
#include <linux/acpi.h>
#include <linux/dcbnl.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
......@@ -131,6 +132,7 @@ struct hnae3_client_ops {
int (*init_instance)(struct hnae3_handle *handle);
void (*uninit_instance)(struct hnae3_handle *handle, bool reset);
void (*link_status_change)(struct hnae3_handle *handle, bool state);
int (*setup_tc)(struct hnae3_handle *handle, u8 tc);
};
#define HNAE3_CLIENT_NAME_LENGTH 16
......@@ -363,6 +365,20 @@ struct hnae3_ae_ops {
u16 vlan, u8 qos, __be16 proto);
};
struct hnae3_dcb_ops {
/* IEEE 802.1Qaz std */
int (*ieee_getets)(struct hnae3_handle *, struct ieee_ets *);
int (*ieee_setets)(struct hnae3_handle *, struct ieee_ets *);
int (*ieee_getpfc)(struct hnae3_handle *, struct ieee_pfc *);
int (*ieee_setpfc)(struct hnae3_handle *, struct ieee_pfc *);
/* DCBX configuration */
u8 (*getdcbx)(struct hnae3_handle *);
u8 (*setdcbx)(struct hnae3_handle *, u8);
int (*map_update)(struct hnae3_handle *);
};
struct hnae3_ae_algo {
const struct hnae3_ae_ops *ops;
struct list_head node;
......@@ -394,6 +410,7 @@ struct hnae3_knic_private_info {
u16 num_tqps; /* total number of TQPs in this handle */
struct hnae3_queue **tqp; /* array base of all TQPs in this instance */
const struct hnae3_dcb_ops *dcb_ops;
};
struct hnae3_roce_private_info {
......
......@@ -7,5 +7,9 @@ ccflags-y := -Idrivers/net/ethernet/hisilicon/hns3
obj-$(CONFIG_HNS3_HCLGE) += hclge.o
hclge-objs = hclge_main.o hclge_cmd.o hclge_mdio.o hclge_tm.o
hclge-$(CONFIG_HNS3_DCB) += hclge_dcb.o
obj-$(CONFIG_HNS3_ENET) += hns3.o
hns3-objs = hns3_enet.o hns3_ethtool.o
hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o
......@@ -311,6 +311,7 @@ struct hclge_tc_thrd {
struct hclge_priv_buf {
struct hclge_waterline wl; /* Waterline for low and high*/
u32 buf_size; /* TC private buffer size */
u32 tx_buf_size;
u32 enable; /* Enable TC private buffer or not */
};
......@@ -321,6 +322,11 @@ struct hclge_shared_buf {
u32 buf_size;
};
struct hclge_pkt_buf_alloc {
struct hclge_priv_buf priv_buf[HCLGE_MAX_TC_NUM];
struct hclge_shared_buf s_buf;
};
#define HCLGE_RX_COM_WL_EN_B 15
struct hclge_rx_com_wl_buf {
__le16 high_wl;
......
/*
* Copyright (c) 2016-2017 Hisilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "hclge_main.h"
#include "hclge_tm.h"
#include "hnae3.h"
#define BW_PERCENT 100
static int hclge_ieee_ets_to_tm_info(struct hclge_dev *hdev,
struct ieee_ets *ets)
{
u8 i;
for (i = 0; i < HNAE3_MAX_TC; i++) {
switch (ets->tc_tsa[i]) {
case IEEE_8021QAZ_TSA_STRICT:
hdev->tm_info.tc_info[i].tc_sch_mode =
HCLGE_SCH_MODE_SP;
hdev->tm_info.pg_info[0].tc_dwrr[i] = 0;
break;
case IEEE_8021QAZ_TSA_ETS:
hdev->tm_info.tc_info[i].tc_sch_mode =
HCLGE_SCH_MODE_DWRR;
hdev->tm_info.pg_info[0].tc_dwrr[i] =
ets->tc_tx_bw[i];
break;
default:
/* Hardware only supports SP (strict priority)
* or ETS (enhanced transmission selection)
* algorithms, if we receive some other value
* from dcbnl, then throw an error.
*/
return -EINVAL;
}
}
return hclge_tm_prio_tc_info_update(hdev, ets->prio_tc);
}
static void hclge_tm_info_to_ieee_ets(struct hclge_dev *hdev,
struct ieee_ets *ets)
{
u32 i;
memset(ets, 0, sizeof(*ets));
ets->willing = 1;
ets->ets_cap = hdev->tc_max;
for (i = 0; i < HNAE3_MAX_TC; i++) {
ets->prio_tc[i] = hdev->tm_info.prio_tc[i];
ets->tc_tx_bw[i] = hdev->tm_info.pg_info[0].tc_dwrr[i];
if (hdev->tm_info.tc_info[i].tc_sch_mode ==
HCLGE_SCH_MODE_SP)
ets->tc_tsa[i] = IEEE_8021QAZ_TSA_STRICT;
else
ets->tc_tsa[i] = IEEE_8021QAZ_TSA_ETS;
}
}
/* IEEE std */
static int hclge_ieee_getets(struct hnae3_handle *h, struct ieee_ets *ets)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
hclge_tm_info_to_ieee_ets(hdev, ets);
return 0;
}
static int hclge_ets_validate(struct hclge_dev *hdev, struct ieee_ets *ets,
u8 *tc, bool *changed)
{
u32 total_ets_bw = 0;
u8 max_tc = 0;
u8 i;
for (i = 0; i < HNAE3_MAX_TC; i++) {
if (ets->prio_tc[i] >= hdev->tc_max ||
i >= hdev->tc_max)
return -EINVAL;
if (ets->prio_tc[i] != hdev->tm_info.prio_tc[i])
*changed = true;
if (ets->prio_tc[i] > max_tc)
max_tc = ets->prio_tc[i];
switch (ets->tc_tsa[i]) {
case IEEE_8021QAZ_TSA_STRICT:
if (hdev->tm_info.tc_info[i].tc_sch_mode !=
HCLGE_SCH_MODE_SP)
*changed = true;
break;
case IEEE_8021QAZ_TSA_ETS:
if (hdev->tm_info.tc_info[i].tc_sch_mode !=
HCLGE_SCH_MODE_DWRR)
*changed = true;
total_ets_bw += ets->tc_tx_bw[i];
break;
default:
return -EINVAL;
}
}
if (total_ets_bw != BW_PERCENT)
return -EINVAL;
*tc = max_tc + 1;
if (*tc != hdev->tm_info.num_tc)
*changed = true;
return 0;
}
static int hclge_map_update(struct hnae3_handle *h)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
int ret;
ret = hclge_tm_map_cfg(hdev);
if (ret)
return ret;
ret = hclge_tm_schd_mode_hw(hdev);
if (ret)
return ret;
ret = hclge_pause_setup_hw(hdev);
if (ret)
return ret;
ret = hclge_buffer_alloc(hdev);
if (ret)
return ret;
return hclge_rss_init_hw(hdev);
}
static int hclge_client_setup_tc(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
struct hnae3_client *client;
struct hnae3_handle *handle;
int ret;
u32 i;
for (i = 0; i < hdev->num_vmdq_vport + 1; i++) {
handle = &vport[i].nic;
client = handle->client;
if (!client || !client->ops || !client->ops->setup_tc)
continue;
ret = client->ops->setup_tc(handle, hdev->tm_info.num_tc);
if (ret)
return ret;
}
return 0;
}
static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
bool map_changed = false;
u8 num_tc = 0;
int ret;
if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
ret = hclge_ets_validate(hdev, ets, &num_tc, &map_changed);
if (ret)
return ret;
hclge_tm_schd_info_update(hdev, num_tc);
ret = hclge_ieee_ets_to_tm_info(hdev, ets);
if (ret)
return ret;
if (map_changed) {
ret = hclge_client_setup_tc(hdev);
if (ret)
return ret;
}
return hclge_tm_dwrr_cfg(hdev);
}
static int hclge_ieee_getpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
u8 i, j, pfc_map, *prio_tc;
memset(pfc, 0, sizeof(*pfc));
pfc->pfc_cap = hdev->pfc_max;
prio_tc = hdev->tm_info.prio_tc;
pfc_map = hdev->tm_info.hw_pfc_map;
/* Pfc setting is based on TC */
for (i = 0; i < hdev->tm_info.num_tc; i++) {
for (j = 0; j < HNAE3_MAX_USER_PRIO; j++) {
if ((prio_tc[j] == i) && (pfc_map & BIT(i)))
pfc->pfc_en |= BIT(j);
}
}
return 0;
}
static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
u8 i, j, pfc_map, *prio_tc;
if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
prio_tc = hdev->tm_info.prio_tc;
pfc_map = 0;
for (i = 0; i < hdev->tm_info.num_tc; i++) {
for (j = 0; j < HNAE3_MAX_USER_PRIO; j++) {
if ((prio_tc[j] == i) && (pfc->pfc_en & BIT(j))) {
pfc_map |= BIT(i);
break;
}
}
}
if (pfc_map == hdev->tm_info.hw_pfc_map)
return 0;
hdev->tm_info.hw_pfc_map = pfc_map;
return hclge_pause_setup_hw(hdev);
}
/* DCBX configuration */
static u8 hclge_getdcbx(struct hnae3_handle *h)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
return hdev->dcbx_cap;
}
static u8 hclge_setdcbx(struct hnae3_handle *h, u8 mode)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
/* No support for LLD_MANAGED modes or CEE */
if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
(mode & DCB_CAP_DCBX_VER_CEE) ||
!(mode & DCB_CAP_DCBX_HOST))
return 1;
hdev->dcbx_cap = mode;
return 0;
}
static const struct hnae3_dcb_ops hns3_dcb_ops = {
.ieee_getets = hclge_ieee_getets,
.ieee_setets = hclge_ieee_setets,
.ieee_getpfc = hclge_ieee_getpfc,
.ieee_setpfc = hclge_ieee_setpfc,
.getdcbx = hclge_getdcbx,
.setdcbx = hclge_setdcbx,
.map_update = hclge_map_update,
};
void hclge_dcb_ops_set(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
struct hnae3_knic_private_info *kinfo;
/* Hdev does not support DCB or vport is
* not a pf, then dcb_ops is not set.
*/
if (!hnae3_dev_dcb_supported(hdev) ||
vport->vport_id != 0)
return;
kinfo = &vport->nic.kinfo;
kinfo->dcb_ops = &hns3_dcb_ops;
hdev->dcbx_cap = DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_HOST;
}
/*
* Copyright (c) 2016~2017 Hisilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __HCLGE_DCB_H__
#define __HCLGE_DCB_H__
#include "hclge_main.h"
#ifdef CONFIG_HNS3_DCB
void hclge_dcb_ops_set(struct hclge_dev *hdev);
#else
static inline void hclge_dcb_ops_set(struct hclge_dev *hdev) {}
#endif
#endif /* __HCLGE_DCB_H__ */
......@@ -421,8 +421,11 @@ struct hclge_dev {
#define HCLGE_FLAG_TC_BASE_SCH_MODE 1
#define HCLGE_FLAG_VNET_BASE_SCH_MODE 2
u8 tx_sch_mode;
u8 tc_max;
u8 pfc_max;
u8 default_up;
u8 dcbx_cap;
struct hclge_tm_info tm_info;
u16 num_msi;
......@@ -463,8 +466,6 @@ struct hclge_dev {
u32 pkt_buf_size; /* Total pf buf size for tx/rx */
u32 mps; /* Max packet size */
struct hclge_priv_buf *priv_buf;
struct hclge_shared_buf s_buf;
enum hclge_mta_dmac_sel_type mta_mac_sel_type;
bool enable_mta; /* Mutilcast filter enable */
......@@ -517,4 +518,7 @@ static inline int hclge_get_queue_id(struct hnae3_queue *queue)
int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex);
int hclge_set_vf_vlan_common(struct hclge_dev *vport, int vfid,
bool is_kill, u16 vlan, u8 qos, __be16 proto);
int hclge_buffer_alloc(struct hclge_dev *hdev);
int hclge_rss_init_hw(struct hclge_dev *hdev);
#endif
......@@ -124,6 +124,20 @@ static int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx)
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
static int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap,
u8 pfc_bitmap)
{
struct hclge_desc desc;
struct hclge_pfc_en_cmd *pfc = (struct hclge_pfc_en_cmd *)&desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PFC_PAUSE_EN, false);
pfc->tx_rx_en_bitmap = tx_rx_bitmap;
pfc->pri_en_bitmap = pfc_bitmap;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
static int hclge_fill_pri_array(struct hclge_dev *hdev, u8 *pri, u8 pri_id)
{
u8 tc;
......@@ -287,6 +301,34 @@ static int hclge_tm_pg_shapping_cfg(struct hclge_dev *hdev,
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
static int hclge_tm_port_shaper_cfg(struct hclge_dev *hdev)
{
struct hclge_port_shapping_cmd *shap_cfg_cmd;
struct hclge_desc desc;
u32 shapping_para = 0;
u8 ir_u, ir_b, ir_s;
int ret;
ret = hclge_shaper_para_calc(HCLGE_ETHER_MAX_RATE,
HCLGE_SHAPER_LVL_PORT,
&ir_b, &ir_u, &ir_s);
if (ret)
return ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PORT_SHAPPING, false);
shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data;
hclge_tm_set_field(shapping_para, IR_B, ir_b);
hclge_tm_set_field(shapping_para, IR_U, ir_u);
hclge_tm_set_field(shapping_para, IR_S, ir_s);
hclge_tm_set_field(shapping_para, BS_B, HCLGE_SHAPER_BS_U_DEF);
hclge_tm_set_field(shapping_para, BS_S, HCLGE_SHAPER_BS_S_DEF);
shap_cfg_cmd->port_shapping_para = cpu_to_le32(shapping_para);
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
static int hclge_tm_pri_shapping_cfg(struct hclge_dev *hdev,
enum hclge_shap_bucket bucket, u8 pri_id,
u8 ir_b, u8 ir_u, u8 ir_s,
......@@ -346,13 +388,13 @@ static int hclge_tm_pri_schd_mode_cfg(struct hclge_dev *hdev, u8 pri_id)
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
static int hclge_tm_qs_schd_mode_cfg(struct hclge_dev *hdev, u16 qs_id)
static int hclge_tm_qs_schd_mode_cfg(struct hclge_dev *hdev, u16 qs_id, u8 mode)
{
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_SCH_MODE_CFG, false);
if (hdev->tm_info.tc_info[qs_id].tc_sch_mode == HCLGE_SCH_MODE_DWRR)
if (mode == HCLGE_SCH_MODE_DWRR)
desc.data[1] = cpu_to_le32(HCLGE_TM_TX_SCHD_DWRR_MSK);
else
desc.data[1] = 0;
......@@ -444,6 +486,10 @@ static void hclge_tm_tc_info_init(struct hclge_dev *hdev)
hdev->tm_info.prio_tc[i] =
(i >= hdev->tm_info.num_tc) ? 0 : i;
/* DCB is enabled if we have more than 1 TC */
if (hdev->tm_info.num_tc > 1)
hdev->flag |= HCLGE_FLAG_DCB_ENABLE;
else
hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
}
......@@ -470,6 +516,24 @@ static void hclge_tm_pg_info_init(struct hclge_dev *hdev)
}
}
static void hclge_pfc_info_init(struct hclge_dev *hdev)
{
if (!(hdev->flag & HCLGE_FLAG_DCB_ENABLE)) {
if (hdev->fc_mode_last_time == HCLGE_FC_PFC)
dev_warn(&hdev->pdev->dev,
"DCB is disable, but last mode is FC_PFC\n");
hdev->tm_info.fc_mode = hdev->fc_mode_last_time;
} else if (hdev->tm_info.fc_mode != HCLGE_FC_PFC) {
/* fc_mode_last_time record the last fc_mode when
* DCB is enabled, so that fc_mode can be set to
* the correct value when DCB is disabled.
*/
hdev->fc_mode_last_time = hdev->tm_info.fc_mode;
hdev->tm_info.fc_mode = HCLGE_FC_PFC;
}
}
static int hclge_tm_schd_info_init(struct hclge_dev *hdev)
{
if ((hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE) &&
......@@ -482,8 +546,7 @@ static int hclge_tm_schd_info_init(struct hclge_dev *hdev)
hclge_tm_vport_info_update(hdev);
hdev->tm_info.fc_mode = HCLGE_FC_NONE;
hdev->fc_mode_last_time = hdev->tm_info.fc_mode;
hclge_pfc_info_init(hdev);
return 0;
}
......@@ -596,17 +659,18 @@ static int hclge_tm_pri_q_qs_cfg(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
int ret;
u32 i;
u32 i, k;
if (hdev->tx_sch_mode == HCLGE_FLAG_TC_BASE_SCH_MODE) {
/* Cfg qs -> pri mapping, one by one mapping */
for (k = 0; k < hdev->num_alloc_vport; k++)
for (i = 0; i < hdev->tm_info.num_tc; i++) {
ret = hclge_tm_qs_to_pri_map_cfg(hdev, i, i);
ret = hclge_tm_qs_to_pri_map_cfg(
hdev, vport[k].qs_offset + i, i);
if (ret)
return ret;
}
} else if (hdev->tx_sch_mode == HCLGE_FLAG_VNET_BASE_SCH_MODE) {
int k;
/* Cfg qs -> pri mapping, qs = tc, pri = vf, 8 qs -> 1 pri */
for (k = 0; k < hdev->num_alloc_vport; k++)
for (i = 0; i < HNAE3_MAX_TC; i++) {
......@@ -755,10 +819,11 @@ static int hclge_tm_pri_shaper_cfg(struct hclge_dev *hdev)
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;
u32 i;
u32 i, k;
for (i = 0; i < hdev->tm_info.num_tc; i++) {
pg_info =
......@@ -769,10 +834,14 @@ static int hclge_tm_pri_tc_base_dwrr_cfg(struct hclge_dev *hdev)
if (ret)
return ret;
ret = hclge_tm_qs_weight_cfg(hdev, i, dwrr);
for (k = 0; k < hdev->num_alloc_vport; k++) {
ret = hclge_tm_qs_weight_cfg(
hdev, vport[k].qs_offset + i,
vport[k].dwrr);
if (ret)
return ret;
}
}
return 0;
}
......@@ -835,10 +904,14 @@ static int hclge_tm_pri_dwrr_cfg(struct hclge_dev *hdev)
return 0;
}
static int hclge_tm_map_cfg(struct hclge_dev *hdev)
int hclge_tm_map_cfg(struct hclge_dev *hdev)
{
int ret;
ret = hclge_up_to_tc_map(hdev);
if (ret)
return ret;
ret = hclge_tm_pg_to_pri_map(hdev);
if (ret)
return ret;
......@@ -850,6 +923,10 @@ static int hclge_tm_shaper_cfg(struct hclge_dev *hdev)
{
int ret;
ret = hclge_tm_port_shaper_cfg(hdev);
if (ret)
return ret;
ret = hclge_tm_pg_shaper_cfg(hdev);
if (ret)
return ret;
......@@ -898,7 +975,10 @@ static int hclge_tm_schd_mode_vnet_base_cfg(struct hclge_vport *vport)
return ret;
for (i = 0; i < kinfo->num_tc; i++) {
ret = hclge_tm_qs_schd_mode_cfg(hdev, vport->qs_offset + i);
u8 sch_mode = hdev->tm_info.tc_info[i].tc_sch_mode;
ret = hclge_tm_qs_schd_mode_cfg(hdev, vport->qs_offset + i,
sch_mode);
if (ret)
return ret;
}
......@@ -910,7 +990,7 @@ static int hclge_tm_lvl34_schd_mode_cfg(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
int ret;
u8 i;
u8 i, k;
if (hdev->tx_sch_mode == HCLGE_FLAG_TC_BASE_SCH_MODE) {
for (i = 0; i < hdev->tm_info.num_tc; i++) {
......@@ -918,10 +998,14 @@ static int hclge_tm_lvl34_schd_mode_cfg(struct hclge_dev *hdev)
if (ret)
return ret;
ret = hclge_tm_qs_schd_mode_cfg(hdev, i);
for (k = 0; k < hdev->num_alloc_vport; k++) {
ret = hclge_tm_qs_schd_mode_cfg(
hdev, vport[k].qs_offset + i,
HCLGE_SCH_MODE_DWRR);
if (ret)
return ret;
}
}
} else {
for (i = 0; i < hdev->num_alloc_vport; i++) {
ret = hclge_tm_schd_mode_vnet_base_cfg(vport);
......@@ -935,7 +1019,7 @@ static int hclge_tm_lvl34_schd_mode_cfg(struct hclge_dev *hdev)
return 0;
}
static int hclge_tm_schd_mode_hw(struct hclge_dev *hdev)
int hclge_tm_schd_mode_hw(struct hclge_dev *hdev)
{
int ret;
......@@ -969,27 +1053,109 @@ static int hclge_tm_schd_setup_hw(struct hclge_dev *hdev)
return hclge_tm_schd_mode_hw(hdev);
}
static int hclge_pfc_setup_hw(struct hclge_dev *hdev)
{
u8 enable_bitmap = 0;
if (hdev->tm_info.fc_mode == HCLGE_FC_PFC)
enable_bitmap = HCLGE_TX_MAC_PAUSE_EN_MSK |
HCLGE_RX_MAC_PAUSE_EN_MSK;
return hclge_pfc_pause_en_cfg(hdev, enable_bitmap,
hdev->tm_info.hw_pfc_map);
}
static int hclge_mac_pause_setup_hw(struct hclge_dev *hdev)
{
bool tx_en, rx_en;
switch (hdev->tm_info.fc_mode) {
case HCLGE_FC_NONE:
tx_en = false;
rx_en = false;
break;
case HCLGE_FC_RX_PAUSE:
tx_en = false;
rx_en = true;
break;
case HCLGE_FC_TX_PAUSE:
tx_en = true;
rx_en = false;
break;
case HCLGE_FC_FULL:
tx_en = true;
rx_en = true;
break;
default:
tx_en = true;
rx_en = true;
}
return hclge_mac_pause_en_cfg(hdev, tx_en, rx_en);
}
int hclge_pause_setup_hw(struct hclge_dev *hdev)
{
bool en = hdev->tm_info.fc_mode != HCLGE_FC_PFC;
int ret;
u8 i;
ret = hclge_mac_pause_en_cfg(hdev, en, en);
if (ret)
return ret;
if (hdev->tm_info.fc_mode != HCLGE_FC_PFC)
return hclge_mac_pause_setup_hw(hdev);
/* Only DCB-supported dev supports qset back pressure setting */
/* Only DCB-supported dev supports qset back pressure and pfc cmd */
if (!hnae3_dev_dcb_supported(hdev))
return 0;
/* When MAC is GE Mode, hdev does not support pfc setting */
ret = hclge_pfc_setup_hw(hdev);
if (ret)
dev_warn(&hdev->pdev->dev, "set pfc pause failed:%d\n", ret);
for (i = 0; i < hdev->tm_info.num_tc; i++) {
ret = hclge_tm_qs_bp_cfg(hdev, i);
if (ret)
return ret;
}
return hclge_up_to_tc_map(hdev);
return 0;
}
int hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc)
{
struct hclge_vport *vport = hdev->vport;
struct hnae3_knic_private_info *kinfo;
u32 i, k;
for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) {
if (prio_tc[i] >= hdev->tm_info.num_tc)
return -EINVAL;
hdev->tm_info.prio_tc[i] = prio_tc[i];
for (k = 0; k < hdev->num_alloc_vport; k++) {
kinfo = &vport[k].nic.kinfo;
kinfo->prio_tc[i] = prio_tc[i];
}
}
return 0;
}
void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc)
{
u8 i, bit_map = 0;
hdev->tm_info.num_tc = num_tc;
for (i = 0; i < hdev->tm_info.num_tc; i++)
bit_map |= BIT(i);
if (!bit_map) {
bit_map = 1;
hdev->tm_info.num_tc = 1;
}
hdev->hw_tc_map = bit_map;
hclge_tm_schd_info_init(hdev);
}
int hclge_tm_init_hw(struct hclge_dev *hdev)
......@@ -1013,8 +1179,13 @@ int hclge_tm_init_hw(struct hclge_dev *hdev)
int hclge_tm_schd_init(struct hclge_dev *hdev)
{
int ret = hclge_tm_schd_info_init(hdev);
int ret;
/* fc_mode is HCLGE_FC_FULL on reset */
hdev->tm_info.fc_mode = HCLGE_FC_FULL;
hdev->fc_mode_last_time = hdev->tm_info.fc_mode;
ret = hclge_tm_schd_info_init(hdev);
if (ret)
return ret;
......
......@@ -94,6 +94,15 @@ struct hclge_bp_to_qs_map_cmd {
u32 rsvd1;
};
struct hclge_pfc_en_cmd {
u8 tx_rx_en_bitmap;
u8 pri_en_bitmap;
};
struct hclge_port_shapping_cmd {
__le32 port_shapping_para;
};
#define hclge_tm_set_field(dest, string, val) \
hnae_set_field((dest), (HCLGE_TM_SHAP_##string##_MSK), \
(HCLGE_TM_SHAP_##string##_LSH), val)
......@@ -103,4 +112,10 @@ struct hclge_bp_to_qs_map_cmd {
int hclge_tm_schd_init(struct hclge_dev *hdev);
int hclge_pause_setup_hw(struct hclge_dev *hdev);
int hclge_tm_schd_mode_hw(struct hclge_dev *hdev);
int hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc);
void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc);
int hclge_tm_dwrr_cfg(struct hclge_dev *hdev);
int hclge_tm_map_cfg(struct hclge_dev *hdev);
int hclge_tm_init_hw(struct hclge_dev *hdev);
#endif
/*
* Copyright (c) 2016-2017 Hisilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "hnae3.h"
#include "hns3_enet.h"
static
int hns3_dcbnl_ieee_getets(struct net_device *ndev, struct ieee_ets *ets)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
struct hnae3_handle *h = priv->ae_handle;
if (h->kinfo.dcb_ops->ieee_getets)
return h->kinfo.dcb_ops->ieee_getets(h, ets);
return -EOPNOTSUPP;
}
static
int hns3_dcbnl_ieee_setets(struct net_device *ndev, struct ieee_ets *ets)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
struct hnae3_handle *h = priv->ae_handle;
if (h->kinfo.dcb_ops->ieee_setets)
return h->kinfo.dcb_ops->ieee_setets(h, ets);
return -EOPNOTSUPP;
}
static
int hns3_dcbnl_ieee_getpfc(struct net_device *ndev, struct ieee_pfc *pfc)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
struct hnae3_handle *h = priv->ae_handle;
if (h->kinfo.dcb_ops->ieee_getpfc)
return h->kinfo.dcb_ops->ieee_getpfc(h, pfc);
return -EOPNOTSUPP;
}
static
int hns3_dcbnl_ieee_setpfc(struct net_device *ndev, struct ieee_pfc *pfc)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
struct hnae3_handle *h = priv->ae_handle;
if (h->kinfo.dcb_ops->ieee_setpfc)
return h->kinfo.dcb_ops->ieee_setpfc(h, pfc);
return -EOPNOTSUPP;
}
/* DCBX configuration */
static u8 hns3_dcbnl_getdcbx(struct net_device *ndev)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
struct hnae3_handle *h = priv->ae_handle;
if (h->kinfo.dcb_ops->getdcbx)
return h->kinfo.dcb_ops->getdcbx(h);
return 0;
}
/* return 0 if successful, otherwise fail */
static u8 hns3_dcbnl_setdcbx(struct net_device *ndev, u8 mode)
{
struct hns3_nic_priv *priv = netdev_priv(ndev);
struct hnae3_handle *h = priv->ae_handle;
if (h->kinfo.dcb_ops->setdcbx)
return h->kinfo.dcb_ops->setdcbx(h, mode);
return 1;
}
static const struct dcbnl_rtnl_ops hns3_dcbnl_ops = {
.ieee_getets = hns3_dcbnl_ieee_getets,
.ieee_setets = hns3_dcbnl_ieee_setets,
.ieee_getpfc = hns3_dcbnl_ieee_getpfc,
.ieee_setpfc = hns3_dcbnl_ieee_setpfc,
.getdcbx = hns3_dcbnl_getdcbx,
.setdcbx = hns3_dcbnl_setdcbx,
};
/* hclge_dcbnl_setup - DCBNL setup
* @handle: the corresponding vport handle
* Set up DCBNL
*/
void hns3_dcbnl_setup(struct hnae3_handle *handle)
{
struct net_device *dev = handle->kinfo.netdev;
if (!handle->kinfo.dcb_ops)
return;
dev->dcbnl_ops = &hns3_dcbnl_ops;
}
......@@ -196,6 +196,32 @@ static void hns3_vector_gl_rl_init(struct hns3_enet_tqp_vector *tqp_vector)
tqp_vector->tx_group.flow_level = HNS3_FLOW_LOW;
}
static int hns3_nic_set_real_num_queue(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = priv->ae_handle;
struct hnae3_knic_private_info *kinfo = &h->kinfo;
unsigned int queue_size = kinfo->rss_size * kinfo->num_tc;
int ret;
ret = netif_set_real_num_tx_queues(netdev, queue_size);
if (ret) {
netdev_err(netdev,
"netif_set_real_num_tx_queues fail, ret=%d!\n",
ret);
return ret;
}
ret = netif_set_real_num_rx_queues(netdev, queue_size);
if (ret) {
netdev_err(netdev,
"netif_set_real_num_rx_queues fail, ret=%d!\n", ret);
return ret;
}
return 0;
}
static int hns3_nic_net_up(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
......@@ -232,26 +258,13 @@ static int hns3_nic_net_up(struct net_device *netdev)
static int hns3_nic_net_open(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = priv->ae_handle;
int ret;
netif_carrier_off(netdev);
ret = netif_set_real_num_tx_queues(netdev, h->kinfo.num_tqps);
if (ret) {
netdev_err(netdev,
"netif_set_real_num_tx_queues fail, ret=%d!\n",
ret);
return ret;
}
ret = netif_set_real_num_rx_queues(netdev, h->kinfo.num_tqps);
if (ret) {
netdev_err(netdev,
"netif_set_real_num_rx_queues fail, ret=%d!\n", ret);
ret = hns3_nic_set_real_num_queue(netdev);
if (ret)
return ret;
}
ret = hns3_nic_net_up(netdev);
if (ret) {
......@@ -2790,6 +2803,8 @@ static int hns3_client_init(struct hnae3_handle *handle)
goto out_reg_netdev_fail;
}
hns3_dcbnl_setup(handle);
/* MTU range: (ETH_MIN_MTU(kernel default) - 9706) */
netdev->max_mtu = HNS3_MAX_MTU - (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
......@@ -2846,10 +2861,69 @@ static void hns3_link_status_change(struct hnae3_handle *handle, bool linkup)
}
}
static int hns3_client_setup_tc(struct hnae3_handle *handle, u8 tc)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct net_device *ndev = kinfo->netdev;
bool if_running = netif_running(ndev);
int ret;
u8 i;
if (tc > HNAE3_MAX_TC)
return -EINVAL;
if (!ndev)
return -ENODEV;
ret = netdev_set_num_tc(ndev, tc);
if (ret)
return ret;
if (if_running) {
(void)hns3_nic_net_stop(ndev);
msleep(100);
}
ret = (kinfo->dcb_ops && kinfo->dcb_ops->map_update) ?
kinfo->dcb_ops->map_update(handle) : -EOPNOTSUPP;
if (ret)
goto err_out;
if (tc <= 1) {
netdev_reset_tc(ndev);
goto out;
}
for (i = 0; i < HNAE3_MAX_TC; i++) {
struct hnae3_tc_info *tc_info = &kinfo->tc_info[i];
if (tc_info->enable)
netdev_set_tc_queue(ndev,
tc_info->tc,
tc_info->tqp_count,
tc_info->tqp_offset);
}
for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) {
netdev_set_prio_tc_map(ndev, i,
kinfo->prio_tc[i]);
}
out:
ret = hns3_nic_set_real_num_queue(ndev);
err_out:
if (if_running)
(void)hns3_nic_net_open(ndev);
return ret;
}
const struct hnae3_client_ops client_ops = {
.init_instance = hns3_client_init,
.uninit_instance = hns3_client_uninit,
.link_status_change = hns3_link_status_change,
.setup_tc = hns3_client_setup_tc,
};
/* hns3_init_module - Driver registration routine
......
......@@ -590,4 +590,11 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
void hns3_ethtool_set_ops(struct net_device *netdev);
int hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget);
#ifdef CONFIG_HNS3_DCB
void hns3_dcbnl_setup(struct hnae3_handle *handle);
#else
static inline void hns3_dcbnl_setup(struct hnae3_handle *handle) {}
#endif
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment