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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-09-28 10:35:12 -07:00
commit de9c8a6a5f
13 changed files with 927 additions and 119 deletions

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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;

View file

@ -0,0 +1,304 @@
/*
* 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;
}

View file

@ -0,0 +1,21 @@
/*
* 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__ */

View file

@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include "hclge_cmd.h"
#include "hclge_dcb.h"
#include "hclge_main.h"
#include "hclge_mdio.h"
#include "hclge_tm.h"
@ -30,7 +31,6 @@
#define HCLGE_64BIT_STATS_FIELD_OFF(f) (offsetof(struct hclge_64_bit_stats, f))
#define HCLGE_32BIT_STATS_FIELD_OFF(f) (offsetof(struct hclge_32_bit_stats, f))
static int hclge_rss_init_hw(struct hclge_dev *hdev);
static int hclge_set_mta_filter_mode(struct hclge_dev *hdev,
enum hclge_mta_dmac_sel_type mta_mac_sel,
bool enable);
@ -1058,7 +1058,7 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->hw.mac.phy_addr = cfg.phy_addr;
hdev->num_desc = cfg.tqp_desc_num;
hdev->tm_info.num_pg = 1;
hdev->tm_info.num_tc = cfg.tc_num;
hdev->tc_max = cfg.tc_num;
hdev->tm_info.hw_pfc_map = 0;
ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed);
@ -1067,15 +1067,25 @@ static int hclge_configure(struct hclge_dev *hdev)
return ret;
}
if ((hdev->tm_info.num_tc > HNAE3_MAX_TC) ||
(hdev->tm_info.num_tc < 1)) {
if ((hdev->tc_max > HNAE3_MAX_TC) ||
(hdev->tc_max < 1)) {
dev_warn(&hdev->pdev->dev, "TC num = %d.\n",
hdev->tm_info.num_tc);
hdev->tm_info.num_tc = 1;
hdev->tc_max);
hdev->tc_max = 1;
}
/* Dev does not support DCB */
if (!hnae3_dev_dcb_supported(hdev)) {
hdev->tc_max = 1;
hdev->pfc_max = 0;
} else {
hdev->pfc_max = hdev->tc_max;
}
hdev->tm_info.num_tc = hdev->tc_max;
/* Currently not support uncontiuous tc */
for (i = 0; i < cfg.tc_num; i++)
for (i = 0; i < hdev->tm_info.num_tc; i++)
hnae_set_bit(hdev->hw_tc_map, i, 1);
if (!hdev->num_vmdq_vport && !hdev->num_req_vfs)
@ -1324,7 +1334,8 @@ static int hclge_alloc_vport(struct hclge_dev *hdev)
return 0;
}
static int hclge_cmd_alloc_tx_buff(struct hclge_dev *hdev, u16 buf_size)
static int hclge_cmd_alloc_tx_buff(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
/* TX buffer size is unit by 128 byte */
#define HCLGE_BUF_SIZE_UNIT_SHIFT 7
@ -1337,10 +1348,13 @@ static int hclge_cmd_alloc_tx_buff(struct hclge_dev *hdev, u16 buf_size)
req = (struct hclge_tx_buff_alloc *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TX_BUFF_ALLOC, 0);
for (i = 0; i < HCLGE_TC_NUM; i++)
for (i = 0; i < HCLGE_TC_NUM; i++) {
u32 buf_size = buf_alloc->priv_buf[i].tx_buf_size;
req->tx_pkt_buff[i] =
cpu_to_le16((buf_size >> HCLGE_BUF_SIZE_UNIT_SHIFT) |
HCLGE_BUF_SIZE_UPDATE_EN_MSK);
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
@ -1352,9 +1366,10 @@ static int hclge_cmd_alloc_tx_buff(struct hclge_dev *hdev, u16 buf_size)
return 0;
}
static int hclge_tx_buffer_alloc(struct hclge_dev *hdev, u32 buf_size)
static int hclge_tx_buffer_alloc(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
int ret = hclge_cmd_alloc_tx_buff(hdev, buf_size);
int ret = hclge_cmd_alloc_tx_buff(hdev, buf_alloc);
if (ret) {
dev_err(&hdev->pdev->dev,
@ -1387,13 +1402,14 @@ static int hclge_get_pfc_enalbe_num(struct hclge_dev *hdev)
}
/* Get the number of pfc enabled TCs, which have private buffer */
static int hclge_get_pfc_priv_num(struct hclge_dev *hdev)
static int hclge_get_pfc_priv_num(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_priv_buf *priv;
int i, cnt = 0;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
priv = &hdev->priv_buf[i];
priv = &buf_alloc->priv_buf[i];
if ((hdev->tm_info.hw_pfc_map & BIT(i)) &&
priv->enable)
cnt++;
@ -1403,13 +1419,14 @@ static int hclge_get_pfc_priv_num(struct hclge_dev *hdev)
}
/* Get the number of pfc disabled TCs, which have private buffer */
static int hclge_get_no_pfc_priv_num(struct hclge_dev *hdev)
static int hclge_get_no_pfc_priv_num(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_priv_buf *priv;
int i, cnt = 0;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
priv = &hdev->priv_buf[i];
priv = &buf_alloc->priv_buf[i];
if (hdev->hw_tc_map & BIT(i) &&
!(hdev->tm_info.hw_pfc_map & BIT(i)) &&
priv->enable)
@ -1419,21 +1436,33 @@ static int hclge_get_no_pfc_priv_num(struct hclge_dev *hdev)
return cnt;
}
static u32 hclge_get_rx_priv_buff_alloced(struct hclge_dev *hdev)
static u32 hclge_get_rx_priv_buff_alloced(struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_priv_buf *priv;
u32 rx_priv = 0;
int i;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
priv = &hdev->priv_buf[i];
priv = &buf_alloc->priv_buf[i];
if (priv->enable)
rx_priv += priv->buf_size;
}
return rx_priv;
}
static bool hclge_is_rx_buf_ok(struct hclge_dev *hdev, u32 rx_all)
static u32 hclge_get_tx_buff_alloced(struct hclge_pkt_buf_alloc *buf_alloc)
{
u32 i, total_tx_size = 0;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
total_tx_size += buf_alloc->priv_buf[i].tx_buf_size;
return total_tx_size;
}
static bool hclge_is_rx_buf_ok(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc,
u32 rx_all)
{
u32 shared_buf_min, shared_buf_tc, shared_std;
int tc_num, pfc_enable_num;
@ -1454,46 +1483,74 @@ static bool hclge_is_rx_buf_ok(struct hclge_dev *hdev, u32 rx_all)
hdev->mps;
shared_std = max_t(u32, shared_buf_min, shared_buf_tc);
rx_priv = hclge_get_rx_priv_buff_alloced(hdev);
rx_priv = hclge_get_rx_priv_buff_alloced(buf_alloc);
if (rx_all <= rx_priv + shared_std)
return false;
shared_buf = rx_all - rx_priv;
hdev->s_buf.buf_size = shared_buf;
hdev->s_buf.self.high = shared_buf;
hdev->s_buf.self.low = 2 * hdev->mps;
buf_alloc->s_buf.buf_size = shared_buf;
buf_alloc->s_buf.self.high = shared_buf;
buf_alloc->s_buf.self.low = 2 * hdev->mps;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
if ((hdev->hw_tc_map & BIT(i)) &&
(hdev->tm_info.hw_pfc_map & BIT(i))) {
hdev->s_buf.tc_thrd[i].low = hdev->mps;
hdev->s_buf.tc_thrd[i].high = 2 * hdev->mps;
buf_alloc->s_buf.tc_thrd[i].low = hdev->mps;
buf_alloc->s_buf.tc_thrd[i].high = 2 * hdev->mps;
} else {
hdev->s_buf.tc_thrd[i].low = 0;
hdev->s_buf.tc_thrd[i].high = hdev->mps;
buf_alloc->s_buf.tc_thrd[i].low = 0;
buf_alloc->s_buf.tc_thrd[i].high = hdev->mps;
}
}
return true;
}
static int hclge_tx_buffer_calc(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
u32 i, total_size;
total_size = hdev->pkt_buf_size;
/* alloc tx buffer for all enabled tc */
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i];
if (total_size < HCLGE_DEFAULT_TX_BUF)
return -ENOMEM;
if (hdev->hw_tc_map & BIT(i))
priv->tx_buf_size = HCLGE_DEFAULT_TX_BUF;
else
priv->tx_buf_size = 0;
total_size -= priv->tx_buf_size;
}
return 0;
}
/* hclge_rx_buffer_calc: calculate the rx private buffer size for all TCs
* @hdev: pointer to struct hclge_dev
* @tx_size: the allocated tx buffer for all TCs
* @buf_alloc: pointer to buffer calculation data
* @return: 0: calculate sucessful, negative: fail
*/
int hclge_rx_buffer_calc(struct hclge_dev *hdev, u32 tx_size)
int hclge_rx_buffer_calc(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
u32 rx_all = hdev->pkt_buf_size - tx_size;
u32 rx_all = hdev->pkt_buf_size;
int no_pfc_priv_num, pfc_priv_num;
struct hclge_priv_buf *priv;
int i;
rx_all -= hclge_get_tx_buff_alloced(buf_alloc);
/* When DCB is not supported, rx private
* buffer is not allocated.
*/
if (!hnae3_dev_dcb_supported(hdev)) {
if (!hclge_is_rx_buf_ok(hdev, rx_all))
if (!hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all))
return -ENOMEM;
return 0;
@ -1501,7 +1558,7 @@ int hclge_rx_buffer_calc(struct hclge_dev *hdev, u32 tx_size)
/* step 1, try to alloc private buffer for all enabled tc */
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
priv = &hdev->priv_buf[i];
priv = &buf_alloc->priv_buf[i];
if (hdev->hw_tc_map & BIT(i)) {
priv->enable = 1;
if (hdev->tm_info.hw_pfc_map & BIT(i)) {
@ -1522,14 +1579,14 @@ int hclge_rx_buffer_calc(struct hclge_dev *hdev, u32 tx_size)
}
}
if (hclge_is_rx_buf_ok(hdev, rx_all))
if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all))
return 0;
/* step 2, try to decrease the buffer size of
* no pfc TC's private buffer
*/
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
priv = &hdev->priv_buf[i];
priv = &buf_alloc->priv_buf[i];
priv->enable = 0;
priv->wl.low = 0;
@ -1552,18 +1609,18 @@ int hclge_rx_buffer_calc(struct hclge_dev *hdev, u32 tx_size)
}
}
if (hclge_is_rx_buf_ok(hdev, rx_all))
if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all))
return 0;
/* step 3, try to reduce the number of pfc disabled TCs,
* which have private buffer
*/
/* get the total no pfc enable TC number, which have private buffer */
no_pfc_priv_num = hclge_get_no_pfc_priv_num(hdev);
no_pfc_priv_num = hclge_get_no_pfc_priv_num(hdev, buf_alloc);
/* let the last to be cleared first */
for (i = HCLGE_MAX_TC_NUM - 1; i >= 0; i--) {
priv = &hdev->priv_buf[i];
priv = &buf_alloc->priv_buf[i];
if (hdev->hw_tc_map & BIT(i) &&
!(hdev->tm_info.hw_pfc_map & BIT(i))) {
@ -1575,22 +1632,22 @@ int hclge_rx_buffer_calc(struct hclge_dev *hdev, u32 tx_size)
no_pfc_priv_num--;
}
if (hclge_is_rx_buf_ok(hdev, rx_all) ||
if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all) ||
no_pfc_priv_num == 0)
break;
}
if (hclge_is_rx_buf_ok(hdev, rx_all))
if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all))
return 0;
/* step 4, try to reduce the number of pfc enabled TCs
* which have private buffer.
*/
pfc_priv_num = hclge_get_pfc_priv_num(hdev);
pfc_priv_num = hclge_get_pfc_priv_num(hdev, buf_alloc);
/* let the last to be cleared first */
for (i = HCLGE_MAX_TC_NUM - 1; i >= 0; i--) {
priv = &hdev->priv_buf[i];
priv = &buf_alloc->priv_buf[i];
if (hdev->hw_tc_map & BIT(i) &&
hdev->tm_info.hw_pfc_map & BIT(i)) {
@ -1602,17 +1659,18 @@ int hclge_rx_buffer_calc(struct hclge_dev *hdev, u32 tx_size)
pfc_priv_num--;
}
if (hclge_is_rx_buf_ok(hdev, rx_all) ||
if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all) ||
pfc_priv_num == 0)
break;
}
if (hclge_is_rx_buf_ok(hdev, rx_all))
if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all))
return 0;
return -ENOMEM;
}
static int hclge_rx_priv_buf_alloc(struct hclge_dev *hdev)
static int hclge_rx_priv_buf_alloc(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_rx_priv_buff *req;
struct hclge_desc desc;
@ -1624,7 +1682,7 @@ static int hclge_rx_priv_buf_alloc(struct hclge_dev *hdev)
/* Alloc private buffer TCs */
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
struct hclge_priv_buf *priv = &hdev->priv_buf[i];
struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i];
req->buf_num[i] =
cpu_to_le16(priv->buf_size >> HCLGE_BUF_UNIT_S);
@ -1633,7 +1691,7 @@ static int hclge_rx_priv_buf_alloc(struct hclge_dev *hdev)
}
req->shared_buf =
cpu_to_le16((hdev->s_buf.buf_size >> HCLGE_BUF_UNIT_S) |
cpu_to_le16((buf_alloc->s_buf.buf_size >> HCLGE_BUF_UNIT_S) |
(1 << HCLGE_TC0_PRI_BUF_EN_B));
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@ -1648,7 +1706,8 @@ static int hclge_rx_priv_buf_alloc(struct hclge_dev *hdev)
#define HCLGE_PRIV_ENABLE(a) ((a) > 0 ? 1 : 0)
static int hclge_rx_priv_wl_config(struct hclge_dev *hdev)
static int hclge_rx_priv_wl_config(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_rx_priv_wl_buf *req;
struct hclge_priv_buf *priv;
@ -1668,7 +1727,9 @@ static int hclge_rx_priv_wl_config(struct hclge_dev *hdev)
desc[i].flag &= ~cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
for (j = 0; j < HCLGE_TC_NUM_ONE_DESC; j++) {
priv = &hdev->priv_buf[i * HCLGE_TC_NUM_ONE_DESC + j];
u32 idx = i * HCLGE_TC_NUM_ONE_DESC + j;
priv = &buf_alloc->priv_buf[idx];
req->tc_wl[j].high =
cpu_to_le16(priv->wl.high >> HCLGE_BUF_UNIT_S);
req->tc_wl[j].high |=
@ -1693,9 +1754,10 @@ static int hclge_rx_priv_wl_config(struct hclge_dev *hdev)
return 0;
}
static int hclge_common_thrd_config(struct hclge_dev *hdev)
static int hclge_common_thrd_config(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_shared_buf *s_buf = &hdev->s_buf;
struct hclge_shared_buf *s_buf = &buf_alloc->s_buf;
struct hclge_rx_com_thrd *req;
struct hclge_desc desc[2];
struct hclge_tc_thrd *tc;
@ -1739,9 +1801,10 @@ static int hclge_common_thrd_config(struct hclge_dev *hdev)
return 0;
}
static int hclge_common_wl_config(struct hclge_dev *hdev)
static int hclge_common_wl_config(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_shared_buf *buf = &hdev->s_buf;
struct hclge_shared_buf *buf = &buf_alloc->s_buf;
struct hclge_rx_com_wl *req;
struct hclge_desc desc;
int ret;
@ -1771,63 +1834,68 @@ static int hclge_common_wl_config(struct hclge_dev *hdev)
int hclge_buffer_alloc(struct hclge_dev *hdev)
{
u32 tx_buf_size = HCLGE_DEFAULT_TX_BUF;
struct hclge_pkt_buf_alloc *pkt_buf;
int ret;
hdev->priv_buf = devm_kmalloc_array(&hdev->pdev->dev, HCLGE_MAX_TC_NUM,
sizeof(struct hclge_priv_buf),
GFP_KERNEL | __GFP_ZERO);
if (!hdev->priv_buf)
pkt_buf = kzalloc(sizeof(*pkt_buf), GFP_KERNEL);
if (!pkt_buf)
return -ENOMEM;
ret = hclge_tx_buffer_alloc(hdev, tx_buf_size);
ret = hclge_tx_buffer_calc(hdev, pkt_buf);
if (ret) {
dev_err(&hdev->pdev->dev,
"could not calc tx buffer size for all TCs %d\n", ret);
goto out;
}
ret = hclge_tx_buffer_alloc(hdev, pkt_buf);
if (ret) {
dev_err(&hdev->pdev->dev,
"could not alloc tx buffers %d\n", ret);
return ret;
goto out;
}
ret = hclge_rx_buffer_calc(hdev, tx_buf_size);
ret = hclge_rx_buffer_calc(hdev, pkt_buf);
if (ret) {
dev_err(&hdev->pdev->dev,
"could not calc rx priv buffer size for all TCs %d\n",
ret);
return ret;
goto out;
}
ret = hclge_rx_priv_buf_alloc(hdev);
ret = hclge_rx_priv_buf_alloc(hdev, pkt_buf);
if (ret) {
dev_err(&hdev->pdev->dev, "could not alloc rx priv buffer %d\n",
ret);
return ret;
goto out;
}
if (hnae3_dev_dcb_supported(hdev)) {
ret = hclge_rx_priv_wl_config(hdev);
ret = hclge_rx_priv_wl_config(hdev, pkt_buf);
if (ret) {
dev_err(&hdev->pdev->dev,
"could not configure rx private waterline %d\n",
ret);
return ret;
goto out;
}
ret = hclge_common_thrd_config(hdev);
ret = hclge_common_thrd_config(hdev, pkt_buf);
if (ret) {
dev_err(&hdev->pdev->dev,
"could not configure common threshold %d\n",
ret);
return ret;
goto out;
}
}
ret = hclge_common_wl_config(hdev);
if (ret) {
ret = hclge_common_wl_config(hdev, pkt_buf);
if (ret)
dev_err(&hdev->pdev->dev,
"could not configure common waterline %d\n", ret);
return ret;
}
return 0;
out:
kfree(pkt_buf);
return ret;
}
static int hclge_init_roce_base_info(struct hclge_vport *vport)
@ -2597,7 +2665,7 @@ static int hclge_get_tc_size(struct hnae3_handle *handle)
return hdev->rss_size_max;
}
static int hclge_rss_init_hw(struct hclge_dev *hdev)
int hclge_rss_init_hw(struct hclge_dev *hdev)
{
const u8 hfunc = HCLGE_RSS_HASH_ALGO_TOEPLITZ;
struct hclge_vport *vport = hdev->vport;
@ -4181,6 +4249,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
return ret;
}
hclge_dcb_ops_set(hdev);
setup_timer(&hdev->service_timer, hclge_service_timer,
(unsigned long)hdev);
INIT_WORK(&hdev->service_task, hclge_service_task);

View file

@ -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

View file

@ -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,7 +486,11 @@ 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;
hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
/* 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;
}
static void hclge_tm_pg_info_init(struct hclge_dev *hdev)
@ -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 (i = 0; i < hdev->tm_info.num_tc; i++) {
ret = hclge_tm_qs_to_pri_map_cfg(hdev, i, i);
if (ret)
return ret;
}
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, 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,9 +834,13 @@ 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);
if (ret)
return ret;
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,9 +998,13 @@ 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);
if (ret)
return ret;
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++) {
@ -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;

View file

@ -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

View file

@ -0,0 +1,106 @@
/*
* 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;
}

View file

@ -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);
ret = hns3_nic_set_real_num_queue(netdev);
if (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);
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

View file

@ -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