numam-dpdk/drivers/net/hns3/hns3_dump.c
Dongdong Liu fbb7a43a36 net/hns3: support Rx/Tx descriptor dump
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>
2022-10-06 18:38:48 +02:00

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