fbb7a43a36
This patch support query HW descriptor from hns3 device. HW descriptor is also called BD (buffer description) which is shared memory between software and hardware. Signed-off-by: Min Hu (Connor) <humin29@huawei.com> Signed-off-by: Dongdong Liu <liudongdong3@huawei.com> Acked-by: Ferruh Yigit <ferruh.yigit@xilinx.com>
1022 lines
27 KiB
C
1022 lines
27 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(C) 2022 HiSilicon Limited
|
|
*/
|
|
|
|
#include <rte_malloc.h>
|
|
|
|
#include "hns3_common.h"
|
|
#include "hns3_logs.h"
|
|
#include "hns3_regs.h"
|
|
#include "hns3_rxtx.h"
|
|
#include "hns3_dump.h"
|
|
|
|
#define HNS3_BD_DW_NUM 8
|
|
#define HNS3_BD_ADDRESS_LAST_DW 2
|
|
|
|
static const char *
|
|
hns3_get_adapter_state_name(enum hns3_adapter_state state)
|
|
{
|
|
const struct {
|
|
enum hns3_adapter_state state;
|
|
const char *name;
|
|
} adapter_state_name[] = {
|
|
{HNS3_NIC_UNINITIALIZED, "UNINITIALIZED"},
|
|
{HNS3_NIC_INITIALIZED, "INITIALIZED"},
|
|
{HNS3_NIC_CONFIGURING, "CONFIGURING"},
|
|
{HNS3_NIC_CONFIGURED, "CONFIGURED"},
|
|
{HNS3_NIC_STARTING, "STARTING"},
|
|
{HNS3_NIC_STARTED, "STARTED"},
|
|
{HNS3_NIC_STOPPING, "STOPPING"},
|
|
{HNS3_NIC_CLOSING, "CLOSING"},
|
|
{HNS3_NIC_CLOSED, "CLOSED"},
|
|
{HNS3_NIC_REMOVED, "REMOVED"},
|
|
{HNS3_NIC_NSTATES, "NSTATES"},
|
|
};
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < RTE_DIM(adapter_state_name); i++)
|
|
if (state == adapter_state_name[i].state)
|
|
return adapter_state_name[i].name;
|
|
|
|
return "Unknown";
|
|
}
|
|
|
|
static const char *
|
|
hns3_get_io_func_hint_name(uint32_t hint)
|
|
{
|
|
switch (hint) {
|
|
case HNS3_IO_FUNC_HINT_NONE:
|
|
return "none";
|
|
case HNS3_IO_FUNC_HINT_VEC:
|
|
return "vec";
|
|
case HNS3_IO_FUNC_HINT_SVE:
|
|
return "sve";
|
|
case HNS3_IO_FUNC_HINT_SIMPLE:
|
|
return "simple";
|
|
case HNS3_IO_FUNC_HINT_COMMON:
|
|
return "common";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_get_dev_mac_info(FILE *file, struct hns3_adapter *hns)
|
|
{
|
|
struct hns3_hw *hw = &hns->hw;
|
|
struct hns3_pf *pf = &hns->pf;
|
|
|
|
fprintf(file, " - MAC Info:\n");
|
|
fprintf(file,
|
|
"\t -- query_type=%u\n"
|
|
"\t -- supported_speed=0x%x\n"
|
|
"\t -- advertising=0x%x\n"
|
|
"\t -- lp_advertising=0x%x\n"
|
|
"\t -- support_autoneg=%s\n"
|
|
"\t -- support_fc_autoneg=%s\n",
|
|
hw->mac.query_type,
|
|
hw->mac.supported_speed,
|
|
hw->mac.advertising,
|
|
hw->mac.lp_advertising,
|
|
hw->mac.support_autoneg != 0 ? "Yes" : "No",
|
|
pf->support_fc_autoneg ? "Yes" : "No");
|
|
}
|
|
|
|
static void
|
|
hns3_get_dev_feature_capability(FILE *file, struct hns3_hw *hw)
|
|
{
|
|
const struct {
|
|
enum hns3_dev_cap cap;
|
|
const char *name;
|
|
} caps_name[] = {
|
|
{HNS3_DEV_SUPPORT_DCB_B, "DCB"},
|
|
{HNS3_DEV_SUPPORT_COPPER_B, "COPPER"},
|
|
{HNS3_DEV_SUPPORT_FD_QUEUE_REGION_B, "FD QUEUE REGION"},
|
|
{HNS3_DEV_SUPPORT_PTP_B, "PTP"},
|
|
{HNS3_DEV_SUPPORT_TX_PUSH_B, "TX PUSH"},
|
|
{HNS3_DEV_SUPPORT_INDEP_TXRX_B, "INDEP TXRX"},
|
|
{HNS3_DEV_SUPPORT_STASH_B, "STASH"},
|
|
{HNS3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, "RXD Advanced Layout"},
|
|
{HNS3_DEV_SUPPORT_OUTER_UDP_CKSUM_B, "OUTER UDP CKSUM"},
|
|
{HNS3_DEV_SUPPORT_RAS_IMP_B, "RAS IMP"},
|
|
{HNS3_DEV_SUPPORT_TM_B, "TM"},
|
|
{HNS3_DEV_SUPPORT_VF_VLAN_FLT_MOD_B, "VF VLAN FILTER MOD"},
|
|
};
|
|
uint32_t i;
|
|
|
|
fprintf(file, " - Dev Capability:\n");
|
|
for (i = 0; i < RTE_DIM(caps_name); i++)
|
|
fprintf(file, "\t -- support %s: %s\n", caps_name[i].name,
|
|
hns3_get_bit(hw->capability, caps_name[i].cap) ? "Yes" :
|
|
"No");
|
|
}
|
|
|
|
static const char *
|
|
hns3_get_fdir_tuple_name(uint32_t index)
|
|
{
|
|
const char * const tuple_name[] = {
|
|
"outer_dst_mac",
|
|
"outer_src_mac",
|
|
"outer_vlan_1st_tag",
|
|
"outer_vlan_2nd_tag",
|
|
"outer_eth_type",
|
|
"outer_l2_rsv",
|
|
"outer_ip_tos",
|
|
"outer_ip_proto",
|
|
"outer_src_ip",
|
|
"outer_dst_ip",
|
|
"outer_l3_rsv",
|
|
"outer_src_port",
|
|
"outer_dst_port",
|
|
"outer_l4_rsv",
|
|
"outer_tun_vni",
|
|
"outer_tun_flow_id",
|
|
"inner_dst_mac",
|
|
"inner_src_mac",
|
|
"inner_vlan_tag1",
|
|
"inner_vlan_tag2",
|
|
"inner_eth_type",
|
|
"inner_l2_rsv",
|
|
"inner_ip_tos",
|
|
"inner_ip_proto",
|
|
"inner_src_ip",
|
|
"inner_dst_ip",
|
|
"inner_l3_rsv",
|
|
"inner_src_port",
|
|
"inner_dst_port",
|
|
"inner_sctp_tag",
|
|
};
|
|
if (index < RTE_DIM(tuple_name))
|
|
return tuple_name[index];
|
|
else
|
|
return "unknown";
|
|
}
|
|
|
|
static void
|
|
hns3_get_fdir_basic_info(FILE *file, struct hns3_pf *pf)
|
|
{
|
|
#define HNS3_PERLINE_TUPLE_NAME_LEN 4
|
|
struct hns3_fd_cfg *fdcfg = &pf->fdir.fd_cfg;
|
|
uint32_t i, count = 0;
|
|
|
|
fprintf(file, " - Fdir Info:\n");
|
|
fprintf(file,
|
|
"\t -- mode=%u max_key_len=%u rule_num:%u cnt_num:%u\n"
|
|
"\t -- key_sel=%u tuple_active=0x%x meta_data_active=0x%x\n"
|
|
"\t -- ipv6_word_en: in_s=%u in_d=%u out_s=%u out_d=%u\n"
|
|
"\t -- active_tuples:\n",
|
|
fdcfg->fd_mode, fdcfg->max_key_length,
|
|
fdcfg->rule_num[HNS3_FD_STAGE_1],
|
|
fdcfg->cnt_num[HNS3_FD_STAGE_1],
|
|
fdcfg->key_cfg[HNS3_FD_STAGE_1].key_sel,
|
|
fdcfg->key_cfg[HNS3_FD_STAGE_1].tuple_active,
|
|
fdcfg->key_cfg[HNS3_FD_STAGE_1].meta_data_active,
|
|
fdcfg->key_cfg[HNS3_FD_STAGE_1].inner_sipv6_word_en,
|
|
fdcfg->key_cfg[HNS3_FD_STAGE_1].inner_dipv6_word_en,
|
|
fdcfg->key_cfg[HNS3_FD_STAGE_1].outer_sipv6_word_en,
|
|
fdcfg->key_cfg[HNS3_FD_STAGE_1].outer_dipv6_word_en);
|
|
|
|
for (i = 0; i < MAX_TUPLE; i++) {
|
|
if (!(fdcfg->key_cfg[HNS3_FD_STAGE_1].tuple_active & BIT(i)))
|
|
continue;
|
|
if (count % HNS3_PERLINE_TUPLE_NAME_LEN == 0)
|
|
fprintf(file, "\t ");
|
|
fprintf(file, " %s", hns3_get_fdir_tuple_name(i));
|
|
count++;
|
|
if (count % HNS3_PERLINE_TUPLE_NAME_LEN == 0)
|
|
fprintf(file, "\n");
|
|
}
|
|
if (count % HNS3_PERLINE_TUPLE_NAME_LEN)
|
|
fprintf(file, "\n");
|
|
}
|
|
|
|
static void
|
|
hns3_get_device_basic_info(FILE *file, struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_adapter *hns = dev->data->dev_private;
|
|
struct hns3_hw *hw = &hns->hw;
|
|
|
|
fprintf(file,
|
|
" - Device Base Info:\n"
|
|
"\t -- name: %s\n"
|
|
"\t -- adapter_state=%s\n"
|
|
"\t -- nb_rx_queues=%u nb_tx_queues=%u\n"
|
|
"\t -- total_tqps_num=%u tqps_num=%u intr_tqps_num=%u\n"
|
|
"\t -- rss_size_max=%u alloc_rss_size=%u tx_qnum_per_tc=%u\n"
|
|
"\t -- min_tx_pkt_len=%u intr_mapping_mode=%u vlan_mode=%u\n"
|
|
"\t -- tso_mode=%u max_non_tso_bd_num=%u\n"
|
|
"\t -- max_tm_rate=%u Mbps\n"
|
|
"\t -- set link down: %s\n"
|
|
"\t -- rx_func_hint=%s tx_func_hint=%s\n"
|
|
"\t -- dev_flags: lsc=%d\n"
|
|
"\t -- intr_conf: lsc=%u rxq=%u\n",
|
|
dev->data->name,
|
|
hns3_get_adapter_state_name(hw->adapter_state),
|
|
dev->data->nb_rx_queues, dev->data->nb_tx_queues,
|
|
hw->total_tqps_num, hw->tqps_num, hw->intr_tqps_num,
|
|
hw->rss_size_max, hw->alloc_rss_size, hw->tx_qnum_per_tc,
|
|
hw->min_tx_pkt_len, hw->intr.mapping_mode, hw->vlan_mode,
|
|
hw->tso_mode, hw->max_non_tso_bd_num,
|
|
hw->max_tm_rate,
|
|
hw->set_link_down ? "Yes" : "No",
|
|
hns3_get_io_func_hint_name(hns->rx_func_hint),
|
|
hns3_get_io_func_hint_name(hns->tx_func_hint),
|
|
!!(dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC),
|
|
dev->data->dev_conf.intr_conf.lsc,
|
|
dev->data->dev_conf.intr_conf.rxq);
|
|
}
|
|
|
|
static struct hns3_rx_queue *
|
|
hns3_get_rx_queue(struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
struct hns3_rx_queue *rxq;
|
|
uint32_t queue_id;
|
|
void **rx_queues;
|
|
|
|
for (queue_id = 0; queue_id < dev->data->nb_rx_queues; queue_id++) {
|
|
rx_queues = dev->data->rx_queues;
|
|
if (rx_queues == NULL || rx_queues[queue_id] == NULL) {
|
|
hns3_err(hw, "detect rx_queues is NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
rxq = (struct hns3_rx_queue *)rx_queues[queue_id];
|
|
if (rxq->rx_deferred_start)
|
|
continue;
|
|
|
|
return rx_queues[queue_id];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct hns3_tx_queue *
|
|
hns3_get_tx_queue(struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
struct hns3_tx_queue *txq;
|
|
uint32_t queue_id;
|
|
void **tx_queues;
|
|
|
|
for (queue_id = 0; queue_id < dev->data->nb_tx_queues; queue_id++) {
|
|
tx_queues = dev->data->tx_queues;
|
|
if (tx_queues == NULL || tx_queues[queue_id] == NULL) {
|
|
hns3_err(hw, "detect tx_queues is NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
txq = (struct hns3_tx_queue *)tx_queues[queue_id];
|
|
if (txq->tx_deferred_start)
|
|
continue;
|
|
|
|
return tx_queues[queue_id];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
hns3_get_rxtx_fake_queue_info(FILE *file, struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
struct hns3_rx_queue *rxq;
|
|
struct hns3_tx_queue *txq;
|
|
uint32_t queue_id = 0;
|
|
void **rx_queues;
|
|
void **tx_queues;
|
|
|
|
if (hns3_dev_get_support(hw, INDEP_TXRX))
|
|
return;
|
|
|
|
if (dev->data->nb_rx_queues < dev->data->nb_tx_queues) {
|
|
rx_queues = hw->fkq_data.rx_queues;
|
|
if (rx_queues == NULL || rx_queues[queue_id] == NULL) {
|
|
hns3_err(hw, "detect rx_queues is NULL!\n");
|
|
return;
|
|
}
|
|
rxq = (struct hns3_rx_queue *)rx_queues[queue_id];
|
|
|
|
fprintf(file,
|
|
"\t -- first fake_queue info:\n"
|
|
"\t Rx: port=%u nb_desc=%u free_thresh=%u\n",
|
|
rxq->port_id, rxq->nb_rx_desc, rxq->rx_free_thresh);
|
|
} else if (dev->data->nb_rx_queues > dev->data->nb_tx_queues) {
|
|
tx_queues = hw->fkq_data.tx_queues;
|
|
queue_id = 0;
|
|
|
|
if (tx_queues == NULL || tx_queues[queue_id] == NULL) {
|
|
hns3_err(hw, "detect tx_queues is NULL!\n");
|
|
return;
|
|
}
|
|
txq = (struct hns3_tx_queue *)tx_queues[queue_id];
|
|
|
|
fprintf(file,
|
|
"\t -- first fake_queue info:\n"
|
|
"\t Tx: port=%u nb_desc=%u\n",
|
|
txq->port_id, txq->nb_tx_desc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_get_queue_enable_state(struct hns3_hw *hw, uint32_t *queue_state,
|
|
uint32_t nb_queues, bool is_rxq)
|
|
{
|
|
#define HNS3_QUEUE_NUM_PER_STATS (sizeof(*queue_state) * HNS3_UINT8_BIT)
|
|
uint32_t queue_en_reg;
|
|
uint32_t reg_offset;
|
|
uint32_t state;
|
|
uint32_t i;
|
|
|
|
queue_en_reg = is_rxq ? HNS3_RING_RX_EN_REG : HNS3_RING_TX_EN_REG;
|
|
for (i = 0; i < nb_queues; i++) {
|
|
reg_offset = hns3_get_tqp_reg_offset(i);
|
|
state = hns3_read_dev(hw, reg_offset + HNS3_RING_EN_REG);
|
|
if (hns3_dev_get_support(hw, INDEP_TXRX))
|
|
state = state && hns3_read_dev(hw, reg_offset +
|
|
queue_en_reg);
|
|
hns3_set_bit(queue_state[i / HNS3_QUEUE_NUM_PER_STATS],
|
|
i % HNS3_QUEUE_NUM_PER_STATS, state);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_print_queue_state_perline(FILE *file, const uint32_t *queue_state,
|
|
uint32_t nb_queues, uint32_t line_num)
|
|
{
|
|
#define HNS3_NUM_QUEUE_PER_LINE (sizeof(uint32_t) * HNS3_UINT8_BIT)
|
|
uint32_t id = line_num * HNS3_NUM_QUEUE_PER_LINE;
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < HNS3_NUM_QUEUE_PER_LINE; i++) {
|
|
fprintf(file, "%1lx", hns3_get_bit(queue_state[line_num], i));
|
|
|
|
if (id % HNS3_UINT8_BIT == HNS3_UINT8_BIT - 1) {
|
|
fprintf(file, "%s",
|
|
i == HNS3_NUM_QUEUE_PER_LINE - 1 ? "\n" : ":");
|
|
}
|
|
id++;
|
|
if (id >= nb_queues) {
|
|
fprintf(file, "\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_display_queue_enable_state(FILE *file, const uint32_t *queue_state,
|
|
uint32_t nb_queues, bool is_rxq)
|
|
{
|
|
#define HNS3_NUM_QUEUE_PER_LINE (sizeof(uint32_t) * HNS3_UINT8_BIT)
|
|
uint32_t i;
|
|
|
|
fprintf(file, "\t %s queue id | enable state bitMap\n",
|
|
is_rxq ? "Rx" : "Tx");
|
|
|
|
for (i = 0; i < (nb_queues - 1) / HNS3_NUM_QUEUE_PER_LINE + 1; i++) {
|
|
uint32_t line_end = (i + 1) * HNS3_NUM_QUEUE_PER_LINE - 1;
|
|
uint32_t line_start = i * HNS3_NUM_QUEUE_PER_LINE;
|
|
fprintf(file, "\t %04u - %04u | ", line_start,
|
|
nb_queues - 1 > line_end ? line_end : nb_queues - 1);
|
|
|
|
hns3_print_queue_state_perline(file, queue_state, nb_queues, i);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_get_rxtx_queue_enable_state(FILE *file, struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
uint32_t *rx_queue_state;
|
|
uint32_t *tx_queue_state;
|
|
uint32_t nb_rx_queues;
|
|
uint32_t nb_tx_queues;
|
|
uint32_t bitmap_size;
|
|
|
|
nb_rx_queues = dev->data->nb_rx_queues;
|
|
nb_tx_queues = dev->data->nb_tx_queues;
|
|
if (nb_rx_queues == 0) {
|
|
fprintf(file, "\t -- Rx queue number is 0\n");
|
|
return;
|
|
}
|
|
if (nb_tx_queues == 0) {
|
|
fprintf(file, "\t -- Tx queue number is 0\n");
|
|
return;
|
|
}
|
|
|
|
bitmap_size = (hw->tqps_num * sizeof(uint32_t) + HNS3_UINT32_BIT) /
|
|
HNS3_UINT32_BIT;
|
|
rx_queue_state = (uint32_t *)rte_zmalloc(NULL, bitmap_size, 0);
|
|
if (rx_queue_state == NULL) {
|
|
hns3_err(hw, "Failed to allocate memory for rx queue state!");
|
|
return;
|
|
}
|
|
|
|
tx_queue_state = (uint32_t *)rte_zmalloc(NULL, bitmap_size, 0);
|
|
if (tx_queue_state == NULL) {
|
|
hns3_err(hw, "Failed to allocate memory for tx queue state!");
|
|
rte_free(rx_queue_state);
|
|
return;
|
|
}
|
|
|
|
fprintf(file, "\t -- enable state:\n");
|
|
hns3_get_queue_enable_state(hw, rx_queue_state, nb_rx_queues, true);
|
|
hns3_display_queue_enable_state(file, rx_queue_state, nb_rx_queues,
|
|
true);
|
|
|
|
hns3_get_queue_enable_state(hw, tx_queue_state, nb_tx_queues, false);
|
|
hns3_display_queue_enable_state(file, tx_queue_state, nb_tx_queues,
|
|
false);
|
|
rte_free(rx_queue_state);
|
|
rte_free(tx_queue_state);
|
|
}
|
|
|
|
static void
|
|
hns3_get_rxtx_queue_info(FILE *file, struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_rx_queue *rxq;
|
|
struct hns3_tx_queue *txq;
|
|
|
|
rxq = hns3_get_rx_queue(dev);
|
|
if (rxq == NULL)
|
|
return;
|
|
txq = hns3_get_tx_queue(dev);
|
|
if (txq == NULL)
|
|
return;
|
|
fprintf(file, " - Rx/Tx Queue Info:\n");
|
|
fprintf(file,
|
|
"\t -- first queue rxtx info:\n"
|
|
"\t Rx: port=%u nb_desc=%u free_thresh=%u\n"
|
|
"\t Tx: port=%u nb_desc=%u\n"
|
|
"\t -- tx push: %s\n",
|
|
rxq->port_id, rxq->nb_rx_desc, rxq->rx_free_thresh,
|
|
txq->port_id, txq->nb_tx_desc,
|
|
txq->tx_push_enable ? "enabled" : "disabled");
|
|
|
|
hns3_get_rxtx_fake_queue_info(file, dev);
|
|
hns3_get_rxtx_queue_enable_state(file, dev);
|
|
}
|
|
|
|
static int
|
|
hns3_get_vlan_filter_cfg(FILE *file, struct hns3_hw *hw)
|
|
{
|
|
#define HNS3_FILTER_TYPE_VF 0
|
|
#define HNS3_FILTER_TYPE_PORT 1
|
|
#define HNS3_FILTER_FE_NIC_INGRESS_B BIT(0)
|
|
#define HNS3_FILTER_FE_NIC_EGRESS_B BIT(1)
|
|
struct hns3_vlan_filter_ctrl_cmd *req;
|
|
struct hns3_cmd_desc desc;
|
|
uint8_t i;
|
|
int ret;
|
|
|
|
static const uint32_t vlan_filter_type[] = {
|
|
HNS3_FILTER_TYPE_PORT,
|
|
HNS3_FILTER_TYPE_VF
|
|
};
|
|
|
|
for (i = 0; i < RTE_DIM(vlan_filter_type); i++) {
|
|
hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_FILTER_CTRL,
|
|
true);
|
|
req = (struct hns3_vlan_filter_ctrl_cmd *)desc.data;
|
|
req->vlan_type = vlan_filter_type[i];
|
|
req->vf_id = HNS3_PF_FUNC_ID;
|
|
ret = hns3_cmd_send(hw, &desc, 1);
|
|
if (ret != 0) {
|
|
hns3_err(hw,
|
|
"NIC IMP exec ret=%d desc_num=%d optcode=0x%x!",
|
|
ret, 1, rte_le_to_cpu_16(desc.opcode));
|
|
return ret;
|
|
}
|
|
fprintf(file,
|
|
"\t -- %s VLAN filter configuration\n"
|
|
"\t nic_ingress :%s\n"
|
|
"\t nic_egress :%s\n",
|
|
req->vlan_type == HNS3_FILTER_TYPE_PORT ?
|
|
"Port" : "VF",
|
|
req->vlan_fe & HNS3_FILTER_FE_NIC_INGRESS_B ?
|
|
"Enable" : "Disable",
|
|
req->vlan_fe & HNS3_FILTER_FE_NIC_EGRESS_B ?
|
|
"Enable" : "Disable");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
hns3_get_vlan_rx_offload_cfg(FILE *file, struct hns3_hw *hw)
|
|
{
|
|
struct hns3_vport_vtag_rx_cfg_cmd *req;
|
|
struct hns3_cmd_desc desc;
|
|
uint16_t vport_id;
|
|
uint8_t bitmap;
|
|
int ret;
|
|
|
|
hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_PORT_RX_CFG, true);
|
|
req = (struct hns3_vport_vtag_rx_cfg_cmd *)desc.data;
|
|
vport_id = HNS3_PF_FUNC_ID;
|
|
req->vf_offset = vport_id / HNS3_VF_NUM_PER_CMD;
|
|
bitmap = 1 << (vport_id % HNS3_VF_NUM_PER_BYTE);
|
|
req->vf_bitmap[req->vf_offset] = bitmap;
|
|
|
|
/*
|
|
* current version VF is not supported when PF is driven by DPDK driver,
|
|
* just need to configure rx parameters for PF vport.
|
|
*/
|
|
ret = hns3_cmd_send(hw, &desc, 1);
|
|
if (ret != 0) {
|
|
hns3_err(hw,
|
|
"NIC firmware exec ret=%d optcode=0x%x!", ret,
|
|
rte_le_to_cpu_16(desc.opcode));
|
|
return ret;
|
|
}
|
|
|
|
fprintf(file,
|
|
"\t -- RX VLAN configuration\n"
|
|
"\t vlan1_strip_en :%s\n"
|
|
"\t vlan2_strip_en :%s\n"
|
|
"\t vlan1_vlan_prionly :%s\n"
|
|
"\t vlan2_vlan_prionly :%s\n"
|
|
"\t vlan1_strip_discard :%s\n"
|
|
"\t vlan2_strip_discard :%s\n",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_REM_TAG1_EN_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_REM_TAG2_EN_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_SHOW_TAG1_EN_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_SHOW_TAG2_EN_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_DISCARD_TAG1_EN_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_DISCARD_TAG2_EN_B) ? "Enable" : "Disable");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
hns3_parse_tx_vlan_cfg(FILE *file, struct hns3_vport_vtag_tx_cfg_cmd *req)
|
|
{
|
|
#define VLAN_VID_MASK 0x0fff
|
|
#define VLAN_PRIO_SHIFT 13
|
|
|
|
fprintf(file,
|
|
"\t -- TX VLAN configuration\n"
|
|
"\t accept_tag1 :%s\n"
|
|
"\t accept_untag1 :%s\n"
|
|
"\t insert_tag1_en :%s\n"
|
|
"\t default_vlan_tag1 = %d, qos = %d\n"
|
|
"\t accept_tag2 :%s\n"
|
|
"\t accept_untag2 :%s\n"
|
|
"\t insert_tag2_en :%s\n"
|
|
"\t default_vlan_tag2 = %d, qos = %d\n"
|
|
"\t vlan_shift_mode :%s\n",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_ACCEPT_TAG1_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_ACCEPT_UNTAG1_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_PORT_INS_TAG1_EN_B) ? "Enable" : "Disable",
|
|
req->def_vlan_tag1 & VLAN_VID_MASK,
|
|
req->def_vlan_tag1 >> VLAN_PRIO_SHIFT,
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_ACCEPT_TAG2_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_ACCEPT_UNTAG2_B) ? "Enable" : "Disable",
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_PORT_INS_TAG2_EN_B) ? "Enable" : "Disable",
|
|
req->def_vlan_tag2 & VLAN_VID_MASK,
|
|
req->def_vlan_tag2 >> VLAN_PRIO_SHIFT,
|
|
hns3_get_bit(req->vport_vlan_cfg,
|
|
HNS3_TAG_SHIFT_MODE_EN_B) ? "Enable" :
|
|
"Disable");
|
|
}
|
|
|
|
static int
|
|
hns3_get_vlan_tx_offload_cfg(FILE *file, struct hns3_hw *hw)
|
|
{
|
|
struct hns3_vport_vtag_tx_cfg_cmd *req;
|
|
struct hns3_cmd_desc desc;
|
|
uint16_t vport_id;
|
|
uint8_t bitmap;
|
|
int ret;
|
|
|
|
hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_PORT_TX_CFG, true);
|
|
req = (struct hns3_vport_vtag_tx_cfg_cmd *)desc.data;
|
|
vport_id = HNS3_PF_FUNC_ID;
|
|
req->vf_offset = vport_id / HNS3_VF_NUM_PER_CMD;
|
|
bitmap = 1 << (vport_id % HNS3_VF_NUM_PER_BYTE);
|
|
req->vf_bitmap[req->vf_offset] = bitmap;
|
|
/*
|
|
* current version VF is not supported when PF is driven by DPDK driver,
|
|
* just need to configure tx parameters for PF vport.
|
|
*/
|
|
ret = hns3_cmd_send(hw, &desc, 1);
|
|
if (ret != 0) {
|
|
hns3_err(hw,
|
|
"NIC firmware exec ret=%d desc_num=%d optcode=0x%x!",
|
|
ret, 1, rte_le_to_cpu_16(desc.opcode));
|
|
return ret;
|
|
}
|
|
|
|
hns3_parse_tx_vlan_cfg(file, req);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
hns3_get_port_pvid_info(FILE *file, struct hns3_hw *hw)
|
|
{
|
|
fprintf(file, " - pvid status: %s\n",
|
|
hw->port_base_vlan_cfg.state ? "On" : "Off");
|
|
}
|
|
|
|
static void
|
|
hns3_get_vlan_config_info(FILE *file, struct hns3_hw *hw)
|
|
{
|
|
int ret;
|
|
|
|
fprintf(file, " - VLAN Config Info:\n");
|
|
ret = hns3_get_vlan_filter_cfg(file, hw);
|
|
if (ret < 0)
|
|
return;
|
|
|
|
ret = hns3_get_vlan_rx_offload_cfg(file, hw);
|
|
if (ret < 0)
|
|
return;
|
|
|
|
ret = hns3_get_vlan_tx_offload_cfg(file, hw);
|
|
if (ret < 0)
|
|
return;
|
|
}
|
|
|
|
static void
|
|
hns3_get_tm_conf_shaper_info(FILE *file, struct hns3_tm_conf *conf)
|
|
{
|
|
struct hns3_shaper_profile_list *shaper_profile_list =
|
|
&conf->shaper_profile_list;
|
|
struct hns3_tm_shaper_profile *shaper_profile;
|
|
|
|
if (conf->nb_shaper_profile == 0)
|
|
return;
|
|
|
|
fprintf(file, " shaper_profile:\n");
|
|
TAILQ_FOREACH(shaper_profile, shaper_profile_list, node) {
|
|
fprintf(file,
|
|
" id=%u reference_count=%u peak_rate=%" PRIu64 "Bps\n",
|
|
shaper_profile->shaper_profile_id,
|
|
shaper_profile->reference_count,
|
|
shaper_profile->profile.peak.rate);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_get_tm_conf_port_node_info(FILE *file, struct hns3_tm_conf *conf)
|
|
{
|
|
if (conf->root == NULL)
|
|
return;
|
|
|
|
fprintf(file,
|
|
" port_node:\n"
|
|
" node_id=%u reference_count=%u shaper_profile_id=%d\n",
|
|
conf->root->id, conf->root->reference_count,
|
|
conf->root->shaper_profile ?
|
|
(int)conf->root->shaper_profile->shaper_profile_id : -1);
|
|
}
|
|
|
|
static void
|
|
hns3_get_tm_conf_tc_node_info(FILE *file, struct hns3_tm_conf *conf)
|
|
{
|
|
struct hns3_tm_node_list *tc_list = &conf->tc_list;
|
|
struct hns3_tm_node *tc_node[HNS3_MAX_TC_NUM];
|
|
struct hns3_tm_node *tm_node;
|
|
uint32_t tidx;
|
|
|
|
if (conf->nb_tc_node == 0)
|
|
return;
|
|
|
|
fprintf(file, " tc_node:\n");
|
|
memset(tc_node, 0, sizeof(tc_node));
|
|
TAILQ_FOREACH(tm_node, tc_list, node) {
|
|
tidx = hns3_tm_calc_node_tc_no(conf, tm_node->id);
|
|
if (tidx < HNS3_MAX_TC_NUM)
|
|
tc_node[tidx] = tm_node;
|
|
}
|
|
|
|
for (tidx = 0; tidx < HNS3_MAX_TC_NUM; tidx++) {
|
|
tm_node = tc_node[tidx];
|
|
if (tm_node == NULL)
|
|
continue;
|
|
fprintf(file,
|
|
" id=%u TC%u reference_count=%u parent_id=%d "
|
|
"shaper_profile_id=%d\n",
|
|
tm_node->id, hns3_tm_calc_node_tc_no(conf, tm_node->id),
|
|
tm_node->reference_count,
|
|
tm_node->parent ? (int)tm_node->parent->id : -1,
|
|
tm_node->shaper_profile ?
|
|
(int)tm_node->shaper_profile->shaper_profile_id : -1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_get_tm_conf_queue_format_info(FILE *file, struct hns3_tm_node **queue_node,
|
|
uint32_t *queue_node_tc,
|
|
uint32_t nb_tx_queues)
|
|
{
|
|
#define HNS3_PERLINE_QUEUES 32
|
|
#define HNS3_PERLINE_STRIDE 8
|
|
uint32_t i, j, line_num, start_queue_id, end_queue_id;
|
|
|
|
line_num = (nb_tx_queues + HNS3_PERLINE_QUEUES - 1) /
|
|
HNS3_PERLINE_QUEUES;
|
|
for (i = 0; i < line_num; i++) {
|
|
start_queue_id = i * HNS3_PERLINE_QUEUES;
|
|
end_queue_id = (i + 1) * HNS3_PERLINE_QUEUES - 1;
|
|
if (end_queue_id > nb_tx_queues - 1)
|
|
end_queue_id = nb_tx_queues - 1;
|
|
fprintf(file, " %04u - %04u | ", start_queue_id,
|
|
end_queue_id);
|
|
for (j = start_queue_id; j < nb_tx_queues; j++) {
|
|
if (j >= end_queue_id + 1)
|
|
break;
|
|
if (j > start_queue_id && j % HNS3_PERLINE_STRIDE == 0)
|
|
fprintf(file, ":");
|
|
fprintf(file, "%u",
|
|
queue_node[j] ? queue_node_tc[j] :
|
|
HNS3_MAX_TC_NUM);
|
|
}
|
|
fprintf(file, "\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
hns3_get_tm_conf_queue_node_info(FILE *file, struct hns3_tm_conf *conf,
|
|
uint32_t nb_tx_queues)
|
|
{
|
|
struct hns3_tm_node_list *queue_list = &conf->queue_list;
|
|
uint32_t nb_queue_node = conf->nb_leaf_nodes_max + 1;
|
|
struct hns3_tm_node *queue_node[nb_queue_node];
|
|
uint32_t queue_node_tc[nb_queue_node];
|
|
struct hns3_tm_node *tm_node;
|
|
|
|
if (conf->nb_queue_node == 0)
|
|
return;
|
|
|
|
fprintf(file,
|
|
" queue_node:\n"
|
|
" tx queue id | mapped tc (8 mean node not exist)\n");
|
|
|
|
memset(queue_node, 0, sizeof(queue_node));
|
|
memset(queue_node_tc, 0, sizeof(queue_node_tc));
|
|
nb_tx_queues = RTE_MIN(nb_tx_queues, nb_queue_node);
|
|
TAILQ_FOREACH(tm_node, queue_list, node) {
|
|
if (tm_node->id >= nb_queue_node)
|
|
continue;
|
|
queue_node[tm_node->id] = tm_node;
|
|
queue_node_tc[tm_node->id] = tm_node->parent ?
|
|
hns3_tm_calc_node_tc_no(conf, tm_node->parent->id) : 0;
|
|
nb_tx_queues = RTE_MAX(nb_tx_queues, tm_node->id + 1);
|
|
}
|
|
|
|
hns3_get_tm_conf_queue_format_info(file, queue_node, queue_node_tc,
|
|
nb_tx_queues);
|
|
}
|
|
|
|
static void
|
|
hns3_get_tm_conf_info(FILE *file, struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
|
|
struct hns3_tm_conf *conf = &pf->tm_conf;
|
|
|
|
if (!hns3_dev_get_support(hw, TM))
|
|
return;
|
|
|
|
fprintf(file, " - TM config info:\n");
|
|
fprintf(file,
|
|
"\t -- nb_leaf_nodes_max=%u nb_nodes_max=%u\n"
|
|
"\t -- nb_shaper_profile=%u nb_tc_node=%u nb_queue_node=%u\n"
|
|
"\t -- committed=%u\n",
|
|
conf->nb_leaf_nodes_max, conf->nb_nodes_max,
|
|
conf->nb_shaper_profile, conf->nb_tc_node, conf->nb_queue_node,
|
|
conf->committed);
|
|
|
|
hns3_get_tm_conf_shaper_info(file, conf);
|
|
hns3_get_tm_conf_port_node_info(file, conf);
|
|
hns3_get_tm_conf_tc_node_info(file, conf);
|
|
hns3_get_tm_conf_queue_node_info(file, conf, dev->data->nb_tx_queues);
|
|
}
|
|
|
|
static void
|
|
hns3_fc_mode_to_rxtx_pause(enum hns3_fc_mode fc_mode, bool *rx_pause,
|
|
bool *tx_pause)
|
|
{
|
|
switch (fc_mode) {
|
|
case HNS3_FC_NONE:
|
|
*tx_pause = false;
|
|
*rx_pause = false;
|
|
break;
|
|
case HNS3_FC_RX_PAUSE:
|
|
*rx_pause = true;
|
|
*tx_pause = false;
|
|
break;
|
|
case HNS3_FC_TX_PAUSE:
|
|
*rx_pause = false;
|
|
*tx_pause = true;
|
|
break;
|
|
case HNS3_FC_FULL:
|
|
*rx_pause = true;
|
|
*tx_pause = true;
|
|
break;
|
|
default:
|
|
*rx_pause = false;
|
|
*tx_pause = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool
|
|
hns3_is_link_fc_mode(struct hns3_adapter *hns)
|
|
{
|
|
struct hns3_hw *hw = &hns->hw;
|
|
struct hns3_pf *pf = &hns->pf;
|
|
|
|
if (hw->current_fc_status == HNS3_FC_STATUS_PFC)
|
|
return false;
|
|
|
|
if (hw->num_tc > 1 && !pf->support_multi_tc_pause)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
hns3_get_link_fc_info(FILE *file, struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_adapter *hns = dev->data->dev_private;
|
|
struct hns3_hw *hw = &hns->hw;
|
|
struct rte_eth_fc_conf cur_fc_conf;
|
|
bool rx_pause1;
|
|
bool tx_pause1;
|
|
bool rx_pause2;
|
|
bool tx_pause2;
|
|
int ret;
|
|
|
|
if (!hns3_is_link_fc_mode(hns))
|
|
return;
|
|
|
|
ret = hns3_flow_ctrl_get(dev, &cur_fc_conf);
|
|
if (ret) {
|
|
fprintf(file, "get device flow control info fail!\n");
|
|
return;
|
|
}
|
|
|
|
hns3_fc_mode_to_rxtx_pause(hw->requested_fc_mode,
|
|
&rx_pause1, &tx_pause1);
|
|
hns3_fc_mode_to_rxtx_pause((enum hns3_fc_mode)cur_fc_conf.mode,
|
|
&rx_pause2, &tx_pause2);
|
|
|
|
fprintf(file,
|
|
"\t -- link_fc_info:\n"
|
|
"\t Requested fc:\n"
|
|
"\t Rx: %s\n"
|
|
"\t Tx: %s\n"
|
|
"\t Current fc:\n"
|
|
"\t Rx: %s\n"
|
|
"\t Tx: %s\n"
|
|
"\t Autonegotiate: %s\n"
|
|
"\t Pause time: 0x%x\n",
|
|
rx_pause1 ? "On" : "Off", tx_pause1 ? "On" : "Off",
|
|
rx_pause2 ? "On" : "Off", tx_pause2 ? "On" : "Off",
|
|
cur_fc_conf.autoneg == RTE_ETH_LINK_AUTONEG ? "On" : "Off",
|
|
cur_fc_conf.pause_time);
|
|
}
|
|
|
|
static void
|
|
hns3_get_flow_ctrl_info(FILE *file, struct rte_eth_dev *dev)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
|
|
fprintf(file, " - Flow Ctrl Info:\n");
|
|
fprintf(file,
|
|
"\t -- fc_common_info:\n"
|
|
"\t current_fc_status=%u\n"
|
|
"\t requested_fc_mode=%u\n",
|
|
hw->current_fc_status,
|
|
hw->requested_fc_mode);
|
|
|
|
hns3_get_link_fc_info(file, dev);
|
|
}
|
|
|
|
int
|
|
hns3_eth_dev_priv_dump(struct rte_eth_dev *dev, FILE *file)
|
|
{
|
|
struct hns3_adapter *hns = dev->data->dev_private;
|
|
struct hns3_hw *hw = &hns->hw;
|
|
|
|
hns3_get_device_basic_info(file, dev);
|
|
hns3_get_dev_feature_capability(file, hw);
|
|
hns3_get_rxtx_queue_info(file, dev);
|
|
hns3_get_port_pvid_info(file, hw);
|
|
|
|
/*
|
|
* VF only supports dumping basic info, feature capability and queue
|
|
* info.
|
|
*/
|
|
if (hns->is_vf)
|
|
return 0;
|
|
|
|
hns3_get_dev_mac_info(file, hns);
|
|
hns3_get_vlan_config_info(file, hw);
|
|
hns3_get_fdir_basic_info(file, &hns->pf);
|
|
hns3_get_tm_conf_info(file, dev);
|
|
hns3_get_flow_ctrl_info(file, dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
hns3_rx_descriptor_dump(const struct rte_eth_dev *dev, uint16_t queue_id,
|
|
uint16_t offset, uint16_t num, FILE *file)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
struct hns3_rx_queue *rxq = dev->data->rx_queues[queue_id];
|
|
uint32_t *bd_data;
|
|
uint16_t count = 0;
|
|
uint16_t desc_id;
|
|
int i;
|
|
|
|
if (offset >= rxq->nb_rx_desc)
|
|
return -EINVAL;
|
|
|
|
if (num > rxq->nb_rx_desc) {
|
|
hns3_err(hw, "Invalid BD num=%u\n", num);
|
|
return -EINVAL;
|
|
}
|
|
|
|
while (count < num) {
|
|
desc_id = (rxq->next_to_use + offset + count) % rxq->nb_rx_desc;
|
|
bd_data = (uint32_t *)(&rxq->rx_ring[desc_id]);
|
|
fprintf(file, "Rx queue id:%u BD id:%u\n", queue_id, desc_id);
|
|
for (i = 0; i < HNS3_BD_DW_NUM; i++) {
|
|
/*
|
|
* For the sake of security, first 8 bytes of BD which
|
|
* stands for physical address of packet should not be
|
|
* shown.
|
|
*/
|
|
if (i < HNS3_BD_ADDRESS_LAST_DW) {
|
|
fprintf(file, "RX BD WORD[%d]:0x%08x\n", i, 0);
|
|
continue;
|
|
}
|
|
fprintf(file, "RX BD WORD[%d]:0x%08x\n", i,
|
|
*(bd_data + i));
|
|
}
|
|
count++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
hns3_tx_descriptor_dump(const struct rte_eth_dev *dev, uint16_t queue_id,
|
|
uint16_t offset, uint16_t num, FILE *file)
|
|
{
|
|
struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
|
struct hns3_tx_queue *txq = dev->data->tx_queues[queue_id];
|
|
uint32_t *bd_data;
|
|
uint16_t count = 0;
|
|
uint16_t desc_id;
|
|
int i;
|
|
|
|
if (offset >= txq->nb_tx_desc)
|
|
return -EINVAL;
|
|
|
|
if (num > txq->nb_tx_desc) {
|
|
hns3_err(hw, "Invalid BD num=%u\n", num);
|
|
return -EINVAL;
|
|
}
|
|
|
|
while (count < num) {
|
|
desc_id = (txq->next_to_use + offset + count) % txq->nb_tx_desc;
|
|
bd_data = (uint32_t *)(&txq->tx_ring[desc_id]);
|
|
fprintf(file, "Tx queue id:%u BD id:%u\n", queue_id, desc_id);
|
|
for (i = 0; i < HNS3_BD_DW_NUM; i++) {
|
|
/*
|
|
* For the sake of security, first 8 bytes of BD which
|
|
* stands for physical address of packet should not be
|
|
* shown.
|
|
*/
|
|
if (i < HNS3_BD_ADDRESS_LAST_DW) {
|
|
fprintf(file, "TX BD WORD[%d]:0x%08x\n", i, 0);
|
|
continue;
|
|
}
|
|
|
|
fprintf(file, "Tx BD WORD[%d]:0x%08x\n", i,
|
|
*(bd_data + i));
|
|
}
|
|
count++;
|
|
}
|
|
|
|
return 0;
|
|
}
|