Commit 0a14fd29 authored by David S. Miller's avatar David S. Miller

Merge branch 'hns3-next'

Huazhong Tan says:

====================
net: hns3: updates for -next

This series adds some updates for the HNS3 ethernet driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fc25f9f6 e76e6886
...@@ -91,6 +91,7 @@ enum HNAE3_DEV_CAP_BITS { ...@@ -91,6 +91,7 @@ enum HNAE3_DEV_CAP_BITS {
HNAE3_DEV_SUPPORT_STASH_B, HNAE3_DEV_SUPPORT_STASH_B,
HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
HNAE3_DEV_SUPPORT_PAUSE_B, HNAE3_DEV_SUPPORT_PAUSE_B,
HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
}; };
#define hnae3_dev_fd_supported(hdev) \ #define hnae3_dev_fd_supported(hdev) \
...@@ -141,6 +142,9 @@ enum HNAE3_DEV_CAP_BITS { ...@@ -141,6 +142,9 @@ enum HNAE3_DEV_CAP_BITS {
#define hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev) \ #define hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B, (ae_dev)->caps) test_bit(HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B, (ae_dev)->caps)
#define hnae3_ae_dev_rxd_adv_layout_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, (ae_dev)->caps)
#define ring_ptr_move_fw(ring, p) \ #define ring_ptr_move_fw(ring, p) \
((ring)->p = ((ring)->p + 1) % (ring)->desc_num) ((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
#define ring_ptr_move_bw(ring, p) \ #define ring_ptr_move_bw(ring, p) \
...@@ -246,6 +250,24 @@ enum hnae3_port_base_vlan_state { ...@@ -246,6 +250,24 @@ enum hnae3_port_base_vlan_state {
HNAE3_PORT_BASE_VLAN_NOCHANGE, HNAE3_PORT_BASE_VLAN_NOCHANGE,
}; };
enum hnae3_dbg_cmd {
HNAE3_DBG_CMD_TM_NODES,
HNAE3_DBG_CMD_TM_PRI,
HNAE3_DBG_CMD_TM_QSET,
HNAE3_DBG_CMD_DEV_INFO,
HNAE3_DBG_CMD_TX_BD,
HNAE3_DBG_CMD_RX_BD,
HNAE3_DBG_CMD_MAC_UC,
HNAE3_DBG_CMD_MAC_MC,
HNAE3_DBG_CMD_MNG_TBL,
HNAE3_DBG_CMD_LOOPBACK,
HNAE3_DBG_CMD_INTERRUPT_INFO,
HNAE3_DBG_CMD_RESET_INFO,
HNAE3_DBG_CMD_IMP_INFO,
HNAE3_DBG_CMD_NCL_CONFIG,
HNAE3_DBG_CMD_UNKNOWN,
};
struct hnae3_vector_info { struct hnae3_vector_info {
u8 __iomem *io_addr; u8 __iomem *io_addr;
int vector; int vector;
...@@ -623,7 +645,7 @@ struct hnae3_ae_ops { ...@@ -623,7 +645,7 @@ struct hnae3_ae_ops {
int (*add_arfs_entry)(struct hnae3_handle *handle, u16 queue_id, int (*add_arfs_entry)(struct hnae3_handle *handle, u16 queue_id,
u16 flow_id, struct flow_keys *fkeys); u16 flow_id, struct flow_keys *fkeys);
int (*dbg_run_cmd)(struct hnae3_handle *handle, const char *cmd_buf); int (*dbg_run_cmd)(struct hnae3_handle *handle, const char *cmd_buf);
int (*dbg_read_cmd)(struct hnae3_handle *handle, const char *cmd_buf, int (*dbg_read_cmd)(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len); char *buf, int len);
pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev); pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev);
bool (*get_hw_reset_stat)(struct hnae3_handle *handle); bool (*get_hw_reset_stat)(struct hnae3_handle *handle);
...@@ -786,10 +808,6 @@ struct hnae3_handle { ...@@ -786,10 +808,6 @@ struct hnae3_handle {
#define hnae3_get_bit(origin, shift) \ #define hnae3_get_bit(origin, shift) \
hnae3_get_field(origin, 0x1 << (shift), shift) hnae3_get_field(origin, 0x1 << (shift), shift)
#define HNAE3_DBG_TM_NODES "tm_nodes"
#define HNAE3_DBG_TM_PRI "tm_priority"
#define HNAE3_DBG_TM_QSET "tm_qset"
int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev); int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev);
void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev); void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev);
......
...@@ -5,13 +5,193 @@ ...@@ -5,13 +5,193 @@
#include <linux/device.h> #include <linux/device.h>
#include "hnae3.h" #include "hnae3.h"
#include "hns3_debugfs.h"
#include "hns3_enet.h" #include "hns3_enet.h"
#define HNS3_DBG_READ_LEN 65536
#define HNS3_DBG_WRITE_LEN 1024
static struct dentry *hns3_dbgfs_root; static struct dentry *hns3_dbgfs_root;
static struct hns3_dbg_dentry_info hns3_dbg_dentry[] = {
{
.name = "tm"
},
{
.name = "tx_bd_info"
},
{
.name = "rx_bd_info"
},
{
.name = "mac_list"
},
/* keep common at the bottom and add new directory above */
{
.name = "common"
},
};
static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, unsigned int cmd);
static int hns3_dbg_common_file_init(struct hnae3_handle *handle,
unsigned int cmd);
static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = {
{
.name = "tm_nodes",
.cmd = HNAE3_DBG_CMD_TM_NODES,
.dentry = HNS3_DBG_DENTRY_TM,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "tm_priority",
.cmd = HNAE3_DBG_CMD_TM_PRI,
.dentry = HNS3_DBG_DENTRY_TM,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "tm_qset",
.cmd = HNAE3_DBG_CMD_TM_QSET,
.dentry = HNS3_DBG_DENTRY_TM,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "dev_info",
.cmd = HNAE3_DBG_CMD_DEV_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "tx_bd_queue",
.cmd = HNAE3_DBG_CMD_TX_BD,
.dentry = HNS3_DBG_DENTRY_TX_BD,
.buf_len = HNS3_DBG_READ_LEN_4MB,
.init = hns3_dbg_bd_file_init,
},
{
.name = "rx_bd_queue",
.cmd = HNAE3_DBG_CMD_RX_BD,
.dentry = HNS3_DBG_DENTRY_RX_BD,
.buf_len = HNS3_DBG_READ_LEN_4MB,
.init = hns3_dbg_bd_file_init,
},
{
.name = "uc",
.cmd = HNAE3_DBG_CMD_MAC_UC,
.dentry = HNS3_DBG_DENTRY_MAC,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "mc",
.cmd = HNAE3_DBG_CMD_MAC_MC,
.dentry = HNS3_DBG_DENTRY_MAC,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "mng_tbl",
.cmd = HNAE3_DBG_CMD_MNG_TBL,
.dentry = HNS3_DBG_DENTRY_COMMON,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "loopback",
.cmd = HNAE3_DBG_CMD_LOOPBACK,
.dentry = HNS3_DBG_DENTRY_COMMON,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "interrupt_info",
.cmd = HNAE3_DBG_CMD_INTERRUPT_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "reset_info",
.cmd = HNAE3_DBG_CMD_RESET_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "imp_info",
.cmd = HNAE3_DBG_CMD_IMP_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.buf_len = HNS3_DBG_READ_LEN,
.init = hns3_dbg_common_file_init,
},
{
.name = "ncl_config",
.cmd = HNAE3_DBG_CMD_NCL_CONFIG,
.dentry = HNS3_DBG_DENTRY_COMMON,
.buf_len = HNS3_DBG_READ_LEN_128KB,
.init = hns3_dbg_common_file_init,
},
};
static struct hns3_dbg_cap_info hns3_dbg_cap[] = {
{
.name = "support FD",
.cap_bit = HNAE3_DEV_SUPPORT_FD_B,
}, {
.name = "support GRO",
.cap_bit = HNAE3_DEV_SUPPORT_GRO_B,
}, {
.name = "support FEC",
.cap_bit = HNAE3_DEV_SUPPORT_FEC_B,
}, {
.name = "support UDP GSO",
.cap_bit = HNAE3_DEV_SUPPORT_UDP_GSO_B,
}, {
.name = "support PTP",
.cap_bit = HNAE3_DEV_SUPPORT_PTP_B,
}, {
.name = "support INT QL",
.cap_bit = HNAE3_DEV_SUPPORT_INT_QL_B,
}, {
.name = "support HW TX csum",
.cap_bit = HNAE3_DEV_SUPPORT_HW_TX_CSUM_B,
}, {
.name = "support UDP tunnel csum",
.cap_bit = HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
}, {
.name = "support TX push",
.cap_bit = HNAE3_DEV_SUPPORT_TX_PUSH_B,
}, {
.name = "support imp-controlled PHY",
.cap_bit = HNAE3_DEV_SUPPORT_PHY_IMP_B,
}, {
.name = "support rxd advanced layout",
.cap_bit = HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
},
};
static void hns3_dbg_fill_content(char *content, u16 len,
const struct hns3_dbg_item *items,
const char **result, u16 size)
{
char *pos = content;
u16 i;
memset(content, ' ', len);
for (i = 0; i < size; i++) {
if (result)
strncpy(pos, result[i], strlen(result[i]));
else
strncpy(pos, items[i].name, strlen(items[i].name));
pos += strlen(items[i].name) + items[i].interval;
}
*pos++ = '\n';
*pos++ = '\0';
}
static int hns3_dbg_queue_info(struct hnae3_handle *h, static int hns3_dbg_queue_info(struct hnae3_handle *h,
const char *cmd_buf) const char *cmd_buf)
{ {
...@@ -169,118 +349,159 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h) ...@@ -169,118 +349,159 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h)
return 0; return 0;
} }
static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) static const struct hns3_dbg_item rx_bd_info_items[] = {
{ "BD_IDX", 3 },
{ "L234_INFO", 2 },
{ "PKT_LEN", 3 },
{ "SIZE", 4 },
{ "RSS_HASH", 4 },
{ "FD_ID", 2 },
{ "VLAN_TAG", 2 },
{ "O_DM_VLAN_ID_FB", 2 },
{ "OT_VLAN_TAG", 2 },
{ "BD_BASE_INFO", 2 },
{ "PTYPE", 2 },
{ "HW_CSUM", 2 },
};
static void hns3_dump_rx_bd_info(struct hns3_nic_priv *priv,
struct hns3_desc *desc, char **result, int idx)
{
unsigned int j = 0;
sprintf(result[j++], "%5d", idx);
sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.l234_info));
sprintf(result[j++], "%7u", le16_to_cpu(desc->rx.pkt_len));
sprintf(result[j++], "%4u", le16_to_cpu(desc->rx.size));
sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.rss_hash));
sprintf(result[j++], "%5u", le16_to_cpu(desc->rx.fd_id));
sprintf(result[j++], "%8u", le16_to_cpu(desc->rx.vlan_tag));
sprintf(result[j++], "%15u", le16_to_cpu(desc->rx.o_dm_vlan_id_fb));
sprintf(result[j++], "%11u", le16_to_cpu(desc->rx.ot_vlan_tag));
sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.bd_base_info));
if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) {
u32 ol_info = le32_to_cpu(desc->rx.ol_info);
sprintf(result[j++], "%5lu", hnae3_get_field(ol_info,
HNS3_RXD_PTYPE_M,
HNS3_RXD_PTYPE_S));
sprintf(result[j++], "%7u", le16_to_cpu(desc->csum));
} else {
sprintf(result[j++], "NA");
sprintf(result[j++], "NA");
}
}
static int hns3_dbg_rx_bd_info(struct hns3_dbg_data *d, char *buf, int len)
{ {
struct hns3_nic_priv *priv = h->priv; char data_str[ARRAY_SIZE(rx_bd_info_items)][HNS3_DBG_DATA_STR_LEN];
struct hns3_desc *rx_desc, *tx_desc; struct hns3_nic_priv *priv = d->handle->priv;
struct device *dev = &h->pdev->dev; char *result[ARRAY_SIZE(rx_bd_info_items)];
char content[HNS3_DBG_INFO_LEN];
struct hns3_enet_ring *ring; struct hns3_enet_ring *ring;
u32 tx_index, rx_index; struct hns3_desc *desc;
u32 q_num, value; unsigned int i;
dma_addr_t addr; int pos = 0;
u16 mss_hw_csum;
u32 l234info;
int cnt;
cnt = sscanf(&cmd_buf[8], "%u %u", &q_num, &tx_index); if (d->qid >= d->handle->kinfo.num_tqps) {
if (cnt == 2) { dev_err(&d->handle->pdev->dev,
rx_index = tx_index; "queue%u is not in use\n", d->qid);
} else if (cnt != 1) {
dev_err(dev, "bd info: bad command string, cnt=%d\n", cnt);
return -EINVAL; return -EINVAL;
} }
if (q_num >= h->kinfo.num_tqps) { for (i = 0; i < ARRAY_SIZE(rx_bd_info_items); i++)
dev_err(dev, "Queue number(%u) is out of range(0-%u)\n", q_num, result[i] = &data_str[i][0];
h->kinfo.num_tqps - 1);
return -EINVAL; pos += scnprintf(buf + pos, len - pos,
"Queue %u rx bd info:\n", d->qid);
hns3_dbg_fill_content(content, sizeof(content), rx_bd_info_items,
NULL, ARRAY_SIZE(rx_bd_info_items));
pos += scnprintf(buf + pos, len - pos, "%s", content);
ring = &priv->ring[d->qid + d->handle->kinfo.num_tqps];
for (i = 0; i < ring->desc_num; i++) {
desc = &ring->desc[i];
hns3_dump_rx_bd_info(priv, desc, result, i);
hns3_dbg_fill_content(content, sizeof(content),
rx_bd_info_items, (const char **)result,
ARRAY_SIZE(rx_bd_info_items));
pos += scnprintf(buf + pos, len - pos, "%s", content);
} }
ring = &priv->ring[q_num]; return 0;
value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG); }
tx_index = (cnt == 1) ? value : tx_index;
static const struct hns3_dbg_item tx_bd_info_items[] = {
{ "BD_IDX", 5 },
{ "ADDRESS", 2 },
{ "VLAN_TAG", 2 },
{ "SIZE", 2 },
{ "T_CS_VLAN_TSO", 2 },
{ "OT_VLAN_TAG", 3 },
{ "TV", 2 },
{ "OLT_VLAN_LEN", 2},
{ "PAYLEN_OL4CS", 2},
{ "BD_FE_SC_VLD", 2},
{ "MSS_HW_CSUM", 0},
};
static void hns3_dump_tx_bd_info(struct hns3_nic_priv *priv,
struct hns3_desc *desc, char **result, int idx)
{
unsigned int j = 0;
sprintf(result[j++], "%6d", idx);
sprintf(result[j++], "%#llx", le64_to_cpu(desc->addr));
sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.vlan_tag));
sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.send_size));
sprintf(result[j++], "%#x",
le32_to_cpu(desc->tx.type_cs_vlan_tso_len));
sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.outer_vlan_tag));
sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.tv));
sprintf(result[j++], "%10u",
le32_to_cpu(desc->tx.ol_type_vlan_len_msec));
sprintf(result[j++], "%#x", le32_to_cpu(desc->tx.paylen_ol4cs));
sprintf(result[j++], "%#x", le16_to_cpu(desc->tx.bdtp_fe_sc_vld_ra_ri));
sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.mss_hw_csum));
}
static int hns3_dbg_tx_bd_info(struct hns3_dbg_data *d, char *buf, int len)
{
char data_str[ARRAY_SIZE(tx_bd_info_items)][HNS3_DBG_DATA_STR_LEN];
struct hns3_nic_priv *priv = d->handle->priv;
char *result[ARRAY_SIZE(tx_bd_info_items)];
char content[HNS3_DBG_INFO_LEN];
struct hns3_enet_ring *ring;
struct hns3_desc *desc;
unsigned int i;
int pos = 0;
if (tx_index >= ring->desc_num) { if (d->qid >= d->handle->kinfo.num_tqps) {
dev_err(dev, "bd index(%u) is out of range(0-%u)\n", tx_index, dev_err(&d->handle->pdev->dev,
ring->desc_num - 1); "queue%u is not in use\n", d->qid);
return -EINVAL; return -EINVAL;
} }
tx_desc = &ring->desc[tx_index]; for (i = 0; i < ARRAY_SIZE(tx_bd_info_items); i++)
addr = le64_to_cpu(tx_desc->addr); result[i] = &data_str[i][0];
mss_hw_csum = le16_to_cpu(tx_desc->tx.mss_hw_csum);
dev_info(dev, "TX Queue Num: %u, BD Index: %u\n", q_num, tx_index);
dev_info(dev, "(TX)addr: %pad\n", &addr);
dev_info(dev, "(TX)vlan_tag: %u\n", le16_to_cpu(tx_desc->tx.vlan_tag));
dev_info(dev, "(TX)send_size: %u\n",
le16_to_cpu(tx_desc->tx.send_size));
if (mss_hw_csum & BIT(HNS3_TXD_HW_CS_B)) {
u32 offset = le32_to_cpu(tx_desc->tx.ol_type_vlan_len_msec);
u32 start = le32_to_cpu(tx_desc->tx.type_cs_vlan_tso_len);
dev_info(dev, "(TX)csum start: %u\n",
hnae3_get_field(start,
HNS3_TXD_CSUM_START_M,
HNS3_TXD_CSUM_START_S));
dev_info(dev, "(TX)csum offset: %u\n",
hnae3_get_field(offset,
HNS3_TXD_CSUM_OFFSET_M,
HNS3_TXD_CSUM_OFFSET_S));
} else {
dev_info(dev, "(TX)vlan_tso: %u\n",
tx_desc->tx.type_cs_vlan_tso);
dev_info(dev, "(TX)l2_len: %u\n", tx_desc->tx.l2_len);
dev_info(dev, "(TX)l3_len: %u\n", tx_desc->tx.l3_len);
dev_info(dev, "(TX)l4_len: %u\n", tx_desc->tx.l4_len);
dev_info(dev, "(TX)vlan_msec: %u\n",
tx_desc->tx.ol_type_vlan_msec);
dev_info(dev, "(TX)ol2_len: %u\n", tx_desc->tx.ol2_len);
dev_info(dev, "(TX)ol3_len: %u\n", tx_desc->tx.ol3_len);
dev_info(dev, "(TX)ol4_len: %u\n", tx_desc->tx.ol4_len);
}
dev_info(dev, "(TX)vlan_tag: %u\n", pos += scnprintf(buf + pos, len - pos,
le16_to_cpu(tx_desc->tx.outer_vlan_tag)); "Queue %u tx bd info:\n", d->qid);
dev_info(dev, "(TX)tv: %u\n", le16_to_cpu(tx_desc->tx.tv)); hns3_dbg_fill_content(content, sizeof(content), tx_bd_info_items,
dev_info(dev, "(TX)paylen_ol4cs: %u\n", NULL, ARRAY_SIZE(tx_bd_info_items));
le32_to_cpu(tx_desc->tx.paylen_ol4cs)); pos += scnprintf(buf + pos, len - pos, "%s", content);
dev_info(dev, "(TX)vld_ra_ri: %u\n",
le16_to_cpu(tx_desc->tx.bdtp_fe_sc_vld_ra_ri)); ring = &priv->ring[d->qid];
dev_info(dev, "(TX)mss_hw_csum: %u\n", mss_hw_csum); for (i = 0; i < ring->desc_num; i++) {
desc = &ring->desc[i];
ring = &priv->ring[q_num + h->kinfo.num_tqps];
value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG);
rx_index = (cnt == 1) ? value : tx_index;
rx_desc = &ring->desc[rx_index];
addr = le64_to_cpu(rx_desc->addr);
l234info = le32_to_cpu(rx_desc->rx.l234_info);
dev_info(dev, "RX Queue Num: %u, BD Index: %u\n", q_num, rx_index);
dev_info(dev, "(RX)addr: %pad\n", &addr);
dev_info(dev, "(RX)l234_info: %u\n", l234info);
if (l234info & BIT(HNS3_RXD_L2_CSUM_B)) {
u32 lo, hi;
lo = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_L_M,
HNS3_RXD_L2_CSUM_L_S);
hi = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_H_M,
HNS3_RXD_L2_CSUM_H_S);
dev_info(dev, "(RX)csum: %u\n", lo | hi << 8);
}
dev_info(dev, "(RX)pkt_len: %u\n", le16_to_cpu(rx_desc->rx.pkt_len)); hns3_dump_tx_bd_info(priv, desc, result, i);
dev_info(dev, "(RX)size: %u\n", le16_to_cpu(rx_desc->rx.size)); hns3_dbg_fill_content(content, sizeof(content),
dev_info(dev, "(RX)rss_hash: %u\n", le32_to_cpu(rx_desc->rx.rss_hash)); tx_bd_info_items, (const char **)result,
dev_info(dev, "(RX)fd_id: %u\n", le16_to_cpu(rx_desc->rx.fd_id)); ARRAY_SIZE(tx_bd_info_items));
dev_info(dev, "(RX)vlan_tag: %u\n", le16_to_cpu(rx_desc->rx.vlan_tag)); pos += scnprintf(buf + pos, len - pos, "%s", content);
dev_info(dev, "(RX)o_dm_vlan_id_fb: %u\n", }
le16_to_cpu(rx_desc->rx.o_dm_vlan_id_fb));
dev_info(dev, "(RX)ot_vlan_tag: %u\n",
le16_to_cpu(rx_desc->rx.ot_vlan_tag));
dev_info(dev, "(RX)bd_base_info: %u\n",
le32_to_cpu(rx_desc->rx.bd_base_info));
return 0; return 0;
} }
...@@ -294,9 +515,6 @@ static void hns3_dbg_help(struct hnae3_handle *h) ...@@ -294,9 +515,6 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "available commands\n"); dev_info(&h->pdev->dev, "available commands\n");
dev_info(&h->pdev->dev, "queue info <number>\n"); dev_info(&h->pdev->dev, "queue info <number>\n");
dev_info(&h->pdev->dev, "queue map\n"); dev_info(&h->pdev->dev, "queue map\n");
dev_info(&h->pdev->dev, "bd info <q_num> <bd index>\n");
dev_info(&h->pdev->dev, "dev capability\n");
dev_info(&h->pdev->dev, "dev spec\n");
if (!hns3_is_phys_func(h->pdev)) if (!hns3_is_phys_func(h->pdev))
return; return;
...@@ -308,16 +526,8 @@ static void hns3_dbg_help(struct hnae3_handle *h) ...@@ -308,16 +526,8 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "dump qos pause cfg\n"); dev_info(&h->pdev->dev, "dump qos pause cfg\n");
dev_info(&h->pdev->dev, "dump qos pri map\n"); dev_info(&h->pdev->dev, "dump qos pri map\n");
dev_info(&h->pdev->dev, "dump qos buf cfg\n"); dev_info(&h->pdev->dev, "dump qos buf cfg\n");
dev_info(&h->pdev->dev, "dump mng tbl\n");
dev_info(&h->pdev->dev, "dump reset info\n");
dev_info(&h->pdev->dev, "dump m7 info\n");
dev_info(&h->pdev->dev, "dump ncl_config <offset> <length>(in hex)\n");
dev_info(&h->pdev->dev, "dump mac tnl status\n"); dev_info(&h->pdev->dev, "dump mac tnl status\n");
dev_info(&h->pdev->dev, "dump loopback\n");
dev_info(&h->pdev->dev, "dump qs shaper [qs id]\n"); dev_info(&h->pdev->dev, "dump qs shaper [qs id]\n");
dev_info(&h->pdev->dev, "dump uc mac list <func id>\n");
dev_info(&h->pdev->dev, "dump mc mac list <func id>\n");
dev_info(&h->pdev->dev, "dump intr\n");
memset(printf_buf, 0, HNS3_DBG_BUF_LEN); memset(printf_buf, 0, HNS3_DBG_BUF_LEN);
strncat(printf_buf, "dump reg [[bios common] [ssu <port_id>]", strncat(printf_buf, "dump reg [[bios common] [ssu <port_id>]",
...@@ -338,65 +548,78 @@ static void hns3_dbg_help(struct hnae3_handle *h) ...@@ -338,65 +548,78 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "%s", printf_buf); dev_info(&h->pdev->dev, "%s", printf_buf);
} }
static void hns3_dbg_dev_caps(struct hnae3_handle *h) static void
hns3_dbg_dev_caps(struct hnae3_handle *h, char *buf, int len, int *pos)
{ {
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
unsigned long *caps; static const char * const str[] = {"no", "yes"};
unsigned long *caps = ae_dev->caps;
caps = ae_dev->caps; u32 i, state;
dev_info(&h->pdev->dev, "support FD: %s\n", *pos += scnprintf(buf + *pos, len - *pos, "dev capability:\n");
test_bit(HNAE3_DEV_SUPPORT_FD_B, caps) ? "yes" : "no");
dev_info(&h->pdev->dev, "support GRO: %s\n", for (i = 0; i < ARRAY_SIZE(hns3_dbg_cap); i++) {
test_bit(HNAE3_DEV_SUPPORT_GRO_B, caps) ? "yes" : "no"); state = test_bit(hns3_dbg_cap[i].cap_bit, caps);
dev_info(&h->pdev->dev, "support FEC: %s\n", *pos += scnprintf(buf + *pos, len - *pos, "%s: %s\n",
test_bit(HNAE3_DEV_SUPPORT_FEC_B, caps) ? "yes" : "no"); hns3_dbg_cap[i].name, str[state]);
dev_info(&h->pdev->dev, "support UDP GSO: %s\n", }
test_bit(HNAE3_DEV_SUPPORT_UDP_GSO_B, caps) ? "yes" : "no");
dev_info(&h->pdev->dev, "support PTP: %s\n", *pos += scnprintf(buf + *pos, len - *pos, "\n");
test_bit(HNAE3_DEV_SUPPORT_PTP_B, caps) ? "yes" : "no");
dev_info(&h->pdev->dev, "support INT QL: %s\n",
test_bit(HNAE3_DEV_SUPPORT_INT_QL_B, caps) ? "yes" : "no");
dev_info(&h->pdev->dev, "support HW TX csum: %s\n",
test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, caps) ? "yes" : "no");
dev_info(&h->pdev->dev, "support UDP tunnel csum: %s\n",
test_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, caps) ?
"yes" : "no");
dev_info(&h->pdev->dev, "support PAUSE: %s\n",
test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps) ?
"yes" : "no");
dev_info(&h->pdev->dev, "support imp-controlled PHY: %s\n",
test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, caps) ? "yes" : "no");
} }
static void hns3_dbg_dev_specs(struct hnae3_handle *h) static void
hns3_dbg_dev_specs(struct hnae3_handle *h, char *buf, int len, int *pos)
{ {
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev); struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
struct hnae3_dev_specs *dev_specs = &ae_dev->dev_specs; struct hnae3_dev_specs *dev_specs = &ae_dev->dev_specs;
struct hnae3_knic_private_info *kinfo = &h->kinfo; struct hnae3_knic_private_info *kinfo = &h->kinfo;
struct hns3_nic_priv *priv = h->priv;
*pos += scnprintf(buf + *pos, len - *pos, "dev_spec:\n");
dev_info(priv->dev, "MAC entry num: %u\n", dev_specs->mac_entry_num); *pos += scnprintf(buf + *pos, len - *pos, "MAC entry num: %u\n",
dev_info(priv->dev, "MNG entry num: %u\n", dev_specs->mng_entry_num); dev_specs->mac_entry_num);
dev_info(priv->dev, "MAX non tso bd num: %u\n", *pos += scnprintf(buf + *pos, len - *pos, "MNG entry num: %u\n",
dev_specs->max_non_tso_bd_num); dev_specs->mng_entry_num);
dev_info(priv->dev, "RSS ind tbl size: %u\n", *pos += scnprintf(buf + *pos, len - *pos, "MAX non tso bd num: %u\n",
dev_specs->rss_ind_tbl_size); dev_specs->max_non_tso_bd_num);
dev_info(priv->dev, "RSS key size: %u\n", dev_specs->rss_key_size); *pos += scnprintf(buf + *pos, len - *pos, "RSS ind tbl size: %u\n",
dev_info(priv->dev, "RSS size: %u\n", kinfo->rss_size); dev_specs->rss_ind_tbl_size);
dev_info(priv->dev, "Allocated RSS size: %u\n", kinfo->req_rss_size); *pos += scnprintf(buf + *pos, len - *pos, "RSS key size: %u\n",
dev_info(priv->dev, "Task queue pairs numbers: %u\n", kinfo->num_tqps); dev_specs->rss_key_size);
*pos += scnprintf(buf + *pos, len - *pos, "RSS size: %u\n",
dev_info(priv->dev, "RX buffer length: %u\n", kinfo->rx_buf_len); kinfo->rss_size);
dev_info(priv->dev, "Desc num per TX queue: %u\n", kinfo->num_tx_desc); *pos += scnprintf(buf + *pos, len - *pos, "Allocated RSS size: %u\n",
dev_info(priv->dev, "Desc num per RX queue: %u\n", kinfo->num_rx_desc); kinfo->req_rss_size);
dev_info(priv->dev, "Total number of enabled TCs: %u\n", *pos += scnprintf(buf + *pos, len - *pos,
kinfo->tc_info.num_tc); "Task queue pairs numbers: %u\n",
dev_info(priv->dev, "MAX INT QL: %u\n", dev_specs->int_ql_max); kinfo->num_tqps);
dev_info(priv->dev, "MAX INT GL: %u\n", dev_specs->max_int_gl); *pos += scnprintf(buf + *pos, len - *pos, "RX buffer length: %u\n",
dev_info(priv->dev, "MAX frame size: %u\n", dev_specs->max_frm_size); kinfo->rx_buf_len);
dev_info(priv->dev, "MAX TM RATE: %uMbps\n", dev_specs->max_tm_rate); *pos += scnprintf(buf + *pos, len - *pos, "Desc num per TX queue: %u\n",
dev_info(priv->dev, "MAX QSET number: %u\n", dev_specs->max_qset_num); kinfo->num_tx_desc);
*pos += scnprintf(buf + *pos, len - *pos, "Desc num per RX queue: %u\n",
kinfo->num_rx_desc);
*pos += scnprintf(buf + *pos, len - *pos,
"Total number of enabled TCs: %u\n",
kinfo->tc_info.num_tc);
*pos += scnprintf(buf + *pos, len - *pos, "MAX INT QL: %u\n",
dev_specs->int_ql_max);
*pos += scnprintf(buf + *pos, len - *pos, "MAX INT GL: %u\n",
dev_specs->max_int_gl);
*pos += scnprintf(buf + *pos, len - *pos, "MAX TM RATE: %u\n",
dev_specs->max_tm_rate);
*pos += scnprintf(buf + *pos, len - *pos, "MAX QSET number: %u\n",
dev_specs->max_qset_num);
}
static int hns3_dbg_dev_info(struct hnae3_handle *h, char *buf, int len)
{
int pos = 0;
hns3_dbg_dev_caps(h, buf, len, &pos);
hns3_dbg_dev_specs(h, buf, len, &pos);
return 0;
} }
static ssize_t hns3_dbg_cmd_read(struct file *filp, char __user *buffer, static ssize_t hns3_dbg_cmd_read(struct file *filp, char __user *buffer,
...@@ -438,12 +661,6 @@ static int hns3_dbg_check_cmd(struct hnae3_handle *handle, char *cmd_buf) ...@@ -438,12 +661,6 @@ static int hns3_dbg_check_cmd(struct hnae3_handle *handle, char *cmd_buf)
ret = hns3_dbg_queue_info(handle, cmd_buf); ret = hns3_dbg_queue_info(handle, cmd_buf);
else if (strncmp(cmd_buf, "queue map", 9) == 0) else if (strncmp(cmd_buf, "queue map", 9) == 0)
ret = hns3_dbg_queue_map(handle); ret = hns3_dbg_queue_map(handle);
else if (strncmp(cmd_buf, "bd info", 7) == 0)
ret = hns3_dbg_bd_info(handle, cmd_buf);
else if (strncmp(cmd_buf, "dev capability", 14) == 0)
hns3_dbg_dev_caps(handle);
else if (strncmp(cmd_buf, "dev spec", 8) == 0)
hns3_dbg_dev_specs(handle);
else if (handle->ae_algo->ops->dbg_run_cmd) else if (handle->ae_algo->ops->dbg_run_cmd)
ret = handle->ae_algo->ops->dbg_run_cmd(handle, cmd_buf); ret = handle->ae_algo->ops->dbg_run_cmd(handle, cmd_buf);
else else
...@@ -500,37 +717,120 @@ static ssize_t hns3_dbg_cmd_write(struct file *filp, const char __user *buffer, ...@@ -500,37 +717,120 @@ static ssize_t hns3_dbg_cmd_write(struct file *filp, const char __user *buffer,
return count; return count;
} }
static int hns3_dbg_get_cmd_index(struct hnae3_handle *handle,
const unsigned char *name, u32 *index)
{
u32 i;
for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
if (!strncmp(name, hns3_dbg_cmd[i].name,
strlen(hns3_dbg_cmd[i].name))) {
*index = i;
return 0;
}
}
dev_err(&handle->pdev->dev, "unknown command(%s)\n", name);
return -EINVAL;
}
static const struct hns3_dbg_func hns3_dbg_cmd_func[] = {
{
.cmd = HNAE3_DBG_CMD_DEV_INFO,
.dbg_dump = hns3_dbg_dev_info,
},
{
.cmd = HNAE3_DBG_CMD_TX_BD,
.dbg_dump_bd = hns3_dbg_tx_bd_info,
},
{
.cmd = HNAE3_DBG_CMD_RX_BD,
.dbg_dump_bd = hns3_dbg_rx_bd_info,
},
};
static int hns3_dbg_read_cmd(struct hns3_dbg_data *dbg_data,
enum hnae3_dbg_cmd cmd, char *buf, int len)
{
const struct hnae3_ae_ops *ops = dbg_data->handle->ae_algo->ops;
const struct hns3_dbg_func *cmd_func;
u32 i;
for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd_func); i++) {
if (cmd == hns3_dbg_cmd_func[i].cmd) {
cmd_func = &hns3_dbg_cmd_func[i];
if (cmd_func->dbg_dump)
return cmd_func->dbg_dump(dbg_data->handle, buf,
len);
else
return cmd_func->dbg_dump_bd(dbg_data, buf,
len);
}
}
if (!ops->dbg_read_cmd)
return -EOPNOTSUPP;
return ops->dbg_read_cmd(dbg_data->handle, cmd, buf, len);
}
static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer, static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct hnae3_handle *handle = filp->private_data; struct hns3_dbg_data *dbg_data = filp->private_data;
const struct hnae3_ae_ops *ops = handle->ae_algo->ops; struct hnae3_handle *handle = dbg_data->handle;
struct hns3_nic_priv *priv = handle->priv; struct hns3_nic_priv *priv = handle->priv;
char *cmd_buf, *read_buf;
ssize_t size = 0; ssize_t size = 0;
int ret = 0; char **save_buf;
char *read_buf;
read_buf = kzalloc(HNS3_DBG_READ_LEN, GFP_KERNEL); u32 index;
if (!read_buf) int ret;
return -ENOMEM;
cmd_buf = filp->f_path.dentry->d_iname; ret = hns3_dbg_get_cmd_index(handle, filp->f_path.dentry->d_iname,
&index);
if (ret)
return ret;
if (ops->dbg_read_cmd) save_buf = &hns3_dbg_cmd[index].buf;
ret = ops->dbg_read_cmd(handle, cmd_buf, read_buf,
HNS3_DBG_READ_LEN);
if (ret) { if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
dev_info(priv->dev, "unknown command\n"); test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) {
ret = -EBUSY;
goto out; goto out;
} }
if (*save_buf) {
read_buf = *save_buf;
} else {
read_buf = kvzalloc(hns3_dbg_cmd[index].buf_len, GFP_KERNEL);
if (!read_buf)
return -ENOMEM;
/* save the buffer addr until the last read operation */
*save_buf = read_buf;
}
/* get data ready for the first time to read */
if (!*ppos) {
ret = hns3_dbg_read_cmd(dbg_data, hns3_dbg_cmd[index].cmd,
read_buf, hns3_dbg_cmd[index].buf_len);
if (ret)
goto out;
}
size = simple_read_from_buffer(buffer, count, ppos, read_buf, size = simple_read_from_buffer(buffer, count, ppos, read_buf,
strlen(read_buf)); strlen(read_buf));
if (size > 0)
return size;
out: out:
kfree(read_buf); /* free the buffer for the last read operation */
return size; if (*save_buf) {
kvfree(*save_buf);
*save_buf = NULL;
}
return ret;
} }
static const struct file_operations hns3_dbg_cmd_fops = { static const struct file_operations hns3_dbg_cmd_fops = {
...@@ -546,29 +846,109 @@ static const struct file_operations hns3_dbg_fops = { ...@@ -546,29 +846,109 @@ static const struct file_operations hns3_dbg_fops = {
.read = hns3_dbg_read, .read = hns3_dbg_read,
}; };
void hns3_dbg_init(struct hnae3_handle *handle) static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, u32 cmd)
{
struct dentry *entry_dir;
struct hns3_dbg_data *data;
u16 max_queue_num;
unsigned int i;
entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
max_queue_num = hns3_get_max_available_channels(handle);
data = devm_kzalloc(&handle->pdev->dev, max_queue_num * sizeof(*data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
for (i = 0; i < max_queue_num; i++) {
char name[HNS3_DBG_FILE_NAME_LEN];
data[i].handle = handle;
data[i].qid = i;
sprintf(name, "%s%u", hns3_dbg_cmd[cmd].name, i);
debugfs_create_file(name, 0400, entry_dir, &data[i],
&hns3_dbg_fops);
}
return 0;
}
static int
hns3_dbg_common_file_init(struct hnae3_handle *handle, u32 cmd)
{
struct hns3_dbg_data *data;
struct dentry *entry_dir;
data = devm_kzalloc(&handle->pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->handle = handle;
entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
debugfs_create_file(hns3_dbg_cmd[cmd].name, 0400, entry_dir,
data, &hns3_dbg_fops);
return 0;
}
int hns3_dbg_init(struct hnae3_handle *handle)
{ {
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
const char *name = pci_name(handle->pdev); const char *name = pci_name(handle->pdev);
struct dentry *entry_dir; int ret;
u32 i;
handle->hnae3_dbgfs = debugfs_create_dir(name, hns3_dbgfs_root); hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry =
debugfs_create_dir(name, hns3_dbgfs_root);
handle->hnae3_dbgfs = hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry;
debugfs_create_file("cmd", 0600, handle->hnae3_dbgfs, handle, debugfs_create_file("cmd", 0600, handle->hnae3_dbgfs, handle,
&hns3_dbg_cmd_fops); &hns3_dbg_cmd_fops);
entry_dir = debugfs_create_dir("tm", handle->hnae3_dbgfs); for (i = 0; i < HNS3_DBG_DENTRY_COMMON; i++)
if (ae_dev->dev_version > HNAE3_DEVICE_VERSION_V2) hns3_dbg_dentry[i].dentry =
debugfs_create_file(HNAE3_DBG_TM_NODES, 0600, entry_dir, handle, debugfs_create_dir(hns3_dbg_dentry[i].name,
&hns3_dbg_fops); handle->hnae3_dbgfs);
debugfs_create_file(HNAE3_DBG_TM_PRI, 0600, entry_dir, handle,
&hns3_dbg_fops); for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
debugfs_create_file(HNAE3_DBG_TM_QSET, 0600, entry_dir, handle, if (hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_TM_NODES &&
&hns3_dbg_fops); ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2)
continue;
if (!hns3_dbg_cmd[i].init) {
dev_err(&handle->pdev->dev,
"cmd %s lack of init func\n",
hns3_dbg_cmd[i].name);
ret = -EINVAL;
goto out;
}
ret = hns3_dbg_cmd[i].init(handle, i);
if (ret) {
dev_err(&handle->pdev->dev, "failed to init cmd %s\n",
hns3_dbg_cmd[i].name);
goto out;
}
}
return 0;
out:
debugfs_remove_recursive(handle->hnae3_dbgfs);
handle->hnae3_dbgfs = NULL;
return ret;
} }
void hns3_dbg_uninit(struct hnae3_handle *handle) void hns3_dbg_uninit(struct hnae3_handle *handle)
{ {
u32 i;
for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++)
if (hns3_dbg_cmd[i].buf) {
kvfree(hns3_dbg_cmd[i].buf);
hns3_dbg_cmd[i].buf = NULL;
}
debugfs_remove_recursive(handle->hnae3_dbgfs); debugfs_remove_recursive(handle->hnae3_dbgfs);
handle->hnae3_dbgfs = NULL; handle->hnae3_dbgfs = NULL;
} }
......
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Hisilicon Limited. */
#ifndef __HNS3_DEBUGFS_H
#define __HNS3_DEBUGFS_H
#define HNS3_DBG_READ_LEN 65536
#define HNS3_DBG_READ_LEN_128KB 0x20000
#define HNS3_DBG_READ_LEN_4MB 0x400000
#define HNS3_DBG_WRITE_LEN 1024
#define HNS3_DBG_DATA_STR_LEN 32
#define HNS3_DBG_INFO_LEN 256
#define HNS3_DBG_ITEM_NAME_LEN 32
#define HNS3_DBG_FILE_NAME_LEN 16
struct hns3_dbg_item {
char name[HNS3_DBG_ITEM_NAME_LEN];
u16 interval; /* blank numbers after the item */
};
struct hns3_dbg_data {
struct hnae3_handle *handle;
u16 qid;
};
enum hns3_dbg_dentry_type {
HNS3_DBG_DENTRY_TM,
HNS3_DBG_DENTRY_TX_BD,
HNS3_DBG_DENTRY_RX_BD,
HNS3_DBG_DENTRY_MAC,
HNS3_DBG_DENTRY_COMMON,
};
struct hns3_dbg_dentry_info {
const char *name;
struct dentry *dentry;
};
struct hns3_dbg_cmd_info {
const char *name;
enum hnae3_dbg_cmd cmd;
enum hns3_dbg_dentry_type dentry;
u32 buf_len;
char *buf;
int (*init)(struct hnae3_handle *handle, unsigned int cmd);
};
struct hns3_dbg_func {
enum hnae3_dbg_cmd cmd;
int (*dbg_dump)(struct hnae3_handle *handle, char *buf, int len);
int (*dbg_dump_bd)(struct hns3_dbg_data *data, char *buf, int len);
};
struct hns3_dbg_cap_info {
const char *name;
enum HNAE3_DEV_CAP_BITS cap_bit;
};
#endif
...@@ -91,6 +91,278 @@ static const struct pci_device_id hns3_pci_tbl[] = { ...@@ -91,6 +91,278 @@ static const struct pci_device_id hns3_pci_tbl[] = {
}; };
MODULE_DEVICE_TABLE(pci, hns3_pci_tbl); MODULE_DEVICE_TABLE(pci, hns3_pci_tbl);
#define HNS3_RX_PTYPE_ENTRY(ptype, l, s, t) \
{ ptype, \
l, \
CHECKSUM_##s, \
HNS3_L3_TYPE_##t, \
1 }
#define HNS3_RX_PTYPE_UNUSED_ENTRY(ptype) \
{ ptype, 0, CHECKSUM_NONE, HNS3_L3_TYPE_PARSE_FAIL, 0 }
static const struct hns3_rx_ptype hns3_rx_ptype_tbl[] = {
HNS3_RX_PTYPE_UNUSED_ENTRY(0),
HNS3_RX_PTYPE_ENTRY(1, 0, COMPLETE, ARP),
HNS3_RX_PTYPE_ENTRY(2, 0, COMPLETE, RARP),
HNS3_RX_PTYPE_ENTRY(3, 0, COMPLETE, LLDP),
HNS3_RX_PTYPE_ENTRY(4, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(5, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(6, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(7, 0, COMPLETE, CNM),
HNS3_RX_PTYPE_ENTRY(8, 0, NONE, PARSE_FAIL),
HNS3_RX_PTYPE_UNUSED_ENTRY(9),
HNS3_RX_PTYPE_UNUSED_ENTRY(10),
HNS3_RX_PTYPE_UNUSED_ENTRY(11),
HNS3_RX_PTYPE_UNUSED_ENTRY(12),
HNS3_RX_PTYPE_UNUSED_ENTRY(13),
HNS3_RX_PTYPE_UNUSED_ENTRY(14),
HNS3_RX_PTYPE_UNUSED_ENTRY(15),
HNS3_RX_PTYPE_ENTRY(16, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(17, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(18, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(19, 0, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(20, 0, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(21, 0, NONE, IPV4),
HNS3_RX_PTYPE_ENTRY(22, 0, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(23, 0, NONE, IPV4),
HNS3_RX_PTYPE_ENTRY(24, 0, NONE, IPV4),
HNS3_RX_PTYPE_ENTRY(25, 0, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_UNUSED_ENTRY(26),
HNS3_RX_PTYPE_UNUSED_ENTRY(27),
HNS3_RX_PTYPE_UNUSED_ENTRY(28),
HNS3_RX_PTYPE_ENTRY(29, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(30, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(31, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(32, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(33, 1, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(34, 1, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(35, 1, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(36, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(37, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_UNUSED_ENTRY(38),
HNS3_RX_PTYPE_ENTRY(39, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(40, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(41, 1, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(42, 1, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(43, 1, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(44, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(45, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_UNUSED_ENTRY(46),
HNS3_RX_PTYPE_UNUSED_ENTRY(47),
HNS3_RX_PTYPE_UNUSED_ENTRY(48),
HNS3_RX_PTYPE_UNUSED_ENTRY(49),
HNS3_RX_PTYPE_UNUSED_ENTRY(50),
HNS3_RX_PTYPE_UNUSED_ENTRY(51),
HNS3_RX_PTYPE_UNUSED_ENTRY(52),
HNS3_RX_PTYPE_UNUSED_ENTRY(53),
HNS3_RX_PTYPE_UNUSED_ENTRY(54),
HNS3_RX_PTYPE_UNUSED_ENTRY(55),
HNS3_RX_PTYPE_UNUSED_ENTRY(56),
HNS3_RX_PTYPE_UNUSED_ENTRY(57),
HNS3_RX_PTYPE_UNUSED_ENTRY(58),
HNS3_RX_PTYPE_UNUSED_ENTRY(59),
HNS3_RX_PTYPE_UNUSED_ENTRY(60),
HNS3_RX_PTYPE_UNUSED_ENTRY(61),
HNS3_RX_PTYPE_UNUSED_ENTRY(62),
HNS3_RX_PTYPE_UNUSED_ENTRY(63),
HNS3_RX_PTYPE_UNUSED_ENTRY(64),
HNS3_RX_PTYPE_UNUSED_ENTRY(65),
HNS3_RX_PTYPE_UNUSED_ENTRY(66),
HNS3_RX_PTYPE_UNUSED_ENTRY(67),
HNS3_RX_PTYPE_UNUSED_ENTRY(68),
HNS3_RX_PTYPE_UNUSED_ENTRY(69),
HNS3_RX_PTYPE_UNUSED_ENTRY(70),
HNS3_RX_PTYPE_UNUSED_ENTRY(71),
HNS3_RX_PTYPE_UNUSED_ENTRY(72),
HNS3_RX_PTYPE_UNUSED_ENTRY(73),
HNS3_RX_PTYPE_UNUSED_ENTRY(74),
HNS3_RX_PTYPE_UNUSED_ENTRY(75),
HNS3_RX_PTYPE_UNUSED_ENTRY(76),
HNS3_RX_PTYPE_UNUSED_ENTRY(77),
HNS3_RX_PTYPE_UNUSED_ENTRY(78),
HNS3_RX_PTYPE_UNUSED_ENTRY(79),
HNS3_RX_PTYPE_UNUSED_ENTRY(80),
HNS3_RX_PTYPE_UNUSED_ENTRY(81),
HNS3_RX_PTYPE_UNUSED_ENTRY(82),
HNS3_RX_PTYPE_UNUSED_ENTRY(83),
HNS3_RX_PTYPE_UNUSED_ENTRY(84),
HNS3_RX_PTYPE_UNUSED_ENTRY(85),
HNS3_RX_PTYPE_UNUSED_ENTRY(86),
HNS3_RX_PTYPE_UNUSED_ENTRY(87),
HNS3_RX_PTYPE_UNUSED_ENTRY(88),
HNS3_RX_PTYPE_UNUSED_ENTRY(89),
HNS3_RX_PTYPE_UNUSED_ENTRY(90),
HNS3_RX_PTYPE_UNUSED_ENTRY(91),
HNS3_RX_PTYPE_UNUSED_ENTRY(92),
HNS3_RX_PTYPE_UNUSED_ENTRY(93),
HNS3_RX_PTYPE_UNUSED_ENTRY(94),
HNS3_RX_PTYPE_UNUSED_ENTRY(95),
HNS3_RX_PTYPE_UNUSED_ENTRY(96),
HNS3_RX_PTYPE_UNUSED_ENTRY(97),
HNS3_RX_PTYPE_UNUSED_ENTRY(98),
HNS3_RX_PTYPE_UNUSED_ENTRY(99),
HNS3_RX_PTYPE_UNUSED_ENTRY(100),
HNS3_RX_PTYPE_UNUSED_ENTRY(101),
HNS3_RX_PTYPE_UNUSED_ENTRY(102),
HNS3_RX_PTYPE_UNUSED_ENTRY(103),
HNS3_RX_PTYPE_UNUSED_ENTRY(104),
HNS3_RX_PTYPE_UNUSED_ENTRY(105),
HNS3_RX_PTYPE_UNUSED_ENTRY(106),
HNS3_RX_PTYPE_UNUSED_ENTRY(107),
HNS3_RX_PTYPE_UNUSED_ENTRY(108),
HNS3_RX_PTYPE_UNUSED_ENTRY(109),
HNS3_RX_PTYPE_UNUSED_ENTRY(110),
HNS3_RX_PTYPE_ENTRY(111, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(112, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(113, 0, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(114, 0, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(115, 0, NONE, IPV6),
HNS3_RX_PTYPE_ENTRY(116, 0, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(117, 0, NONE, IPV6),
HNS3_RX_PTYPE_ENTRY(118, 0, NONE, IPV6),
HNS3_RX_PTYPE_ENTRY(119, 0, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_UNUSED_ENTRY(120),
HNS3_RX_PTYPE_UNUSED_ENTRY(121),
HNS3_RX_PTYPE_UNUSED_ENTRY(122),
HNS3_RX_PTYPE_ENTRY(123, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(124, 0, COMPLETE, PARSE_FAIL),
HNS3_RX_PTYPE_ENTRY(125, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(126, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(127, 1, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(128, 1, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(129, 1, UNNECESSARY, IPV4),
HNS3_RX_PTYPE_ENTRY(130, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_ENTRY(131, 0, COMPLETE, IPV4),
HNS3_RX_PTYPE_UNUSED_ENTRY(132),
HNS3_RX_PTYPE_ENTRY(133, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(134, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(135, 1, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(136, 1, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(137, 1, UNNECESSARY, IPV6),
HNS3_RX_PTYPE_ENTRY(138, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_ENTRY(139, 0, COMPLETE, IPV6),
HNS3_RX_PTYPE_UNUSED_ENTRY(140),
HNS3_RX_PTYPE_UNUSED_ENTRY(141),
HNS3_RX_PTYPE_UNUSED_ENTRY(142),
HNS3_RX_PTYPE_UNUSED_ENTRY(143),
HNS3_RX_PTYPE_UNUSED_ENTRY(144),
HNS3_RX_PTYPE_UNUSED_ENTRY(145),
HNS3_RX_PTYPE_UNUSED_ENTRY(146),
HNS3_RX_PTYPE_UNUSED_ENTRY(147),
HNS3_RX_PTYPE_UNUSED_ENTRY(148),
HNS3_RX_PTYPE_UNUSED_ENTRY(149),
HNS3_RX_PTYPE_UNUSED_ENTRY(150),
HNS3_RX_PTYPE_UNUSED_ENTRY(151),
HNS3_RX_PTYPE_UNUSED_ENTRY(152),
HNS3_RX_PTYPE_UNUSED_ENTRY(153),
HNS3_RX_PTYPE_UNUSED_ENTRY(154),
HNS3_RX_PTYPE_UNUSED_ENTRY(155),
HNS3_RX_PTYPE_UNUSED_ENTRY(156),
HNS3_RX_PTYPE_UNUSED_ENTRY(157),
HNS3_RX_PTYPE_UNUSED_ENTRY(158),
HNS3_RX_PTYPE_UNUSED_ENTRY(159),
HNS3_RX_PTYPE_UNUSED_ENTRY(160),
HNS3_RX_PTYPE_UNUSED_ENTRY(161),
HNS3_RX_PTYPE_UNUSED_ENTRY(162),
HNS3_RX_PTYPE_UNUSED_ENTRY(163),
HNS3_RX_PTYPE_UNUSED_ENTRY(164),
HNS3_RX_PTYPE_UNUSED_ENTRY(165),
HNS3_RX_PTYPE_UNUSED_ENTRY(166),
HNS3_RX_PTYPE_UNUSED_ENTRY(167),
HNS3_RX_PTYPE_UNUSED_ENTRY(168),
HNS3_RX_PTYPE_UNUSED_ENTRY(169),
HNS3_RX_PTYPE_UNUSED_ENTRY(170),
HNS3_RX_PTYPE_UNUSED_ENTRY(171),
HNS3_RX_PTYPE_UNUSED_ENTRY(172),
HNS3_RX_PTYPE_UNUSED_ENTRY(173),
HNS3_RX_PTYPE_UNUSED_ENTRY(174),
HNS3_RX_PTYPE_UNUSED_ENTRY(175),
HNS3_RX_PTYPE_UNUSED_ENTRY(176),
HNS3_RX_PTYPE_UNUSED_ENTRY(177),
HNS3_RX_PTYPE_UNUSED_ENTRY(178),
HNS3_RX_PTYPE_UNUSED_ENTRY(179),
HNS3_RX_PTYPE_UNUSED_ENTRY(180),
HNS3_RX_PTYPE_UNUSED_ENTRY(181),
HNS3_RX_PTYPE_UNUSED_ENTRY(182),
HNS3_RX_PTYPE_UNUSED_ENTRY(183),
HNS3_RX_PTYPE_UNUSED_ENTRY(184),
HNS3_RX_PTYPE_UNUSED_ENTRY(185),
HNS3_RX_PTYPE_UNUSED_ENTRY(186),
HNS3_RX_PTYPE_UNUSED_ENTRY(187),
HNS3_RX_PTYPE_UNUSED_ENTRY(188),
HNS3_RX_PTYPE_UNUSED_ENTRY(189),
HNS3_RX_PTYPE_UNUSED_ENTRY(190),
HNS3_RX_PTYPE_UNUSED_ENTRY(191),
HNS3_RX_PTYPE_UNUSED_ENTRY(192),
HNS3_RX_PTYPE_UNUSED_ENTRY(193),
HNS3_RX_PTYPE_UNUSED_ENTRY(194),
HNS3_RX_PTYPE_UNUSED_ENTRY(195),
HNS3_RX_PTYPE_UNUSED_ENTRY(196),
HNS3_RX_PTYPE_UNUSED_ENTRY(197),
HNS3_RX_PTYPE_UNUSED_ENTRY(198),
HNS3_RX_PTYPE_UNUSED_ENTRY(199),
HNS3_RX_PTYPE_UNUSED_ENTRY(200),
HNS3_RX_PTYPE_UNUSED_ENTRY(201),
HNS3_RX_PTYPE_UNUSED_ENTRY(202),
HNS3_RX_PTYPE_UNUSED_ENTRY(203),
HNS3_RX_PTYPE_UNUSED_ENTRY(204),
HNS3_RX_PTYPE_UNUSED_ENTRY(205),
HNS3_RX_PTYPE_UNUSED_ENTRY(206),
HNS3_RX_PTYPE_UNUSED_ENTRY(207),
HNS3_RX_PTYPE_UNUSED_ENTRY(208),
HNS3_RX_PTYPE_UNUSED_ENTRY(209),
HNS3_RX_PTYPE_UNUSED_ENTRY(210),
HNS3_RX_PTYPE_UNUSED_ENTRY(211),
HNS3_RX_PTYPE_UNUSED_ENTRY(212),
HNS3_RX_PTYPE_UNUSED_ENTRY(213),
HNS3_RX_PTYPE_UNUSED_ENTRY(214),
HNS3_RX_PTYPE_UNUSED_ENTRY(215),
HNS3_RX_PTYPE_UNUSED_ENTRY(216),
HNS3_RX_PTYPE_UNUSED_ENTRY(217),
HNS3_RX_PTYPE_UNUSED_ENTRY(218),
HNS3_RX_PTYPE_UNUSED_ENTRY(219),
HNS3_RX_PTYPE_UNUSED_ENTRY(220),
HNS3_RX_PTYPE_UNUSED_ENTRY(221),
HNS3_RX_PTYPE_UNUSED_ENTRY(222),
HNS3_RX_PTYPE_UNUSED_ENTRY(223),
HNS3_RX_PTYPE_UNUSED_ENTRY(224),
HNS3_RX_PTYPE_UNUSED_ENTRY(225),
HNS3_RX_PTYPE_UNUSED_ENTRY(226),
HNS3_RX_PTYPE_UNUSED_ENTRY(227),
HNS3_RX_PTYPE_UNUSED_ENTRY(228),
HNS3_RX_PTYPE_UNUSED_ENTRY(229),
HNS3_RX_PTYPE_UNUSED_ENTRY(230),
HNS3_RX_PTYPE_UNUSED_ENTRY(231),
HNS3_RX_PTYPE_UNUSED_ENTRY(232),
HNS3_RX_PTYPE_UNUSED_ENTRY(233),
HNS3_RX_PTYPE_UNUSED_ENTRY(234),
HNS3_RX_PTYPE_UNUSED_ENTRY(235),
HNS3_RX_PTYPE_UNUSED_ENTRY(236),
HNS3_RX_PTYPE_UNUSED_ENTRY(237),
HNS3_RX_PTYPE_UNUSED_ENTRY(238),
HNS3_RX_PTYPE_UNUSED_ENTRY(239),
HNS3_RX_PTYPE_UNUSED_ENTRY(240),
HNS3_RX_PTYPE_UNUSED_ENTRY(241),
HNS3_RX_PTYPE_UNUSED_ENTRY(242),
HNS3_RX_PTYPE_UNUSED_ENTRY(243),
HNS3_RX_PTYPE_UNUSED_ENTRY(244),
HNS3_RX_PTYPE_UNUSED_ENTRY(245),
HNS3_RX_PTYPE_UNUSED_ENTRY(246),
HNS3_RX_PTYPE_UNUSED_ENTRY(247),
HNS3_RX_PTYPE_UNUSED_ENTRY(248),
HNS3_RX_PTYPE_UNUSED_ENTRY(249),
HNS3_RX_PTYPE_UNUSED_ENTRY(250),
HNS3_RX_PTYPE_UNUSED_ENTRY(251),
HNS3_RX_PTYPE_UNUSED_ENTRY(252),
HNS3_RX_PTYPE_UNUSED_ENTRY(253),
HNS3_RX_PTYPE_UNUSED_ENTRY(254),
HNS3_RX_PTYPE_UNUSED_ENTRY(255),
};
#define HNS3_INVALID_PTYPE \
ARRAY_SIZE(hns3_rx_ptype_tbl)
static irqreturn_t hns3_irq_handle(int irq, void *vector) static irqreturn_t hns3_irq_handle(int irq, void *vector)
{ {
struct hns3_enet_tqp_vector *tqp_vector = vector; struct hns3_enet_tqp_vector *tqp_vector = vector;
...@@ -362,7 +634,7 @@ static int hns3_nic_set_real_num_queue(struct net_device *netdev) ...@@ -362,7 +634,7 @@ static int hns3_nic_set_real_num_queue(struct net_device *netdev)
return 0; return 0;
} }
static u16 hns3_get_max_available_channels(struct hnae3_handle *h) u16 hns3_get_max_available_channels(struct hnae3_handle *h)
{ {
u16 alloc_tqps, max_rss_size, rss_size; u16 alloc_tqps, max_rss_size, rss_size;
...@@ -2980,51 +3252,31 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info) ...@@ -2980,51 +3252,31 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info)
return 0; return 0;
} }
static void hns3_checksum_complete(struct hns3_enet_ring *ring, static bool hns3_checksum_complete(struct hns3_enet_ring *ring,
struct sk_buff *skb, u32 l234info) struct sk_buff *skb, u32 ptype, u16 csum)
{ {
u32 lo, hi; if (ptype == HNS3_INVALID_PTYPE ||
hns3_rx_ptype_tbl[ptype].ip_summed != CHECKSUM_COMPLETE)
return false;
u64_stats_update_begin(&ring->syncp); u64_stats_update_begin(&ring->syncp);
ring->stats.csum_complete++; ring->stats.csum_complete++;
u64_stats_update_end(&ring->syncp); u64_stats_update_end(&ring->syncp);
skb->ip_summed = CHECKSUM_COMPLETE; skb->ip_summed = CHECKSUM_COMPLETE;
lo = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_L_M, skb->csum = csum_unfold((__force __sum16)csum);
HNS3_RXD_L2_CSUM_L_S);
hi = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_H_M, return true;
HNS3_RXD_L2_CSUM_H_S);
skb->csum = csum_unfold((__force __sum16)(lo | hi << 8));
} }
static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, static void hns3_rx_handle_csum(struct sk_buff *skb, u32 l234info,
u32 l234info, u32 bd_base_info, u32 ol_info) u32 ol_info, u32 ptype)
{ {
struct net_device *netdev = ring_to_netdev(ring);
int l3_type, l4_type; int l3_type, l4_type;
int ol4_type; int ol4_type;
skb->ip_summed = CHECKSUM_NONE; if (ptype != HNS3_INVALID_PTYPE) {
skb->csum_level = hns3_rx_ptype_tbl[ptype].csum_level;
skb_checksum_none_assert(skb); skb->ip_summed = hns3_rx_ptype_tbl[ptype].ip_summed;
if (!(netdev->features & NETIF_F_RXCSUM))
return;
if (l234info & BIT(HNS3_RXD_L2_CSUM_B)) {
hns3_checksum_complete(ring, skb, l234info);
return;
}
/* check if hardware has done checksum */
if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B)))
return;
if (unlikely(l234info & (BIT(HNS3_RXD_L3E_B) | BIT(HNS3_RXD_L4E_B) |
BIT(HNS3_RXD_OL3E_B) |
BIT(HNS3_RXD_OL4E_B)))) {
u64_stats_update_begin(&ring->syncp);
ring->stats.l3l4_csum_err++;
u64_stats_update_end(&ring->syncp);
return; return;
} }
...@@ -3054,6 +3306,45 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, ...@@ -3054,6 +3306,45 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
} }
} }
static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
u32 l234info, u32 bd_base_info, u32 ol_info,
u16 csum)
{
struct net_device *netdev = ring_to_netdev(ring);
struct hns3_nic_priv *priv = netdev_priv(netdev);
u32 ptype = HNS3_INVALID_PTYPE;
skb->ip_summed = CHECKSUM_NONE;
skb_checksum_none_assert(skb);
if (!(netdev->features & NETIF_F_RXCSUM))
return;
if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state))
ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
HNS3_RXD_PTYPE_S);
if (hns3_checksum_complete(ring, skb, ptype, csum))
return;
/* check if hardware has done checksum */
if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B)))
return;
if (unlikely(l234info & (BIT(HNS3_RXD_L3E_B) | BIT(HNS3_RXD_L4E_B) |
BIT(HNS3_RXD_OL3E_B) |
BIT(HNS3_RXD_OL4E_B)))) {
u64_stats_update_begin(&ring->syncp);
ring->stats.l3l4_csum_err++;
u64_stats_update_end(&ring->syncp);
return;
}
hns3_rx_handle_csum(skb, l234info, ol_info, ptype);
}
static void hns3_rx_skb(struct hns3_enet_ring *ring, struct sk_buff *skb) static void hns3_rx_skb(struct hns3_enet_ring *ring, struct sk_buff *skb)
{ {
if (skb_has_frag_list(skb)) if (skb_has_frag_list(skb))
...@@ -3235,8 +3526,10 @@ static int hns3_add_frag(struct hns3_enet_ring *ring) ...@@ -3235,8 +3526,10 @@ static int hns3_add_frag(struct hns3_enet_ring *ring)
static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring, static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
struct sk_buff *skb, u32 l234info, struct sk_buff *skb, u32 l234info,
u32 bd_base_info, u32 ol_info) u32 bd_base_info, u32 ol_info, u16 csum)
{ {
struct net_device *netdev = ring_to_netdev(ring);
struct hns3_nic_priv *priv = netdev_priv(netdev);
u32 l3_type; u32 l3_type;
skb_shinfo(skb)->gso_size = hnae3_get_field(bd_base_info, skb_shinfo(skb)->gso_size = hnae3_get_field(bd_base_info,
...@@ -3244,7 +3537,8 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring, ...@@ -3244,7 +3537,8 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
HNS3_RXD_GRO_SIZE_S); HNS3_RXD_GRO_SIZE_S);
/* if there is no HW GRO, do not set gro params */ /* if there is no HW GRO, do not set gro params */
if (!skb_shinfo(skb)->gso_size) { if (!skb_shinfo(skb)->gso_size) {
hns3_rx_checksum(ring, skb, l234info, bd_base_info, ol_info); hns3_rx_checksum(ring, skb, l234info, bd_base_info, ol_info,
csum);
return 0; return 0;
} }
...@@ -3252,7 +3546,16 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring, ...@@ -3252,7 +3546,16 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
HNS3_RXD_GRO_COUNT_M, HNS3_RXD_GRO_COUNT_M,
HNS3_RXD_GRO_COUNT_S); HNS3_RXD_GRO_COUNT_S);
l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M, HNS3_RXD_L3ID_S); if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) {
u32 ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
HNS3_RXD_PTYPE_S);
l3_type = hns3_rx_ptype_tbl[ptype].l3_type;
} else {
l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M,
HNS3_RXD_L3ID_S);
}
if (l3_type == HNS3_L3_TYPE_IPV4) if (l3_type == HNS3_L3_TYPE_IPV4)
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
else if (l3_type == HNS3_L3_TYPE_IPV6) else if (l3_type == HNS3_L3_TYPE_IPV6)
...@@ -3285,6 +3588,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) ...@@ -3285,6 +3588,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
struct hns3_desc *desc; struct hns3_desc *desc;
unsigned int len; unsigned int len;
int pre_ntc, ret; int pre_ntc, ret;
u16 csum;
/* bdinfo handled below is only valid on the last BD of the /* bdinfo handled below is only valid on the last BD of the
* current packet, and ring->next_to_clean indicates the first * current packet, and ring->next_to_clean indicates the first
...@@ -3296,6 +3600,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) ...@@ -3296,6 +3600,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
bd_base_info = le32_to_cpu(desc->rx.bd_base_info); bd_base_info = le32_to_cpu(desc->rx.bd_base_info);
l234info = le32_to_cpu(desc->rx.l234_info); l234info = le32_to_cpu(desc->rx.l234_info);
ol_info = le32_to_cpu(desc->rx.ol_info); ol_info = le32_to_cpu(desc->rx.ol_info);
csum = le16_to_cpu(desc->csum);
/* Based on hw strategy, the tag offloaded will be stored at /* Based on hw strategy, the tag offloaded will be stored at
* ot_vlan_tag in two layer tag case, and stored at vlan_tag * ot_vlan_tag in two layer tag case, and stored at vlan_tag
...@@ -3328,7 +3633,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) ...@@ -3328,7 +3633,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
/* This is needed in order to enable forwarding support */ /* This is needed in order to enable forwarding support */
ret = hns3_set_gro_and_checksum(ring, skb, l234info, ret = hns3_set_gro_and_checksum(ring, skb, l234info,
bd_base_info, ol_info); bd_base_info, ol_info, csum);
if (unlikely(ret)) { if (unlikely(ret)) {
u64_stats_update_begin(&ring->syncp); u64_stats_update_begin(&ring->syncp);
ring->stats.rx_err_cnt++; ring->stats.rx_err_cnt++;
...@@ -4343,13 +4648,21 @@ static int hns3_client_init(struct hnae3_handle *handle) ...@@ -4343,13 +4648,21 @@ static int hns3_client_init(struct hnae3_handle *handle)
hns3_dcbnl_setup(handle); hns3_dcbnl_setup(handle);
hns3_dbg_init(handle); ret = hns3_dbg_init(handle);
if (ret) {
dev_err(priv->dev, "failed to init debugfs, ret = %d\n",
ret);
goto out_client_start;
}
netdev->max_mtu = HNS3_MAX_MTU(ae_dev->dev_specs.max_frm_size); netdev->max_mtu = HNS3_MAX_MTU(ae_dev->dev_specs.max_frm_size);
if (test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps)) if (test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps))
set_bit(HNS3_NIC_STATE_HW_TX_CSUM_ENABLE, &priv->state); set_bit(HNS3_NIC_STATE_HW_TX_CSUM_ENABLE, &priv->state);
if (hnae3_ae_dev_rxd_adv_layout_supported(ae_dev))
set_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state);
set_bit(HNS3_NIC_STATE_INITED, &priv->state); set_bit(HNS3_NIC_STATE_INITED, &priv->state);
if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3) if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3)
......
...@@ -19,6 +19,7 @@ enum hns3_nic_state { ...@@ -19,6 +19,7 @@ enum hns3_nic_state {
HNS3_NIC_STATE_SERVICE_SCHED, HNS3_NIC_STATE_SERVICE_SCHED,
HNS3_NIC_STATE2_RESET_REQUESTED, HNS3_NIC_STATE2_RESET_REQUESTED,
HNS3_NIC_STATE_HW_TX_CSUM_ENABLE, HNS3_NIC_STATE_HW_TX_CSUM_ENABLE,
HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE,
HNS3_NIC_STATE_MAX HNS3_NIC_STATE_MAX
}; };
...@@ -82,12 +83,6 @@ enum hns3_nic_state { ...@@ -82,12 +83,6 @@ enum hns3_nic_state {
#define HNS3_RXD_STRP_TAGP_S 13 #define HNS3_RXD_STRP_TAGP_S 13
#define HNS3_RXD_STRP_TAGP_M (0x3 << HNS3_RXD_STRP_TAGP_S) #define HNS3_RXD_STRP_TAGP_M (0x3 << HNS3_RXD_STRP_TAGP_S)
#define HNS3_RXD_L2_CSUM_B 15
#define HNS3_RXD_L2_CSUM_L_S 4
#define HNS3_RXD_L2_CSUM_L_M (0xff << HNS3_RXD_L2_CSUM_L_S)
#define HNS3_RXD_L2_CSUM_H_S 24
#define HNS3_RXD_L2_CSUM_H_M (0xff << HNS3_RXD_L2_CSUM_H_S)
#define HNS3_RXD_L2E_B 16 #define HNS3_RXD_L2E_B 16
#define HNS3_RXD_L3E_B 17 #define HNS3_RXD_L3E_B 17
#define HNS3_RXD_L4E_B 18 #define HNS3_RXD_L4E_B 18
...@@ -114,6 +109,9 @@ enum hns3_nic_state { ...@@ -114,6 +109,9 @@ enum hns3_nic_state {
#define HNS3_RXD_FBLI_S 14 #define HNS3_RXD_FBLI_S 14
#define HNS3_RXD_FBLI_M (0x3 << HNS3_RXD_FBLI_S) #define HNS3_RXD_FBLI_M (0x3 << HNS3_RXD_FBLI_S)
#define HNS3_RXD_PTYPE_S 4
#define HNS3_RXD_PTYPE_M GENMASK(11, 4)
#define HNS3_RXD_BDTYPE_S 0 #define HNS3_RXD_BDTYPE_S 0
#define HNS3_RXD_BDTYPE_M (0xf << HNS3_RXD_BDTYPE_S) #define HNS3_RXD_BDTYPE_M (0xf << HNS3_RXD_BDTYPE_S)
#define HNS3_RXD_VLD_B 4 #define HNS3_RXD_VLD_B 4
...@@ -238,7 +236,10 @@ enum hns3_pkt_tun_type { ...@@ -238,7 +236,10 @@ enum hns3_pkt_tun_type {
/* hardware spec ring buffer format */ /* hardware spec ring buffer format */
struct __packed hns3_desc { struct __packed hns3_desc {
__le64 addr; union {
__le64 addr;
__le16 csum;
};
union { union {
struct { struct {
__le16 vlan_tag; __le16 vlan_tag;
...@@ -366,6 +367,14 @@ enum hns3_pkt_ol4type { ...@@ -366,6 +367,14 @@ enum hns3_pkt_ol4type {
HNS3_OL4_TYPE_UNKNOWN HNS3_OL4_TYPE_UNKNOWN
}; };
struct hns3_rx_ptype {
u32 ptype:8;
u32 csum_level:2;
u32 ip_summed:2;
u32 l3_type:4;
u32 valid:1;
};
struct ring_stats { struct ring_stats {
u64 sw_err_cnt; u64 sw_err_cnt;
u64 seg_pkt_cnt; u64 seg_pkt_cnt;
...@@ -397,6 +406,7 @@ struct ring_stats { ...@@ -397,6 +406,7 @@ struct ring_stats {
u64 rx_multicast; u64 rx_multicast;
u64 non_reuse_pg; u64 non_reuse_pg;
}; };
__le16 csum;
}; };
}; };
...@@ -640,9 +650,10 @@ void hns3_dcbnl_setup(struct hnae3_handle *handle); ...@@ -640,9 +650,10 @@ void hns3_dcbnl_setup(struct hnae3_handle *handle);
static inline void hns3_dcbnl_setup(struct hnae3_handle *handle) {} static inline void hns3_dcbnl_setup(struct hnae3_handle *handle) {}
#endif #endif
void hns3_dbg_init(struct hnae3_handle *handle); int hns3_dbg_init(struct hnae3_handle *handle);
void hns3_dbg_uninit(struct hnae3_handle *handle); void hns3_dbg_uninit(struct hnae3_handle *handle);
void hns3_dbg_register_debugfs(const char *debugfs_dir_name); void hns3_dbg_register_debugfs(const char *debugfs_dir_name);
void hns3_dbg_unregister_debugfs(void); void hns3_dbg_unregister_debugfs(void);
void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size); void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size);
u16 hns3_get_max_available_channels(struct hnae3_handle *h);
#endif #endif
...@@ -386,6 +386,8 @@ static void hclge_parse_capability(struct hclge_dev *hdev, ...@@ -386,6 +386,8 @@ static void hclge_parse_capability(struct hclge_dev *hdev,
set_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps); set_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGE_CAP_PHY_IMP_B)) if (hnae3_get_bit(caps, HCLGE_CAP_PHY_IMP_B))
set_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps); set_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGE_CAP_RXD_ADV_LAYOUT_B))
set_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, ae_dev->caps);
} }
static __le32 hclge_build_api_caps(void) static __le32 hclge_build_api_caps(void)
...@@ -469,7 +471,7 @@ static int hclge_firmware_compat_config(struct hclge_dev *hdev) ...@@ -469,7 +471,7 @@ static int hclge_firmware_compat_config(struct hclge_dev *hdev)
struct hclge_desc desc; struct hclge_desc desc;
u32 compat = 0; u32 compat = 0;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_COMPAT_CFG, false); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_COMPAT_CFG, false);
req = (struct hclge_firmware_compat_cmd *)desc.data; req = (struct hclge_firmware_compat_cmd *)desc.data;
......
...@@ -267,10 +267,10 @@ enum hclge_opcode_type { ...@@ -267,10 +267,10 @@ enum hclge_opcode_type {
/* NCL config command */ /* NCL config command */
HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011, HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011,
/* M7 stats command */ /* IMP stats command */
HCLGE_OPC_M7_STATS_BD = 0x7012, HCLGE_OPC_IMP_STATS_BD = 0x7012,
HCLGE_OPC_M7_STATS_INFO = 0x7013, HCLGE_OPC_IMP_STATS_INFO = 0x7013,
HCLGE_OPC_M7_COMPAT_CFG = 0x701A, HCLGE_OPC_IMP_COMPAT_CFG = 0x701A,
/* SFP command */ /* SFP command */
HCLGE_OPC_GET_SFP_EEPROM = 0x7100, HCLGE_OPC_GET_SFP_EEPROM = 0x7100,
...@@ -391,6 +391,7 @@ enum HCLGE_CAP_BITS { ...@@ -391,6 +391,7 @@ enum HCLGE_CAP_BITS {
HCLGE_CAP_UDP_TUNNEL_CSUM_B, HCLGE_CAP_UDP_TUNNEL_CSUM_B,
HCLGE_CAP_FEC_B = 13, HCLGE_CAP_FEC_B = 13,
HCLGE_CAP_PAUSE_B = 14, HCLGE_CAP_PAUSE_B = 14,
HCLGE_CAP_RXD_ADV_LAYOUT_B = 15,
}; };
enum HCLGE_API_CAP_BITS { enum HCLGE_API_CAP_BITS {
...@@ -1100,7 +1101,7 @@ struct hclge_fd_user_def_cfg_cmd { ...@@ -1100,7 +1101,7 @@ struct hclge_fd_user_def_cfg_cmd {
u8 rsv[12]; u8 rsv[12];
}; };
struct hclge_get_m7_bd_cmd { struct hclge_get_imp_bd_cmd {
__le32 bd_num; __le32 bd_num;
u8 rsv[20]; u8 rsv[20];
}; };
......
...@@ -4,10 +4,16 @@ ...@@ -4,10 +4,16 @@
#include <linux/device.h> #include <linux/device.h>
#include "hclge_debugfs.h" #include "hclge_debugfs.h"
#include "hclge_err.h"
#include "hclge_main.h" #include "hclge_main.h"
#include "hclge_tm.h" #include "hclge_tm.h"
#include "hnae3.h" #include "hnae3.h"
static const char * const state_str[] = { "off", "on" };
static const char * const hclge_mac_state_str[] = {
"TO_ADD", "TO_DEL", "ACTIVE"
};
static const struct hclge_dbg_reg_type_info hclge_dbg_reg_info[] = { static const struct hclge_dbg_reg_type_info hclge_dbg_reg_info[] = {
{ .reg_type = "bios common", { .reg_type = "bios common",
.dfx_msg = &hclge_dbg_bios_common_reg[0], .dfx_msg = &hclge_dbg_bios_common_reg[0],
...@@ -71,6 +77,35 @@ static const struct hclge_dbg_reg_type_info hclge_dbg_reg_info[] = { ...@@ -71,6 +77,35 @@ static const struct hclge_dbg_reg_type_info hclge_dbg_reg_info[] = {
.cmd = HCLGE_OPC_DFX_TQP_REG } }, .cmd = HCLGE_OPC_DFX_TQP_REG } },
}; };
static void hclge_dbg_fill_content(char *content, u16 len,
const struct hclge_dbg_item *items,
const char **result, u16 size)
{
char *pos = content;
u16 i;
memset(content, ' ', len);
for (i = 0; i < size; i++) {
if (result)
strncpy(pos, result[i], strlen(result[i]));
else
strncpy(pos, items[i].name, strlen(items[i].name));
pos += strlen(items[i].name) + items[i].interval;
}
*pos++ = '\n';
*pos++ = '\0';
}
static char *hclge_dbg_get_func_id_str(char *buf, u8 id)
{
if (id)
sprintf(buf, "vf%u", id - 1);
else
sprintf(buf, "pf");
return buf;
}
static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset) static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset)
{ {
struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT]; struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
...@@ -1179,24 +1214,19 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) ...@@ -1179,24 +1214,19 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev)
"dump qos buf cfg fail(0x%x), ret = %d\n", cmd, ret); "dump qos buf cfg fail(0x%x), ret = %d\n", cmd, ret);
} }
static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev) static int hclge_dbg_dump_mng_table(struct hclge_dev *hdev, char *buf, int len)
{ {
struct hclge_mac_ethertype_idx_rd_cmd *req0; struct hclge_mac_ethertype_idx_rd_cmd *req0;
char printf_buf[HCLGE_DBG_BUF_LEN];
struct hclge_desc desc; struct hclge_desc desc;
u32 msg_egress_port; u32 msg_egress_port;
int pos = 0;
int ret, i; int ret, i;
dev_info(&hdev->pdev->dev, "mng tab:\n"); pos += scnprintf(buf + pos, len - pos,
memset(printf_buf, 0, HCLGE_DBG_BUF_LEN); "entry mac_addr mask ether ");
strncat(printf_buf, pos += scnprintf(buf + pos, len - pos,
"entry|mac_addr |mask|ether|mask|vlan|mask", "mask vlan mask i_map i_dir e_type ");
HCLGE_DBG_BUF_LEN - 1); pos += scnprintf(buf + pos, len - pos, "pf_id vf_id q_id drop\n");
strncat(printf_buf + strlen(printf_buf),
"|i_map|i_dir|e_type|pf_id|vf_id|q_id|drop\n",
HCLGE_DBG_BUF_LEN - strlen(printf_buf) - 1);
dev_info(&hdev->pdev->dev, "%s", printf_buf);
for (i = 0; i < HCLGE_DBG_MNG_TBL_MAX; i++) { for (i = 0; i < HCLGE_DBG_MNG_TBL_MAX; i++) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_MAC_ETHERTYPE_IDX_RD, hclge_cmd_setup_basic_desc(&desc, HCLGE_MAC_ETHERTYPE_IDX_RD,
...@@ -1207,43 +1237,40 @@ static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev) ...@@ -1207,43 +1237,40 @@ static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev)
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"call hclge_cmd_send fail, ret = %d\n", ret); "failed to dump manage table, ret = %d\n", ret);
return; return ret;
} }
if (!req0->resp_code) if (!req0->resp_code)
continue; continue;
memset(printf_buf, 0, HCLGE_DBG_BUF_LEN); pos += scnprintf(buf + pos, len - pos, "%02u %pM ",
snprintf(printf_buf, HCLGE_DBG_BUF_LEN, le16_to_cpu(req0->index), req0->mac_addr);
"%02u |%02x:%02x:%02x:%02x:%02x:%02x|",
le16_to_cpu(req0->index), pos += scnprintf(buf + pos, len - pos,
req0->mac_addr[0], req0->mac_addr[1], "%x %04x %x %04x ",
req0->mac_addr[2], req0->mac_addr[3], !!(req0->flags & HCLGE_DBG_MNG_MAC_MASK_B),
req0->mac_addr[4], req0->mac_addr[5]); le16_to_cpu(req0->ethter_type),
!!(req0->flags & HCLGE_DBG_MNG_ETHER_MASK_B),
snprintf(printf_buf + strlen(printf_buf), le16_to_cpu(req0->vlan_tag) &
HCLGE_DBG_BUF_LEN - strlen(printf_buf), HCLGE_DBG_MNG_VLAN_TAG);
"%x |%04x |%x |%04x|%x |%02x |%02x |",
!!(req0->flags & HCLGE_DBG_MNG_MAC_MASK_B), pos += scnprintf(buf + pos, len - pos,
le16_to_cpu(req0->ethter_type), "%x %02x %02x ",
!!(req0->flags & HCLGE_DBG_MNG_ETHER_MASK_B), !!(req0->flags & HCLGE_DBG_MNG_VLAN_MASK_B),
le16_to_cpu(req0->vlan_tag) & HCLGE_DBG_MNG_VLAN_TAG, req0->i_port_bitmap, req0->i_port_direction);
!!(req0->flags & HCLGE_DBG_MNG_VLAN_MASK_B),
req0->i_port_bitmap, req0->i_port_direction);
msg_egress_port = le16_to_cpu(req0->egress_port); msg_egress_port = le16_to_cpu(req0->egress_port);
snprintf(printf_buf + strlen(printf_buf), pos += scnprintf(buf + pos, len - pos,
HCLGE_DBG_BUF_LEN - strlen(printf_buf), "%x %x %02x %04x %x\n",
"%x |%x |%02x |%04x|%x\n", !!(msg_egress_port & HCLGE_DBG_MNG_E_TYPE_B),
!!(msg_egress_port & HCLGE_DBG_MNG_E_TYPE_B), msg_egress_port & HCLGE_DBG_MNG_PF_ID,
msg_egress_port & HCLGE_DBG_MNG_PF_ID, (msg_egress_port >> 3) & HCLGE_DBG_MNG_VF_ID,
(msg_egress_port >> 3) & HCLGE_DBG_MNG_VF_ID, le16_to_cpu(req0->egress_queue),
le16_to_cpu(req0->egress_queue), !!(msg_egress_port & HCLGE_DBG_MNG_DROP_B));
!!(msg_egress_port & HCLGE_DBG_MNG_DROP_B));
dev_info(&hdev->pdev->dev, "%s", printf_buf);
} }
return 0;
} }
static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, u8 stage, static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, u8 stage,
...@@ -1363,37 +1390,46 @@ static void hclge_dbg_fd_tcam(struct hclge_dev *hdev) ...@@ -1363,37 +1390,46 @@ static void hclge_dbg_fd_tcam(struct hclge_dev *hdev)
kfree(rule_locs); kfree(rule_locs);
} }
void hclge_dbg_dump_rst_info(struct hclge_dev *hdev) int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len)
{ {
dev_info(&hdev->pdev->dev, "PF reset count: %u\n", int pos = 0;
hdev->rst_stats.pf_rst_cnt);
dev_info(&hdev->pdev->dev, "FLR reset count: %u\n", pos += scnprintf(buf + pos, len - pos, "PF reset count: %u\n",
hdev->rst_stats.flr_rst_cnt); hdev->rst_stats.pf_rst_cnt);
dev_info(&hdev->pdev->dev, "GLOBAL reset count: %u\n", pos += scnprintf(buf + pos, len - pos, "FLR reset count: %u\n",
hdev->rst_stats.global_rst_cnt); hdev->rst_stats.flr_rst_cnt);
dev_info(&hdev->pdev->dev, "IMP reset count: %u\n", pos += scnprintf(buf + pos, len - pos, "GLOBAL reset count: %u\n",
hdev->rst_stats.imp_rst_cnt); hdev->rst_stats.global_rst_cnt);
dev_info(&hdev->pdev->dev, "reset done count: %u\n", pos += scnprintf(buf + pos, len - pos, "IMP reset count: %u\n",
hdev->rst_stats.reset_done_cnt); hdev->rst_stats.imp_rst_cnt);
dev_info(&hdev->pdev->dev, "HW reset done count: %u\n", pos += scnprintf(buf + pos, len - pos, "reset done count: %u\n",
hdev->rst_stats.hw_reset_done_cnt); hdev->rst_stats.reset_done_cnt);
dev_info(&hdev->pdev->dev, "reset count: %u\n", pos += scnprintf(buf + pos, len - pos, "HW reset done count: %u\n",
hdev->rst_stats.reset_cnt); hdev->rst_stats.hw_reset_done_cnt);
dev_info(&hdev->pdev->dev, "reset fail count: %u\n", pos += scnprintf(buf + pos, len - pos, "reset count: %u\n",
hdev->rst_stats.reset_fail_cnt); hdev->rst_stats.reset_cnt);
dev_info(&hdev->pdev->dev, "vector0 interrupt enable status: 0x%x\n", pos += scnprintf(buf + pos, len - pos, "reset fail count: %u\n",
hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_REG_BASE)); hdev->rst_stats.reset_fail_cnt);
dev_info(&hdev->pdev->dev, "reset interrupt source: 0x%x\n", pos += scnprintf(buf + pos, len - pos,
hclge_read_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG)); "vector0 interrupt enable status: 0x%x\n",
dev_info(&hdev->pdev->dev, "reset interrupt status: 0x%x\n", hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_REG_BASE));
hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS)); pos += scnprintf(buf + pos, len - pos, "reset interrupt source: 0x%x\n",
dev_info(&hdev->pdev->dev, "hardware reset status: 0x%x\n", hclge_read_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG));
hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG)); pos += scnprintf(buf + pos, len - pos, "reset interrupt status: 0x%x\n",
dev_info(&hdev->pdev->dev, "handshake status: 0x%x\n", hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS));
hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG)); pos += scnprintf(buf + pos, len - pos, "RAS interrupt status: 0x%x\n",
dev_info(&hdev->pdev->dev, "function reset status: 0x%x\n", hclge_read_dev(&hdev->hw,
hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING)); HCLGE_RAS_PF_OTHER_INT_STS_REG));
dev_info(&hdev->pdev->dev, "hdev state: 0x%lx\n", hdev->state); pos += scnprintf(buf + pos, len - pos, "hardware reset status: 0x%x\n",
hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG));
pos += scnprintf(buf + pos, len - pos, "handshake status: 0x%x\n",
hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG));
pos += scnprintf(buf + pos, len - pos, "function reset status: 0x%x\n",
hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING));
pos += scnprintf(buf + pos, len - pos, "hdev state: 0x%lx\n",
hdev->state);
return 0;
} }
static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev) static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev)
...@@ -1404,169 +1440,179 @@ static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev) ...@@ -1404,169 +1440,179 @@ static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev)
hdev->serv_processed_cnt); hdev->serv_processed_cnt);
} }
static void hclge_dbg_dump_interrupt(struct hclge_dev *hdev) static int hclge_dbg_dump_interrupt(struct hclge_dev *hdev, char *buf, int len)
{ {
dev_info(&hdev->pdev->dev, "num_nic_msi: %u\n", hdev->num_nic_msi); int pos = 0;
dev_info(&hdev->pdev->dev, "num_roce_msi: %u\n", hdev->num_roce_msi);
dev_info(&hdev->pdev->dev, "num_msi_used: %u\n", hdev->num_msi_used); pos += scnprintf(buf + pos, len - pos, "num_nic_msi: %u\n",
dev_info(&hdev->pdev->dev, "num_msi_left: %u\n", hdev->num_msi_left); hdev->num_nic_msi);
pos += scnprintf(buf + pos, len - pos, "num_roce_msi: %u\n",
hdev->num_roce_msi);
pos += scnprintf(buf + pos, len - pos, "num_msi_used: %u\n",
hdev->num_msi_used);
pos += scnprintf(buf + pos, len - pos, "num_msi_left: %u\n",
hdev->num_msi_left);
return 0;
} }
static void hclge_dbg_get_m7_stats_info(struct hclge_dev *hdev) static void hclge_dbg_imp_info_data_print(struct hclge_desc *desc_src,
char *buf, int len, u32 bd_num)
{ {
struct hclge_desc *desc_src, *desc_tmp; #define HCLGE_DBG_IMP_INFO_PRINT_OFFSET 0x2
struct hclge_get_m7_bd_cmd *req;
struct hclge_desc *desc_index = desc_src;
u32 offset = 0;
int pos = 0;
u32 i, j;
pos += scnprintf(buf + pos, len - pos, "offset | data\n");
for (i = 0; i < bd_num; i++) {
j = 0;
while (j < HCLGE_DESC_DATA_LEN - 1) {
pos += scnprintf(buf + pos, len - pos, "0x%04x | ",
offset);
pos += scnprintf(buf + pos, len - pos, "0x%08x ",
le32_to_cpu(desc_index->data[j++]));
pos += scnprintf(buf + pos, len - pos, "0x%08x\n",
le32_to_cpu(desc_index->data[j++]));
offset += sizeof(u32) * HCLGE_DBG_IMP_INFO_PRINT_OFFSET;
}
desc_index++;
}
}
static int
hclge_dbg_get_imp_stats_info(struct hclge_dev *hdev, char *buf, int len)
{
struct hclge_get_imp_bd_cmd *req;
struct hclge_desc *desc_src;
struct hclge_desc desc; struct hclge_desc desc;
u32 bd_num, buf_len; u32 bd_num;
int ret, i; int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_STATS_BD, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_STATS_BD, true);
req = (struct hclge_get_m7_bd_cmd *)desc.data; req = (struct hclge_get_imp_bd_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"get firmware statistics bd number failed, ret = %d\n", "failed to get imp statistics bd number, ret = %d\n",
ret); ret);
return; return ret;
} }
bd_num = le32_to_cpu(req->bd_num); bd_num = le32_to_cpu(req->bd_num);
buf_len = sizeof(struct hclge_desc) * bd_num; desc_src = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
desc_src = kzalloc(buf_len, GFP_KERNEL);
if (!desc_src) if (!desc_src)
return; return -ENOMEM;
desc_tmp = desc_src; ret = hclge_dbg_cmd_send(hdev, desc_src, 0, bd_num,
ret = hclge_dbg_cmd_send(hdev, desc_tmp, 0, bd_num, HCLGE_OPC_IMP_STATS_INFO);
HCLGE_OPC_M7_STATS_INFO);
if (ret) { if (ret) {
kfree(desc_src); kfree(desc_src);
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"get firmware statistics failed, ret = %d\n", ret); "failed to get imp statistics, ret = %d\n", ret);
return; return ret;
} }
for (i = 0; i < bd_num; i++) { hclge_dbg_imp_info_data_print(desc_src, buf, len, bd_num);
dev_info(&hdev->pdev->dev, "0x%08x 0x%08x 0x%08x\n",
le32_to_cpu(desc_tmp->data[0]),
le32_to_cpu(desc_tmp->data[1]),
le32_to_cpu(desc_tmp->data[2]));
dev_info(&hdev->pdev->dev, "0x%08x 0x%08x 0x%08x\n",
le32_to_cpu(desc_tmp->data[3]),
le32_to_cpu(desc_tmp->data[4]),
le32_to_cpu(desc_tmp->data[5]));
desc_tmp++;
}
kfree(desc_src); kfree(desc_src);
return 0;
} }
#define HCLGE_CMD_NCL_CONFIG_BD_NUM 5 #define HCLGE_CMD_NCL_CONFIG_BD_NUM 5
#define HCLGE_MAX_NCL_CONFIG_LENGTH 16384
static void hclge_ncl_config_data_print(struct hclge_dev *hdev, static void hclge_ncl_config_data_print(struct hclge_desc *desc, int *index,
struct hclge_desc *desc, int *offset, char *buf, int *len, int *pos)
int *length)
{ {
#define HCLGE_CMD_DATA_NUM 6 #define HCLGE_CMD_DATA_NUM 6
int i; int offset = HCLGE_MAX_NCL_CONFIG_LENGTH - *index;
int j; int i, j;
for (i = 0; i < HCLGE_CMD_NCL_CONFIG_BD_NUM; i++) { for (i = 0; i < HCLGE_CMD_NCL_CONFIG_BD_NUM; i++) {
for (j = 0; j < HCLGE_CMD_DATA_NUM; j++) { for (j = 0; j < HCLGE_CMD_DATA_NUM; j++) {
if (i == 0 && j == 0) if (i == 0 && j == 0)
continue; continue;
dev_info(&hdev->pdev->dev, "0x%04x | 0x%08x\n", *pos += scnprintf(buf + *pos, *len - *pos,
*offset, "0x%04x | 0x%08x\n", offset,
le32_to_cpu(desc[i].data[j])); le32_to_cpu(desc[i].data[j]));
*offset += sizeof(u32);
*length -= sizeof(u32); offset += sizeof(u32);
if (*length <= 0) *index -= sizeof(u32);
if (*index <= 0)
return; return;
} }
} }
} }
/* hclge_dbg_dump_ncl_config: print specified range of NCL_CONFIG file static int
* @hdev: pointer to struct hclge_dev hclge_dbg_dump_ncl_config(struct hclge_dev *hdev, char *buf, int len)
* @cmd_buf: string that contains offset and length
*/
static void hclge_dbg_dump_ncl_config(struct hclge_dev *hdev,
const char *cmd_buf)
{ {
#define HCLGE_MAX_NCL_CONFIG_OFFSET 4096
#define HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD (20 + 24 * 4) #define HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD (20 + 24 * 4)
#define HCLGE_NCL_CONFIG_PARAM_NUM 2
struct hclge_desc desc[HCLGE_CMD_NCL_CONFIG_BD_NUM]; struct hclge_desc desc[HCLGE_CMD_NCL_CONFIG_BD_NUM];
int bd_num = HCLGE_CMD_NCL_CONFIG_BD_NUM; int bd_num = HCLGE_CMD_NCL_CONFIG_BD_NUM;
int offset; int index = HCLGE_MAX_NCL_CONFIG_LENGTH;
int length; int pos = 0;
int data0; u32 data0;
int ret; int ret;
ret = sscanf(cmd_buf, "%x %x", &offset, &length); pos += scnprintf(buf + pos, len - pos, "offset | data\n");
if (ret != HCLGE_NCL_CONFIG_PARAM_NUM) {
dev_err(&hdev->pdev->dev,
"Too few parameters, num = %d.\n", ret);
return;
}
if (offset < 0 || offset >= HCLGE_MAX_NCL_CONFIG_OFFSET ||
length <= 0 || length > HCLGE_MAX_NCL_CONFIG_OFFSET - offset) {
dev_err(&hdev->pdev->dev,
"Invalid input, offset = %d, length = %d.\n",
offset, length);
return;
}
dev_info(&hdev->pdev->dev, "offset | data\n"); while (index > 0) {
data0 = HCLGE_MAX_NCL_CONFIG_LENGTH - index;
while (length > 0) { if (index >= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD)
data0 = offset;
if (length >= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD)
data0 |= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD << 16; data0 |= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD << 16;
else else
data0 |= length << 16; data0 |= (u32)index << 16;
ret = hclge_dbg_cmd_send(hdev, desc, data0, bd_num, ret = hclge_dbg_cmd_send(hdev, desc, data0, bd_num,
HCLGE_OPC_QUERY_NCL_CONFIG); HCLGE_OPC_QUERY_NCL_CONFIG);
if (ret) if (ret)
return; return ret;
hclge_ncl_config_data_print(hdev, desc, &offset, &length); hclge_ncl_config_data_print(desc, &index, buf, &len, &pos);
} }
return 0;
} }
static void hclge_dbg_dump_loopback(struct hclge_dev *hdev) static int hclge_dbg_dump_loopback(struct hclge_dev *hdev, char *buf, int len)
{ {
struct phy_device *phydev = hdev->hw.mac.phydev; struct phy_device *phydev = hdev->hw.mac.phydev;
struct hclge_config_mac_mode_cmd *req_app; struct hclge_config_mac_mode_cmd *req_app;
struct hclge_common_lb_cmd *req_common; struct hclge_common_lb_cmd *req_common;
struct hclge_desc desc; struct hclge_desc desc;
u8 loopback_en; u8 loopback_en;
int pos = 0;
int ret; int ret;
req_app = (struct hclge_config_mac_mode_cmd *)desc.data; req_app = (struct hclge_config_mac_mode_cmd *)desc.data;
req_common = (struct hclge_common_lb_cmd *)desc.data; req_common = (struct hclge_common_lb_cmd *)desc.data;
dev_info(&hdev->pdev->dev, "mac id: %u\n", hdev->hw.mac.mac_id); pos += scnprintf(buf + pos, len - pos, "mac id: %u\n",
hdev->hw.mac.mac_id);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"failed to dump app loopback status, ret = %d\n", ret); "failed to dump app loopback status, ret = %d\n", ret);
return; return ret;
} }
loopback_en = hnae3_get_bit(le32_to_cpu(req_app->txrx_pad_fcs_loop_en), loopback_en = hnae3_get_bit(le32_to_cpu(req_app->txrx_pad_fcs_loop_en),
HCLGE_MAC_APP_LP_B); HCLGE_MAC_APP_LP_B);
dev_info(&hdev->pdev->dev, "app loopback: %s\n", pos += scnprintf(buf + pos, len - pos, "app loopback: %s\n",
loopback_en ? "on" : "off"); state_str[loopback_en]);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMMON_LOOPBACK, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMMON_LOOPBACK, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
...@@ -1574,27 +1620,30 @@ static void hclge_dbg_dump_loopback(struct hclge_dev *hdev) ...@@ -1574,27 +1620,30 @@ static void hclge_dbg_dump_loopback(struct hclge_dev *hdev)
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"failed to dump common loopback status, ret = %d\n", "failed to dump common loopback status, ret = %d\n",
ret); ret);
return; return ret;
} }
loopback_en = req_common->enable & HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B; loopback_en = req_common->enable & HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
dev_info(&hdev->pdev->dev, "serdes serial loopback: %s\n", pos += scnprintf(buf + pos, len - pos, "serdes serial loopback: %s\n",
loopback_en ? "on" : "off"); state_str[loopback_en]);
loopback_en = req_common->enable & loopback_en = req_common->enable &
HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B; HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B ? 1 : 0;
dev_info(&hdev->pdev->dev, "serdes parallel loopback: %s\n", pos += scnprintf(buf + pos, len - pos, "serdes parallel loopback: %s\n",
loopback_en ? "on" : "off"); state_str[loopback_en]);
if (phydev) { if (phydev) {
dev_info(&hdev->pdev->dev, "phy loopback: %s\n", loopback_en = phydev->loopback_enabled;
phydev->loopback_enabled ? "on" : "off"); pos += scnprintf(buf + pos, len - pos, "phy loopback: %s\n",
state_str[loopback_en]);
} else if (hnae3_dev_phy_imp_supported(hdev)) { } else if (hnae3_dev_phy_imp_supported(hdev)) {
loopback_en = req_common->enable & loopback_en = req_common->enable &
HCLGE_CMD_GE_PHY_INNER_LOOP_B; HCLGE_CMD_GE_PHY_INNER_LOOP_B;
dev_info(&hdev->pdev->dev, "phy loopback: %s\n", pos += scnprintf(buf + pos, len - pos, "phy loopback: %s\n",
loopback_en ? "on" : "off"); state_str[loopback_en]);
} }
return 0;
} }
/* hclge_dbg_dump_mac_tnl_status: print message about mac tnl interrupt /* hclge_dbg_dump_mac_tnl_status: print message about mac tnl interrupt
...@@ -1693,45 +1742,65 @@ static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev, ...@@ -1693,45 +1742,65 @@ static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev,
hclge_dbg_dump_qs_shaper_single(hdev, qsid); hclge_dbg_dump_qs_shaper_single(hdev, qsid);
} }
static int hclge_dbg_dump_mac_list(struct hclge_dev *hdev, const char *cmd_buf, static const struct hclge_dbg_item mac_list_items[] = {
bool is_unicast) { "FUNC_ID", 2 },
{ "MAC_ADDR", 12 },
{ "STATE", 2 },
};
static void hclge_dbg_dump_mac_list(struct hclge_dev *hdev, char *buf, int len,
bool is_unicast)
{ {
char data_str[ARRAY_SIZE(mac_list_items)][HCLGE_DBG_DATA_STR_LEN];
char content[HCLGE_DBG_INFO_LEN], str_id[HCLGE_DBG_ID_LEN];
char *result[ARRAY_SIZE(mac_list_items)];
struct hclge_mac_node *mac_node, *tmp; struct hclge_mac_node *mac_node, *tmp;
struct hclge_vport *vport; struct hclge_vport *vport;
struct list_head *list; struct list_head *list;
u32 func_id; u32 func_id;
int ret; int pos = 0;
int i;
ret = kstrtouint(cmd_buf, 0, &func_id);
if (ret < 0) {
dev_err(&hdev->pdev->dev,
"dump mac list: bad command string, ret = %d\n", ret);
return -EINVAL;
}
if (func_id >= hdev->num_alloc_vport) { for (i = 0; i < ARRAY_SIZE(mac_list_items); i++)
dev_err(&hdev->pdev->dev, result[i] = &data_str[i][0];
"function id(%u) is out of range(0-%u)\n", func_id,
hdev->num_alloc_vport - 1); pos += scnprintf(buf + pos, len - pos, "%s MAC_LIST:\n",
return -EINVAL; is_unicast ? "UC" : "MC");
hclge_dbg_fill_content(content, sizeof(content), mac_list_items,
NULL, ARRAY_SIZE(mac_list_items));
pos += scnprintf(buf + pos, len - pos, "%s", content);
for (func_id = 0; func_id < hdev->num_alloc_vport; func_id++) {
vport = &hdev->vport[func_id];
list = is_unicast ? &vport->uc_mac_list : &vport->mc_mac_list;
spin_lock_bh(&vport->mac_list_lock);
list_for_each_entry_safe(mac_node, tmp, list, node) {
i = 0;
result[i++] = hclge_dbg_get_func_id_str(str_id,
func_id);
sprintf(result[i++], "%pM", mac_node->mac_addr);
sprintf(result[i++], "%5s",
hclge_mac_state_str[mac_node->state]);
hclge_dbg_fill_content(content, sizeof(content),
mac_list_items,
(const char **)result,
ARRAY_SIZE(mac_list_items));
pos += scnprintf(buf + pos, len - pos, "%s", content);
}
spin_unlock_bh(&vport->mac_list_lock);
} }
}
vport = &hdev->vport[func_id]; static int hclge_dbg_dump_mac_uc(struct hclge_dev *hdev, char *buf, int len)
{
list = is_unicast ? &vport->uc_mac_list : &vport->mc_mac_list; hclge_dbg_dump_mac_list(hdev, buf, len, true);
dev_info(&hdev->pdev->dev, "vport %u %s mac list:\n",
func_id, is_unicast ? "uc" : "mc");
dev_info(&hdev->pdev->dev, "mac address state\n");
spin_lock_bh(&vport->mac_list_lock);
list_for_each_entry_safe(mac_node, tmp, list, node) { return 0;
dev_info(&hdev->pdev->dev, "%pM %d\n", }
mac_node->mac_addr, mac_node->state);
}
spin_unlock_bh(&vport->mac_list_lock); static int hclge_dbg_dump_mac_mc(struct hclge_dev *hdev, char *buf, int len)
{
hclge_dbg_dump_mac_list(hdev, buf, len, false);
return 0; return 0;
} }
...@@ -1740,8 +1809,6 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf) ...@@ -1740,8 +1809,6 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
{ {
#define DUMP_REG "dump reg" #define DUMP_REG "dump reg"
#define DUMP_TM_MAP "dump tm map" #define DUMP_TM_MAP "dump tm map"
#define DUMP_LOOPBACK "dump loopback"
#define DUMP_INTERRUPT "dump intr"
struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
...@@ -1760,38 +1827,15 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf) ...@@ -1760,38 +1827,15 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
hclge_dbg_dump_qos_pri_map(hdev); hclge_dbg_dump_qos_pri_map(hdev);
} else if (strncmp(cmd_buf, "dump qos buf cfg", 16) == 0) { } else if (strncmp(cmd_buf, "dump qos buf cfg", 16) == 0) {
hclge_dbg_dump_qos_buf_cfg(hdev); hclge_dbg_dump_qos_buf_cfg(hdev);
} else if (strncmp(cmd_buf, "dump mng tbl", 12) == 0) {
hclge_dbg_dump_mng_table(hdev);
} else if (strncmp(cmd_buf, DUMP_REG, strlen(DUMP_REG)) == 0) { } else if (strncmp(cmd_buf, DUMP_REG, strlen(DUMP_REG)) == 0) {
hclge_dbg_dump_reg_cmd(hdev, &cmd_buf[sizeof(DUMP_REG)]); hclge_dbg_dump_reg_cmd(hdev, &cmd_buf[sizeof(DUMP_REG)]);
} else if (strncmp(cmd_buf, "dump reset info", 15) == 0) {
hclge_dbg_dump_rst_info(hdev);
} else if (strncmp(cmd_buf, "dump serv info", 14) == 0) { } else if (strncmp(cmd_buf, "dump serv info", 14) == 0) {
hclge_dbg_dump_serv_info(hdev); hclge_dbg_dump_serv_info(hdev);
} else if (strncmp(cmd_buf, "dump m7 info", 12) == 0) {
hclge_dbg_get_m7_stats_info(hdev);
} else if (strncmp(cmd_buf, "dump ncl_config", 15) == 0) {
hclge_dbg_dump_ncl_config(hdev,
&cmd_buf[sizeof("dump ncl_config")]);
} else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) { } else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) {
hclge_dbg_dump_mac_tnl_status(hdev); hclge_dbg_dump_mac_tnl_status(hdev);
} else if (strncmp(cmd_buf, DUMP_LOOPBACK,
strlen(DUMP_LOOPBACK)) == 0) {
hclge_dbg_dump_loopback(hdev);
} else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) { } else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) {
hclge_dbg_dump_qs_shaper(hdev, hclge_dbg_dump_qs_shaper(hdev,
&cmd_buf[sizeof("dump qs shaper")]); &cmd_buf[sizeof("dump qs shaper")]);
} else if (strncmp(cmd_buf, "dump uc mac list", 16) == 0) {
hclge_dbg_dump_mac_list(hdev,
&cmd_buf[sizeof("dump uc mac list")],
true);
} else if (strncmp(cmd_buf, "dump mc mac list", 16) == 0) {
hclge_dbg_dump_mac_list(hdev,
&cmd_buf[sizeof("dump mc mac list")],
false);
} else if (strncmp(cmd_buf, DUMP_INTERRUPT,
strlen(DUMP_INTERRUPT)) == 0) {
hclge_dbg_dump_interrupt(hdev);
} else { } else {
dev_info(&hdev->pdev->dev, "unknown command\n"); dev_info(&hdev->pdev->dev, "unknown command\n");
return -EINVAL; return -EINVAL;
...@@ -1800,21 +1844,65 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf) ...@@ -1800,21 +1844,65 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
return 0; return 0;
} }
int hclge_dbg_read_cmd(struct hnae3_handle *handle, const char *cmd_buf, static const struct hclge_dbg_func hclge_dbg_cmd_func[] = {
{
.cmd = HNAE3_DBG_CMD_TM_NODES,
.dbg_dump = hclge_dbg_dump_tm_nodes,
},
{
.cmd = HNAE3_DBG_CMD_TM_PRI,
.dbg_dump = hclge_dbg_dump_tm_pri,
},
{
.cmd = HNAE3_DBG_CMD_TM_QSET,
.dbg_dump = hclge_dbg_dump_tm_qset,
},
{
.cmd = HNAE3_DBG_CMD_MAC_UC,
.dbg_dump = hclge_dbg_dump_mac_uc,
},
{
.cmd = HNAE3_DBG_CMD_MAC_MC,
.dbg_dump = hclge_dbg_dump_mac_mc,
},
{
.cmd = HNAE3_DBG_CMD_MNG_TBL,
.dbg_dump = hclge_dbg_dump_mng_table,
},
{
.cmd = HNAE3_DBG_CMD_LOOPBACK,
.dbg_dump = hclge_dbg_dump_loopback,
},
{
.cmd = HNAE3_DBG_CMD_INTERRUPT_INFO,
.dbg_dump = hclge_dbg_dump_interrupt,
},
{
.cmd = HNAE3_DBG_CMD_RESET_INFO,
.dbg_dump = hclge_dbg_dump_rst_info,
},
{
.cmd = HNAE3_DBG_CMD_IMP_INFO,
.dbg_dump = hclge_dbg_get_imp_stats_info,
},
{
.cmd = HNAE3_DBG_CMD_NCL_CONFIG,
.dbg_dump = hclge_dbg_dump_ncl_config,
},
};
int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len) char *buf, int len)
{ {
struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
u32 i;
if (strncmp(cmd_buf, HNAE3_DBG_TM_NODES, for (i = 0; i < ARRAY_SIZE(hclge_dbg_cmd_func); i++) {
strlen(HNAE3_DBG_TM_NODES)) == 0) if (cmd == hclge_dbg_cmd_func[i].cmd)
return hclge_dbg_dump_tm_nodes(hdev, buf, len); return hclge_dbg_cmd_func[i].dbg_dump(hdev, buf, len);
else if (strncmp(cmd_buf, HNAE3_DBG_TM_PRI, }
strlen(HNAE3_DBG_TM_PRI)) == 0)
return hclge_dbg_dump_tm_pri(hdev, buf, len);
else if (strncmp(cmd_buf, HNAE3_DBG_TM_QSET,
strlen(HNAE3_DBG_TM_QSET)) == 0)
return hclge_dbg_dump_tm_qset(hdev, buf, len);
dev_err(&hdev->pdev->dev, "invalid command(%d)\n", cmd);
return -EINVAL; return -EINVAL;
} }
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "hclge_cmd.h" #include "hclge_cmd.h"
#define HCLGE_DBG_BUF_LEN 256
#define HCLGE_DBG_MNG_TBL_MAX 64 #define HCLGE_DBG_MNG_TBL_MAX 64
#define HCLGE_DBG_MNG_VLAN_MASK_B BIT(0) #define HCLGE_DBG_MNG_VLAN_MASK_B BIT(0)
...@@ -83,6 +82,11 @@ struct hclge_dbg_reg_type_info { ...@@ -83,6 +82,11 @@ struct hclge_dbg_reg_type_info {
struct hclge_dbg_reg_common_msg reg_msg; struct hclge_dbg_reg_common_msg reg_msg;
}; };
struct hclge_dbg_func {
enum hnae3_dbg_cmd cmd;
int (*dbg_dump)(struct hclge_dev *hdev, char *buf, int len);
};
static const struct hclge_dbg_dfx_message hclge_dbg_bios_common_reg[] = { static const struct hclge_dbg_dfx_message hclge_dbg_bios_common_reg[] = {
{false, "Reserved"}, {false, "Reserved"},
{true, "BP_CPU_STATE"}, {true, "BP_CPU_STATE"},
...@@ -723,4 +727,13 @@ static const struct hclge_dbg_dfx_message hclge_dbg_tqp_reg[] = { ...@@ -723,4 +727,13 @@ static const struct hclge_dbg_dfx_message hclge_dbg_tqp_reg[] = {
{true, "RCB_CFG_TX_RING_EBDNUM"}, {true, "RCB_CFG_TX_RING_EBDNUM"},
}; };
#define HCLGE_DBG_INFO_LEN 256
#define HCLGE_DBG_ID_LEN 16
#define HCLGE_DBG_ITEM_NAME_LEN 32
#define HCLGE_DBG_DATA_STR_LEN 32
struct hclge_dbg_item {
char name[HCLGE_DBG_ITEM_NAME_LEN];
u16 interval; /* blank numbers after the item */
};
#endif #endif
...@@ -3936,6 +3936,21 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev) ...@@ -3936,6 +3936,21 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
return ret; return ret;
} }
static void hclge_show_rst_info(struct hclge_dev *hdev)
{
char *buf;
buf = kzalloc(HCLGE_DBG_RESET_INFO_LEN, GFP_KERNEL);
if (!buf)
return;
hclge_dbg_dump_rst_info(hdev, buf, HCLGE_DBG_RESET_INFO_LEN);
dev_info(&hdev->pdev->dev, "dump reset info:\n%s", buf);
kfree(buf);
}
static bool hclge_reset_err_handle(struct hclge_dev *hdev) static bool hclge_reset_err_handle(struct hclge_dev *hdev)
{ {
#define MAX_RESET_FAIL_CNT 5 #define MAX_RESET_FAIL_CNT 5
...@@ -3966,7 +3981,7 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev) ...@@ -3966,7 +3981,7 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev)
dev_err(&hdev->pdev->dev, "Reset fail!\n"); dev_err(&hdev->pdev->dev, "Reset fail!\n");
hclge_dbg_dump_rst_info(hdev); hclge_show_rst_info(hdev);
set_bit(HCLGE_STATE_RST_FAIL, &hdev->state); set_bit(HCLGE_STATE_RST_FAIL, &hdev->state);
...@@ -11167,6 +11182,18 @@ static void hclge_clear_resetting_state(struct hclge_dev *hdev) ...@@ -11167,6 +11182,18 @@ static void hclge_clear_resetting_state(struct hclge_dev *hdev)
} }
} }
static void hclge_init_rxd_adv_layout(struct hclge_dev *hdev)
{
if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 1);
}
static void hclge_uninit_rxd_adv_layout(struct hclge_dev *hdev)
{
if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 0);
}
static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
{ {
struct pci_dev *pdev = ae_dev->pdev; struct pci_dev *pdev = ae_dev->pdev;
...@@ -11339,6 +11366,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) ...@@ -11339,6 +11366,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL); mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL);
} }
hclge_init_rxd_adv_layout(hdev);
/* Enable MISC vector(vector0) */ /* Enable MISC vector(vector0) */
hclge_enable_vector(&hdev->misc_vector, true); hclge_enable_vector(&hdev->misc_vector, true);
...@@ -11720,6 +11749,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) ...@@ -11720,6 +11749,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
if (ret) if (ret)
return ret; return ret;
hclge_init_rxd_adv_layout(hdev);
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n", dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
HCLGE_DRIVER_NAME); HCLGE_DRIVER_NAME);
...@@ -11735,6 +11766,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) ...@@ -11735,6 +11766,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_clear_vf_vlan(hdev); hclge_clear_vf_vlan(hdev);
hclge_misc_affinity_teardown(hdev); hclge_misc_affinity_teardown(hdev);
hclge_state_uninit(hdev); hclge_state_uninit(hdev);
hclge_uninit_rxd_adv_layout(hdev);
hclge_uninit_mac_table(hdev); hclge_uninit_mac_table(hdev);
hclge_del_all_fd_entries(hdev); hclge_del_all_fd_entries(hdev);
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
/* bar registers for common func */ /* bar registers for common func */
#define HCLGE_VECTOR0_OTER_EN_REG 0x20600 #define HCLGE_VECTOR0_OTER_EN_REG 0x20600
#define HCLGE_GRO_EN_REG 0x28000 #define HCLGE_GRO_EN_REG 0x28000
#define HCLGE_RXD_ADV_LAYOUT_EN_REG 0x28008
/* bar registers for rcb */ /* bar registers for rcb */
#define HCLGE_RING_RX_ADDR_L_REG 0x80000 #define HCLGE_RING_RX_ADDR_L_REG 0x80000
...@@ -147,6 +148,8 @@ ...@@ -147,6 +148,8 @@
#define HCLGE_MAX_QSET_NUM 1024 #define HCLGE_MAX_QSET_NUM 1024
#define HCLGE_DBG_RESET_INFO_LEN 1024
enum HLCGE_PORT_TYPE { enum HLCGE_PORT_TYPE {
HOST_PORT, HOST_PORT,
NETWORK_PORT NETWORK_PORT
...@@ -1060,7 +1063,7 @@ int hclge_vport_start(struct hclge_vport *vport); ...@@ -1060,7 +1063,7 @@ int hclge_vport_start(struct hclge_vport *vport);
void hclge_vport_stop(struct hclge_vport *vport); void hclge_vport_stop(struct hclge_vport *vport);
int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu); int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu);
int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf); int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf);
int hclge_dbg_read_cmd(struct hnae3_handle *handle, const char *cmd_buf, int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len); char *buf, int len);
u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle, u16 queue_id); u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle, u16 queue_id);
int hclge_notify_client(struct hclge_dev *hdev, int hclge_notify_client(struct hclge_dev *hdev,
...@@ -1088,6 +1091,6 @@ int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, ...@@ -1088,6 +1091,6 @@ int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
void hclge_report_hw_error(struct hclge_dev *hdev, void hclge_report_hw_error(struct hclge_dev *hdev,
enum hnae3_hw_error_type type); enum hnae3_hw_error_type type);
void hclge_inform_vf_promisc_info(struct hclge_vport *vport); void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
void hclge_dbg_dump_rst_info(struct hclge_dev *hdev); int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len);
int hclge_push_vf_link_status(struct hclge_vport *vport); int hclge_push_vf_link_status(struct hclge_vport *vport);
#endif #endif
...@@ -359,6 +359,8 @@ static void hclgevf_parse_capability(struct hclgevf_dev *hdev, ...@@ -359,6 +359,8 @@ static void hclgevf_parse_capability(struct hclgevf_dev *hdev,
set_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps); set_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGEVF_CAP_UDP_TUNNEL_CSUM_B)) if (hnae3_get_bit(caps, HCLGEVF_CAP_UDP_TUNNEL_CSUM_B))
set_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, ae_dev->caps); set_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGEVF_CAP_RXD_ADV_LAYOUT_B))
set_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, ae_dev->caps);
} }
static __le32 hclgevf_build_api_caps(void) static __le32 hclgevf_build_api_caps(void)
......
...@@ -159,6 +159,7 @@ enum HCLGEVF_CAP_BITS { ...@@ -159,6 +159,7 @@ enum HCLGEVF_CAP_BITS {
HCLGEVF_CAP_HW_PAD_B, HCLGEVF_CAP_HW_PAD_B,
HCLGEVF_CAP_STASH_B, HCLGEVF_CAP_STASH_B,
HCLGEVF_CAP_UDP_TUNNEL_CSUM_B, HCLGEVF_CAP_UDP_TUNNEL_CSUM_B,
HCLGEVF_CAP_RXD_ADV_LAYOUT_B = 15,
}; };
enum HCLGEVF_API_CAP_BITS { enum HCLGEVF_API_CAP_BITS {
......
...@@ -3242,6 +3242,18 @@ static int hclgevf_clear_vport_list(struct hclgevf_dev *hdev) ...@@ -3242,6 +3242,18 @@ static int hclgevf_clear_vport_list(struct hclgevf_dev *hdev)
return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0);
} }
static void hclgevf_init_rxd_adv_layout(struct hclgevf_dev *hdev)
{
if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
hclgevf_write_dev(&hdev->hw, HCLGEVF_RXD_ADV_LAYOUT_EN_REG, 1);
}
static void hclgevf_uninit_rxd_adv_layout(struct hclgevf_dev *hdev)
{
if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
hclgevf_write_dev(&hdev->hw, HCLGEVF_RXD_ADV_LAYOUT_EN_REG, 0);
}
static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
{ {
struct pci_dev *pdev = hdev->pdev; struct pci_dev *pdev = hdev->pdev;
...@@ -3279,6 +3291,8 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) ...@@ -3279,6 +3291,8 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
set_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state); set_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state);
hclgevf_init_rxd_adv_layout(hdev);
dev_info(&hdev->pdev->dev, "Reset done\n"); dev_info(&hdev->pdev->dev, "Reset done\n");
return 0; return 0;
...@@ -3379,6 +3393,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) ...@@ -3379,6 +3393,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
goto err_config; goto err_config;
} }
hclgevf_init_rxd_adv_layout(hdev);
hdev->last_reset_time = jiffies; hdev->last_reset_time = jiffies;
dev_info(&hdev->pdev->dev, "finished initializing %s driver\n", dev_info(&hdev->pdev->dev, "finished initializing %s driver\n",
HCLGEVF_DRIVER_NAME); HCLGEVF_DRIVER_NAME);
...@@ -3405,6 +3421,7 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev) ...@@ -3405,6 +3421,7 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev)
struct hclge_vf_to_pf_msg send_msg; struct hclge_vf_to_pf_msg send_msg;
hclgevf_state_uninit(hdev); hclgevf_state_uninit(hdev);
hclgevf_uninit_rxd_adv_layout(hdev);
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_VF_UNINIT, 0); hclgevf_build_send_msg(&send_msg, HCLGE_MBX_VF_UNINIT, 0);
hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0);
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
/* bar registers for common func */ /* bar registers for common func */
#define HCLGEVF_GRO_EN_REG 0x28000 #define HCLGEVF_GRO_EN_REG 0x28000
#define HCLGEVF_RXD_ADV_LAYOUT_EN_REG 0x28008
/* bar registers for rcb */ /* bar registers for rcb */
#define HCLGEVF_RING_RX_ADDR_L_REG 0x80000 #define HCLGEVF_RING_RX_ADDR_L_REG 0x80000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment