mirror of
https://github.com/torvalds/linux.git
synced 2024-12-07 19:41:31 +00:00
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:
commit
de9c8a6a5f
@ -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;
|
||||
|
304
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
Normal file
304
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
Normal 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;
|
||||
}
|
21
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h
Normal file
21
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.h
Normal 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__ */
|
@ -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);
|
||||
|
@ -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,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;
|
||||
|
||||
|
@ -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
|
||||
|
106
drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_dcbnl.c
Normal file
106
drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_dcbnl.c
Normal 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;
|
||||
}
|
@ -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 @@ out_start_err:
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user