Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Makefile for the HISILICON network device drivers.
#
ccflags-y += -I$(src)
ccflags-y += -I$(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3pf
ccflags-y += -I$(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3vf
ccflags-y += -I$(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3_common
obj-$(CONFIG_HNS3) += hnae3.o
obj-$(CONFIG_HNS3_ENET) += hns3.o
hns3-objs = hns3_enet.o hns3_ethtool.o hns3_debugfs.o
hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o
obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o hclge-common.o
hclge-common-objs += hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o
hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o hns3vf/hclgevf_regs.o
obj-$(CONFIG_HNS3_HCLGE) += hclge.o hclge-common.o
hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_regs.o \
hns3pf/hclge_mbx.o hns3pf/hclge_err.o hns3pf/hclge_debugfs.o hns3pf/hclge_ptp.o hns3pf/hclge_devlink.o \
hns3pf/hclge_fd.o
hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o
@@ -0,0 +1,256 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2017 Hisilicon Limited. */
#ifndef __HCLGE_MBX_H
#define __HCLGE_MBX_H
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/types.h>
enum HCLGE_MBX_OPCODE {
HCLGE_MBX_RESET = 0x01, /* (VF -> PF) assert reset */
HCLGE_MBX_ASSERTING_RESET, /* (PF -> VF) PF is asserting reset */
HCLGE_MBX_SET_UNICAST, /* (VF -> PF) set UC addr */
HCLGE_MBX_SET_MULTICAST, /* (VF -> PF) set MC addr */
HCLGE_MBX_SET_VLAN, /* (VF -> PF) set VLAN */
HCLGE_MBX_MAP_RING_TO_VECTOR, /* (VF -> PF) map ring-to-vector */
HCLGE_MBX_UNMAP_RING_TO_VECTOR, /* (VF -> PF) unamp ring-to-vector */
HCLGE_MBX_SET_PROMISC_MODE, /* (VF -> PF) set promiscuous mode */
HCLGE_MBX_SET_MACVLAN, /* (VF -> PF) set unicast filter */
HCLGE_MBX_API_NEGOTIATE, /* (VF -> PF) negotiate API version */
HCLGE_MBX_GET_QINFO, /* (VF -> PF) get queue config */
HCLGE_MBX_GET_QDEPTH, /* (VF -> PF) get queue depth */
HCLGE_MBX_GET_BASIC_INFO, /* (VF -> PF) get basic info */
HCLGE_MBX_GET_RETA, /* (VF -> PF) get RETA */
HCLGE_MBX_GET_RSS_KEY, /* (VF -> PF) get RSS key */
HCLGE_MBX_GET_MAC_ADDR, /* (VF -> PF) get MAC addr */
HCLGE_MBX_PF_VF_RESP, /* (PF -> VF) generate response to VF */
HCLGE_MBX_GET_BDNUM, /* (VF -> PF) get BD num */
HCLGE_MBX_GET_BUFSIZE, /* (VF -> PF) get buffer size */
HCLGE_MBX_GET_STREAMID, /* (VF -> PF) get stream id */
HCLGE_MBX_SET_AESTART, /* (VF -> PF) start ae */
HCLGE_MBX_SET_TSOSTATS, /* (VF -> PF) get tso stats */
HCLGE_MBX_LINK_STAT_CHANGE, /* (PF -> VF) link status has changed */
HCLGE_MBX_GET_BASE_CONFIG, /* (VF -> PF) get config */
HCLGE_MBX_BIND_FUNC_QUEUE, /* (VF -> PF) bind function and queue */
HCLGE_MBX_GET_LINK_STATUS, /* (VF -> PF) get link status */
HCLGE_MBX_QUEUE_RESET, /* (VF -> PF) reset queue */
HCLGE_MBX_KEEP_ALIVE, /* (VF -> PF) send keep alive cmd */
HCLGE_MBX_SET_ALIVE, /* (VF -> PF) set alive state */
HCLGE_MBX_SET_MTU, /* (VF -> PF) set mtu */
HCLGE_MBX_GET_QID_IN_PF, /* (VF -> PF) get queue id in pf */
HCLGE_MBX_LINK_STAT_MODE, /* (PF -> VF) link mode has changed */
HCLGE_MBX_GET_LINK_MODE, /* (VF -> PF) get the link mode of pf */
HCLGE_MBX_PUSH_VLAN_INFO, /* (PF -> VF) push port base vlan */
HCLGE_MBX_GET_MEDIA_TYPE, /* (VF -> PF) get media type */
HCLGE_MBX_PUSH_PROMISC_INFO, /* (PF -> VF) push vf promisc info */
HCLGE_MBX_VF_UNINIT, /* (VF -> PF) vf is unintializing */
HCLGE_MBX_HANDLE_VF_TBL, /* (VF -> PF) store/clear hw table */
HCLGE_MBX_GET_RING_VECTOR_MAP, /* (VF -> PF) get ring-to-vector map */
HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */
HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */
HCLGE_MBX_NCSI_ERROR, /* (M7 -> PF) receive a NCSI error */
};
/* below are per-VF mac-vlan subcodes */
enum hclge_mbx_mac_vlan_subcode {
HCLGE_MBX_MAC_VLAN_UC_MODIFY = 0, /* modify UC mac addr */
HCLGE_MBX_MAC_VLAN_UC_ADD, /* add a new UC mac addr */
HCLGE_MBX_MAC_VLAN_UC_REMOVE, /* remove a new UC mac addr */
HCLGE_MBX_MAC_VLAN_MC_MODIFY, /* modify MC mac addr */
HCLGE_MBX_MAC_VLAN_MC_ADD, /* add new MC mac addr */
HCLGE_MBX_MAC_VLAN_MC_REMOVE, /* remove MC mac addr */
};
/* below are per-VF vlan cfg subcodes */
enum hclge_mbx_vlan_cfg_subcode {
HCLGE_MBX_VLAN_FILTER = 0, /* set vlan filter */
HCLGE_MBX_VLAN_TX_OFF_CFG, /* set tx side vlan offload */
HCLGE_MBX_VLAN_RX_OFF_CFG, /* set rx side vlan offload */
HCLGE_MBX_PORT_BASE_VLAN_CFG, /* set port based vlan configuration */
HCLGE_MBX_GET_PORT_BASE_VLAN_STATE, /* get port based vlan state */
HCLGE_MBX_ENABLE_VLAN_FILTER,
};
enum hclge_mbx_tbl_cfg_subcode {
HCLGE_MBX_VPORT_LIST_CLEAR,
};
#define HCLGE_MBX_MAX_MSG_SIZE 14
#define HCLGE_MBX_MAX_RESP_DATA_SIZE 8U
#define HCLGE_MBX_MAX_RING_CHAIN_PARAM_NUM 4
#define HCLGE_RESET_SCHED_TIMEOUT (3 * HZ)
#define HCLGE_MBX_SCHED_TIMEOUT (HZ / 2)
struct hclge_ring_chain_param {
u8 ring_type;
u8 tqp_index;
u8 int_gl_index;
};
struct hclge_basic_info {
u8 hw_tc_map;
u8 rsv;
__le16 mbx_api_version;
__le32 pf_caps;
};
struct hclgevf_mbx_resp_status {
struct mutex mbx_mutex; /* protects against contending sync cmd resp */
u32 origin_mbx_msg;
bool received_resp;
int resp_status;
u16 match_id;
u8 additional_info[HCLGE_MBX_MAX_RESP_DATA_SIZE];
};
struct hclge_respond_to_vf_msg {
int status;
u8 data[HCLGE_MBX_MAX_RESP_DATA_SIZE];
u16 len;
};
struct hclge_vf_to_pf_msg {
u8 code;
union {
struct {
u8 subcode;
u8 data[HCLGE_MBX_MAX_MSG_SIZE];
};
struct {
u8 en_bc;
u8 en_uc;
u8 en_mc;
u8 en_limit_promisc;
};
struct {
u8 vector_id;
u8 ring_num;
struct hclge_ring_chain_param
param[HCLGE_MBX_MAX_RING_CHAIN_PARAM_NUM];
};
};
};
struct hclge_pf_to_vf_msg {
__le16 code;
union {
/* used for mbx response */
struct {
__le16 vf_mbx_msg_code;
__le16 vf_mbx_msg_subcode;
__le16 resp_status;
u8 resp_data[HCLGE_MBX_MAX_RESP_DATA_SIZE];
};
/* used for general mbx */
struct {
u8 msg_data[HCLGE_MBX_MAX_MSG_SIZE];
};
};
};
struct hclge_mbx_vf_to_pf_cmd {
u8 rsv;
u8 mbx_src_vfid; /* Auto filled by IMP */
u8 mbx_need_resp;
u8 rsv1[1];
u8 msg_len;
u8 rsv2;
__le16 match_id;
struct hclge_vf_to_pf_msg msg;
};
#define HCLGE_MBX_NEED_RESP_B 0
struct hclge_mbx_pf_to_vf_cmd {
u8 dest_vfid;
u8 rsv[3];
u8 msg_len;
u8 rsv1;
__le16 match_id;
struct hclge_pf_to_vf_msg msg;
};
struct hclge_vf_rst_cmd {
u8 dest_vfid;
u8 vf_rst;
u8 rsv[22];
};
#pragma pack(1)
struct hclge_mbx_link_status {
__le16 link_status;
__le32 speed;
__le16 duplex;
u8 flag;
};
struct hclge_mbx_link_mode {
__le16 idx;
__le64 link_mode;
};
struct hclge_mbx_port_base_vlan {
__le16 state;
__le16 vlan_proto;
__le16 qos;
__le16 vlan_tag;
};
struct hclge_mbx_vf_queue_info {
__le16 num_tqps;
__le16 rss_size;
__le16 rx_buf_len;
};
struct hclge_mbx_vf_queue_depth {
__le16 num_tx_desc;
__le16 num_rx_desc;
};
struct hclge_mbx_vlan_filter {
u8 is_kill;
__le16 vlan_id;
__le16 proto;
};
struct hclge_mbx_mtu_info {
__le32 mtu;
};
#pragma pack()
/* used by VF to store the received Async responses from PF */
struct hclgevf_mbx_arq_ring {
#define HCLGE_MBX_MAX_ARQ_MSG_SIZE 8
#define HCLGE_MBX_MAX_ARQ_MSG_NUM 1024
struct hclgevf_dev *hdev;
u32 head;
u32 tail;
atomic_t count;
__le16 msg_q[HCLGE_MBX_MAX_ARQ_MSG_NUM][HCLGE_MBX_MAX_ARQ_MSG_SIZE];
};
struct hclge_dev;
#define HCLGE_MBX_OPCODE_MAX 256
struct hclge_mbx_ops_param {
struct hclge_vport *vport;
struct hclge_mbx_vf_to_pf_cmd *req;
struct hclge_respond_to_vf_msg *resp_msg;
};
typedef int (*hclge_mbx_ops_fn)(struct hclge_mbx_ops_param *param);
#define hclge_mbx_ring_ptr_move_crq(crq) \
(crq->next_to_use = (crq->next_to_use + 1) % crq->desc_num)
#define hclge_mbx_tail_ptr_move_arq(arq) \
(arq.tail = (arq.tail + 1) % HCLGE_MBX_MAX_ARQ_MSG_NUM)
#define hclge_mbx_head_ptr_move_arq(arq) \
(arq.head = (arq.head + 1) % HCLGE_MBX_MAX_ARQ_MSG_NUM)
/* PF immediately push link status to VFs when link status changed */
#define HCLGE_MBX_PUSH_LINK_STATUS_EN BIT(0)
#endif
@@ -0,0 +1,410 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/list.h>
#include <linux/spinlock.h>
#include "hnae3.h"
static LIST_HEAD(hnae3_ae_algo_list);
static LIST_HEAD(hnae3_client_list);
static LIST_HEAD(hnae3_ae_dev_list);
void hnae3_unregister_ae_algo_prepare(struct hnae3_ae_algo *ae_algo)
{
const struct pci_device_id *pci_id;
struct hnae3_ae_dev *ae_dev;
if (!ae_algo)
return;
list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
continue;
pci_id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
if (!pci_id)
continue;
if (IS_ENABLED(CONFIG_PCI_IOV)) {
device_lock(&ae_dev->pdev->dev);
pci_disable_sriov(ae_dev->pdev);
device_unlock(&ae_dev->pdev->dev);
}
}
}
EXPORT_SYMBOL(hnae3_unregister_ae_algo_prepare);
/* we are keeping things simple and using single lock for all the
* list. This is a non-critical code so other updations, if happen
* in parallel, can wait.
*/
static DEFINE_MUTEX(hnae3_common_lock);
/* ensure the drivers being unloaded one by one */
static DEFINE_MUTEX(hnae3_unload_lock);
void hnae3_acquire_unload_lock(void)
{
mutex_lock(&hnae3_unload_lock);
}
EXPORT_SYMBOL(hnae3_acquire_unload_lock);
void hnae3_release_unload_lock(void)
{
mutex_unlock(&hnae3_unload_lock);
}
EXPORT_SYMBOL(hnae3_release_unload_lock);
static bool hnae3_client_match(enum hnae3_client_type client_type)
{
if (client_type == HNAE3_CLIENT_KNIC ||
client_type == HNAE3_CLIENT_ROCE)
return true;
return false;
}
void hnae3_set_client_init_flag(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev,
unsigned int inited)
{
if (!client || !ae_dev)
return;
switch (client->type) {
case HNAE3_CLIENT_KNIC:
hnae3_set_bit(ae_dev->flag, HNAE3_KNIC_CLIENT_INITED_B, inited);
break;
case HNAE3_CLIENT_ROCE:
hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited);
break;
default:
break;
}
}
EXPORT_SYMBOL(hnae3_set_client_init_flag);
static int hnae3_get_client_init_flag(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev)
{
int inited = 0;
switch (client->type) {
case HNAE3_CLIENT_KNIC:
inited = hnae3_get_bit(ae_dev->flag,
HNAE3_KNIC_CLIENT_INITED_B);
break;
case HNAE3_CLIENT_ROCE:
inited = hnae3_get_bit(ae_dev->flag,
HNAE3_ROCE_CLIENT_INITED_B);
break;
default:
break;
}
return inited;
}
static int hnae3_init_client_instance(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev)
{
int ret;
/* check if this client matches the type of ae_dev */
if (!(hnae3_client_match(client->type) &&
hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) {
return 0;
}
ret = ae_dev->ops->init_client_instance(client, ae_dev);
if (ret)
dev_err(&ae_dev->pdev->dev,
"fail to instantiate client, ret = %d\n", ret);
return ret;
}
static void hnae3_uninit_client_instance(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev)
{
/* check if this client matches the type of ae_dev */
if (!(hnae3_client_match(client->type) &&
hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)))
return;
if (hnae3_get_client_init_flag(client, ae_dev)) {
ae_dev->ops->uninit_client_instance(client, ae_dev);
hnae3_set_client_init_flag(client, ae_dev, 0);
}
}
int hnae3_register_client(struct hnae3_client *client)
{
struct hnae3_client *client_tmp;
struct hnae3_ae_dev *ae_dev;
if (!client)
return -ENODEV;
mutex_lock(&hnae3_common_lock);
/* one system should only have one client for every type */
list_for_each_entry(client_tmp, &hnae3_client_list, node) {
if (client_tmp->type == client->type)
goto exit;
}
list_add_tail(&client->node, &hnae3_client_list);
/* initialize the client on every matched port */
list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
/* if the client could not be initialized on current port, for
* any error reasons, move on to next available port
*/
int ret = hnae3_init_client_instance(client, ae_dev);
if (ret)
dev_err(&ae_dev->pdev->dev,
"match and instantiation failed for port, ret = %d\n",
ret);
}
exit:
mutex_unlock(&hnae3_common_lock);
return 0;
}
EXPORT_SYMBOL(hnae3_register_client);
void hnae3_unregister_client(struct hnae3_client *client)
{
struct hnae3_client *client_tmp;
struct hnae3_ae_dev *ae_dev;
bool existed = false;
if (!client)
return;
mutex_lock(&hnae3_common_lock);
/* one system should only have one client for every type */
list_for_each_entry(client_tmp, &hnae3_client_list, node) {
if (client_tmp->type == client->type) {
existed = true;
break;
}
}
if (!existed) {
mutex_unlock(&hnae3_common_lock);
pr_err("client %s does not exist!\n", client->name);
return;
}
/* un-initialize the client on every matched port */
list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
hnae3_uninit_client_instance(client, ae_dev);
}
list_del(&client->node);
mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_unregister_client);
/* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework
* @ae_algo: AE algorithm
* NOTE: the duplicated name will not be checked
*/
void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
{
const struct pci_device_id *id;
struct hnae3_ae_dev *ae_dev;
struct hnae3_client *client;
int ret;
if (!ae_algo)
return;
mutex_lock(&hnae3_common_lock);
list_add_tail(&ae_algo->node, &hnae3_ae_algo_list);
/* Check if this algo/ops matches the list of ae_devs */
list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
if (!id)
continue;
if (!ae_algo->ops) {
dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n");
continue;
}
ae_dev->ops = ae_algo->ops;
ret = ae_algo->ops->init_ae_dev(ae_dev);
if (ret) {
dev_err(&ae_dev->pdev->dev,
"init ae_dev error, ret = %d\n", ret);
continue;
}
/* ae_dev init should set flag */
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
/* check the client list for the match with this ae_dev type and
* initialize the figure out client instance
*/
list_for_each_entry(client, &hnae3_client_list, node) {
ret = hnae3_init_client_instance(client, ae_dev);
if (ret)
dev_err(&ae_dev->pdev->dev,
"match and instantiation failed, ret = %d\n",
ret);
}
}
mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_register_ae_algo);
/* hnae3_unregister_ae_algo - unregisters a AE algorithm
* @ae_algo: the AE algorithm to unregister
*/
void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
{
const struct pci_device_id *id;
struct hnae3_ae_dev *ae_dev;
struct hnae3_client *client;
if (!ae_algo)
return;
mutex_lock(&hnae3_common_lock);
/* Check if there are matched ae_dev */
list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
continue;
id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
if (!id)
continue;
/* check the client list for the match with this ae_dev type and
* un-initialize the figure out client instance
*/
list_for_each_entry(client, &hnae3_client_list, node)
hnae3_uninit_client_instance(client, ae_dev);
ae_algo->ops->uninit_ae_dev(ae_dev);
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
ae_dev->ops = NULL;
}
list_del(&ae_algo->node);
mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_unregister_ae_algo);
/* hnae3_register_ae_dev - registers a AE device to hnae3 framework
* @ae_dev: the AE device
* NOTE: the duplicated name will not be checked
*/
int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
{
const struct pci_device_id *id;
struct hnae3_ae_algo *ae_algo;
struct hnae3_client *client;
int ret;
if (!ae_dev)
return -ENODEV;
mutex_lock(&hnae3_common_lock);
list_add_tail(&ae_dev->node, &hnae3_ae_dev_list);
/* Check if there are matched ae_algo */
list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
if (!id)
continue;
if (!ae_algo->ops) {
dev_err(&ae_dev->pdev->dev, "ae_algo ops are null\n");
ret = -EOPNOTSUPP;
goto out_err;
}
ae_dev->ops = ae_algo->ops;
ret = ae_dev->ops->init_ae_dev(ae_dev);
if (ret) {
dev_err(&ae_dev->pdev->dev,
"init ae_dev error, ret = %d\n", ret);
goto out_err;
}
/* ae_dev init should set flag */
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
break;
}
/* check the client list for the match with this ae_dev type and
* initialize the figure out client instance
*/
list_for_each_entry(client, &hnae3_client_list, node) {
ret = hnae3_init_client_instance(client, ae_dev);
if (ret)
dev_err(&ae_dev->pdev->dev,
"match and instantiation failed, ret = %d\n",
ret);
}
mutex_unlock(&hnae3_common_lock);
return 0;
out_err:
list_del(&ae_dev->node);
mutex_unlock(&hnae3_common_lock);
return ret;
}
EXPORT_SYMBOL(hnae3_register_ae_dev);
/* hnae3_unregister_ae_dev - unregisters a AE device
* @ae_dev: the AE device to unregister
*/
void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
{
const struct pci_device_id *id;
struct hnae3_ae_algo *ae_algo;
struct hnae3_client *client;
if (!ae_dev)
return;
mutex_lock(&hnae3_common_lock);
/* Check if there are matched ae_algo */
list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
continue;
id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
if (!id)
continue;
list_for_each_entry(client, &hnae3_client_list, node)
hnae3_uninit_client_instance(client, ae_dev);
ae_algo->ops->uninit_ae_dev(ae_dev);
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
ae_dev->ops = NULL;
}
list_del(&ae_dev->node);
mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_unregister_ae_dev);
MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");
MODULE_VERSION(HNAE3_MOD_VERSION);
@@ -0,0 +1,982 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2016-2017 Hisilicon Limited.
#ifndef __HNAE3_H
#define __HNAE3_H
/* Names used in this framework:
* ae handle (handle):
* a set of queues provided by AE
* ring buffer queue (rbq):
* the channel between upper layer and the AE, can do tx and rx
* ring:
* a tx or rx channel within a rbq
* ring description (desc):
* an element in the ring with packet information
* buffer:
* a memory region referred by desc with the full packet payload
*
* "num" means a static number set as a parameter, "count" mean a dynamic
* number set while running
* "cb" means control block
*/
#include <linux/acpi.h>
#include <linux/dcbnl.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/pkt_sched.h>
#include <linux/types.h>
#include <linux/bitmap.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
#define HNAE3_MOD_VERSION "1.0"
#define HNAE3_MIN_VECTOR_NUM 2 /* first one for misc, another for IO */
/* Device version */
#define HNAE3_DEVICE_VERSION_V1 0x00020
#define HNAE3_DEVICE_VERSION_V2 0x00021
#define HNAE3_DEVICE_VERSION_V3 0x00030
#define HNAE3_PCI_REVISION_BIT_SIZE 8
/* Device IDs */
#define HNAE3_DEV_ID_GE 0xA220
#define HNAE3_DEV_ID_25GE 0xA221
#define HNAE3_DEV_ID_25GE_RDMA 0xA222
#define HNAE3_DEV_ID_25GE_RDMA_MACSEC 0xA223
#define HNAE3_DEV_ID_50GE_RDMA 0xA224
#define HNAE3_DEV_ID_50GE_RDMA_MACSEC 0xA225
#define HNAE3_DEV_ID_100G_RDMA_MACSEC 0xA226
#define HNAE3_DEV_ID_200G_RDMA 0xA228
#define HNAE3_DEV_ID_VF 0xA22E
#define HNAE3_DEV_ID_RDMA_DCB_PFC_VF 0xA22F
#define HNAE3_CLASS_NAME_SIZE 16
#define HNAE3_DEV_INITED_B 0x0
#define HNAE3_DEV_SUPPORT_ROCE_B 0x1
#define HNAE3_DEV_SUPPORT_DCB_B 0x2
#define HNAE3_KNIC_CLIENT_INITED_B 0x3
#define HNAE3_UNIC_CLIENT_INITED_B 0x4
#define HNAE3_ROCE_CLIENT_INITED_B 0x5
#define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) | \
BIT(HNAE3_DEV_SUPPORT_ROCE_B))
#define hnae3_dev_roce_supported(hdev) \
hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_ROCE_B)
#define hnae3_dev_dcb_supported(hdev) \
hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_DCB_B)
enum HNAE3_DEV_CAP_BITS {
HNAE3_DEV_SUPPORT_FD_B,
HNAE3_DEV_SUPPORT_GRO_B,
HNAE3_DEV_SUPPORT_FEC_B,
HNAE3_DEV_SUPPORT_UDP_GSO_B,
HNAE3_DEV_SUPPORT_QB_B,
HNAE3_DEV_SUPPORT_FD_FORWARD_TC_B,
HNAE3_DEV_SUPPORT_PTP_B,
HNAE3_DEV_SUPPORT_INT_QL_B,
HNAE3_DEV_SUPPORT_HW_TX_CSUM_B,
HNAE3_DEV_SUPPORT_TX_PUSH_B,
HNAE3_DEV_SUPPORT_PHY_IMP_B,
HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B,
HNAE3_DEV_SUPPORT_HW_PAD_B,
HNAE3_DEV_SUPPORT_STASH_B,
HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
HNAE3_DEV_SUPPORT_PAUSE_B,
HNAE3_DEV_SUPPORT_RAS_IMP_B,
HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B,
HNAE3_DEV_SUPPORT_MC_MAC_MNG_B,
HNAE3_DEV_SUPPORT_CQ_B,
HNAE3_DEV_SUPPORT_FEC_STATS_B,
HNAE3_DEV_SUPPORT_LANE_NUM_B,
HNAE3_DEV_SUPPORT_WOL_B,
HNAE3_DEV_SUPPORT_TM_FLUSH_B,
HNAE3_DEV_SUPPORT_VF_FAULT_B,
HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B,
};
#define hnae3_ae_dev_fd_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_FD_B, (ae_dev)->caps)
#define hnae3_ae_dev_gro_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_GRO_B, (ae_dev)->caps)
#define hnae3_dev_fec_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_FEC_B, (hdev)->ae_dev->caps)
#define hnae3_dev_udp_gso_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_UDP_GSO_B, (hdev)->ae_dev->caps)
#define hnae3_dev_qb_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_QB_B, (hdev)->ae_dev->caps)
#define hnae3_dev_fd_forward_tc_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_FD_FORWARD_TC_B, (hdev)->ae_dev->caps)
#define hnae3_dev_ptp_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_PTP_B, (hdev)->ae_dev->caps)
#define hnae3_dev_int_ql_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_INT_QL_B, (hdev)->ae_dev->caps)
#define hnae3_dev_hw_csum_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, (hdev)->ae_dev->caps)
#define hnae3_dev_tx_push_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_TX_PUSH_B, (hdev)->ae_dev->caps)
#define hnae3_dev_phy_imp_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, (hdev)->ae_dev->caps)
#define hnae3_dev_ras_imp_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_RAS_IMP_B, (hdev)->ae_dev->caps)
#define hnae3_dev_tqp_txrx_indep_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B, (hdev)->ae_dev->caps)
#define hnae3_dev_hw_pad_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_HW_PAD_B, (hdev)->ae_dev->caps)
#define hnae3_dev_stash_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_STASH_B, (hdev)->ae_dev->caps)
#define hnae3_dev_pause_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, (hdev)->ae_dev->caps)
#define hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev) \
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 hnae3_ae_dev_mc_mac_mng_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_MC_MAC_MNG_B, (ae_dev)->caps)
#define hnae3_ae_dev_cq_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_CQ_B, (ae_dev)->caps)
#define hnae3_ae_dev_fec_stats_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_FEC_STATS_B, (ae_dev)->caps)
#define hnae3_ae_dev_lane_num_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_LANE_NUM_B, (ae_dev)->caps)
#define hnae3_ae_dev_wol_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_WOL_B, (ae_dev)->caps)
#define hnae3_ae_dev_tm_flush_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_TM_FLUSH_B, (hdev)->ae_dev->caps)
#define hnae3_ae_dev_vf_fault_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_VF_FAULT_B, (ae_dev)->caps)
#define hnae3_ae_dev_gen_reg_dfx_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B, (hdev)->ae_dev->caps)
enum HNAE3_PF_CAP_BITS {
HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B = 0,
};
#define ring_ptr_move_fw(ring, p) \
((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
#define ring_ptr_move_bw(ring, p) \
((ring)->p = ((ring)->p - 1 + (ring)->desc_num) % (ring)->desc_num)
struct hnae3_handle;
struct hnae3_queue {
void __iomem *io_base;
void __iomem *mem_base;
struct hnae3_ae_algo *ae_algo;
struct hnae3_handle *handle;
int tqp_index; /* index in a handle */
u32 buf_size; /* size for hnae_desc->addr, preset by AE */
u16 tx_desc_num; /* total number of tx desc */
u16 rx_desc_num; /* total number of rx desc */
};
struct hns3_mac_stats {
u64 tx_pause_cnt;
u64 rx_pause_cnt;
};
/* hnae3 loop mode */
enum hnae3_loop {
HNAE3_LOOP_EXTERNAL,
HNAE3_LOOP_APP,
HNAE3_LOOP_SERIAL_SERDES,
HNAE3_LOOP_PARALLEL_SERDES,
HNAE3_LOOP_PHY,
HNAE3_LOOP_NONE,
};
enum hnae3_client_type {
HNAE3_CLIENT_KNIC,
HNAE3_CLIENT_ROCE,
};
/* mac media type */
enum hnae3_media_type {
HNAE3_MEDIA_TYPE_UNKNOWN,
HNAE3_MEDIA_TYPE_FIBER,
HNAE3_MEDIA_TYPE_COPPER,
HNAE3_MEDIA_TYPE_BACKPLANE,
HNAE3_MEDIA_TYPE_NONE,
};
/* must be consistent with definition in firmware */
enum hnae3_module_type {
HNAE3_MODULE_TYPE_UNKNOWN = 0x00,
HNAE3_MODULE_TYPE_FIBRE_LR = 0x01,
HNAE3_MODULE_TYPE_FIBRE_SR = 0x02,
HNAE3_MODULE_TYPE_AOC = 0x03,
HNAE3_MODULE_TYPE_CR = 0x04,
HNAE3_MODULE_TYPE_KR = 0x05,
HNAE3_MODULE_TYPE_TP = 0x06,
};
enum hnae3_fec_mode {
HNAE3_FEC_AUTO = 0,
HNAE3_FEC_BASER,
HNAE3_FEC_RS,
HNAE3_FEC_LLRS,
HNAE3_FEC_NONE,
HNAE3_FEC_USER_DEF,
};
enum hnae3_reset_notify_type {
HNAE3_UP_CLIENT,
HNAE3_DOWN_CLIENT,
HNAE3_INIT_CLIENT,
HNAE3_UNINIT_CLIENT,
};
enum hnae3_hw_error_type {
HNAE3_PPU_POISON_ERROR,
HNAE3_CMDQ_ECC_ERROR,
HNAE3_IMP_RD_POISON_ERROR,
HNAE3_ROCEE_AXI_RESP_ERROR,
};
enum hnae3_reset_type {
HNAE3_VF_RESET,
HNAE3_VF_FUNC_RESET,
HNAE3_VF_PF_FUNC_RESET,
HNAE3_VF_FULL_RESET,
HNAE3_FLR_RESET,
HNAE3_FUNC_RESET,
HNAE3_GLOBAL_RESET,
HNAE3_IMP_RESET,
HNAE3_NONE_RESET,
HNAE3_VF_EXP_RESET,
HNAE3_MAX_RESET,
};
enum hnae3_port_base_vlan_state {
HNAE3_PORT_BASE_VLAN_DISABLE,
HNAE3_PORT_BASE_VLAN_ENABLE,
HNAE3_PORT_BASE_VLAN_MODIFY,
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_TM_MAP,
HNAE3_DBG_CMD_TM_PG,
HNAE3_DBG_CMD_TM_PORT,
HNAE3_DBG_CMD_TC_SCH_INFO,
HNAE3_DBG_CMD_QOS_PAUSE_CFG,
HNAE3_DBG_CMD_QOS_PRI_MAP,
HNAE3_DBG_CMD_QOS_DSCP_MAP,
HNAE3_DBG_CMD_QOS_BUF_CFG,
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_PTP_INFO,
HNAE3_DBG_CMD_INTERRUPT_INFO,
HNAE3_DBG_CMD_RESET_INFO,
HNAE3_DBG_CMD_IMP_INFO,
HNAE3_DBG_CMD_NCL_CONFIG,
HNAE3_DBG_CMD_REG_BIOS_COMMON,
HNAE3_DBG_CMD_REG_SSU,
HNAE3_DBG_CMD_REG_IGU_EGU,
HNAE3_DBG_CMD_REG_RPU,
HNAE3_DBG_CMD_REG_NCSI,
HNAE3_DBG_CMD_REG_RTC,
HNAE3_DBG_CMD_REG_PPP,
HNAE3_DBG_CMD_REG_RCB,
HNAE3_DBG_CMD_REG_TQP,
HNAE3_DBG_CMD_REG_MAC,
HNAE3_DBG_CMD_REG_DCB,
HNAE3_DBG_CMD_VLAN_CONFIG,
HNAE3_DBG_CMD_QUEUE_MAP,
HNAE3_DBG_CMD_RX_QUEUE_INFO,
HNAE3_DBG_CMD_TX_QUEUE_INFO,
HNAE3_DBG_CMD_FD_TCAM,
HNAE3_DBG_CMD_FD_COUNTER,
HNAE3_DBG_CMD_FD_RULE,
HNAE3_DBG_CMD_MAC_TNL_STATUS,
HNAE3_DBG_CMD_SERV_INFO,
HNAE3_DBG_CMD_UMV_INFO,
HNAE3_DBG_CMD_PAGE_POOL_INFO,
HNAE3_DBG_CMD_COAL_INFO,
HNAE3_DBG_CMD_UNKNOWN,
};
#define hnae3_seq_file_to_ae_dev(s) (dev_get_drvdata((s)->private))
#define hnae3_seq_file_to_handle(s) \
(((struct hnae3_ae_dev *)hnae3_seq_file_to_ae_dev(s))->handle)
enum hnae3_tc_map_mode {
HNAE3_TC_MAP_MODE_PRIO,
HNAE3_TC_MAP_MODE_DSCP,
};
struct hnae3_vector_info {
u8 __iomem *io_addr;
int vector;
};
#define HNAE3_RING_TYPE_B 0
#define HNAE3_RING_TYPE_TX 0
#define HNAE3_RING_TYPE_RX 1
#define HNAE3_RING_GL_IDX_S 0
#define HNAE3_RING_GL_IDX_M GENMASK(1, 0)
#define HNAE3_RING_GL_RX 0
#define HNAE3_RING_GL_TX 1
#define HNAE3_FW_VERSION_BYTE3_SHIFT 24
#define HNAE3_FW_VERSION_BYTE3_MASK GENMASK(31, 24)
#define HNAE3_FW_VERSION_BYTE2_SHIFT 16
#define HNAE3_FW_VERSION_BYTE2_MASK GENMASK(23, 16)
#define HNAE3_FW_VERSION_BYTE1_SHIFT 8
#define HNAE3_FW_VERSION_BYTE1_MASK GENMASK(15, 8)
#define HNAE3_FW_VERSION_BYTE0_SHIFT 0
#define HNAE3_FW_VERSION_BYTE0_MASK GENMASK(7, 0)
#define HNAE3_SCC_VERSION_BYTE3_SHIFT 24
#define HNAE3_SCC_VERSION_BYTE3_MASK GENMASK(31, 24)
#define HNAE3_SCC_VERSION_BYTE2_SHIFT 16
#define HNAE3_SCC_VERSION_BYTE2_MASK GENMASK(23, 16)
#define HNAE3_SCC_VERSION_BYTE1_SHIFT 8
#define HNAE3_SCC_VERSION_BYTE1_MASK GENMASK(15, 8)
#define HNAE3_SCC_VERSION_BYTE0_SHIFT 0
#define HNAE3_SCC_VERSION_BYTE0_MASK GENMASK(7, 0)
struct hnae3_ring_chain_node {
struct hnae3_ring_chain_node *next;
u32 tqp_index;
u32 flag;
u32 int_gl_idx;
};
#define HNAE3_IS_TX_RING(node) \
(((node)->flag & 1 << HNAE3_RING_TYPE_B) == HNAE3_RING_TYPE_TX)
/* device specification info from firmware */
struct hnae3_dev_specs {
u32 mac_entry_num; /* number of mac-vlan table entry */
u32 mng_entry_num; /* number of manager table entry */
u32 max_tm_rate;
u16 rss_ind_tbl_size;
u16 rss_key_size;
u16 int_ql_max; /* max value of interrupt coalesce based on INT_QL */
u16 max_int_gl; /* max value of interrupt coalesce based on INT_GL */
u8 max_non_tso_bd_num; /* max BD number of one non-TSO packet */
u16 max_frm_size;
u16 max_qset_num;
u16 umv_size;
u16 mc_mac_size;
u32 mac_stats_num;
u8 tnl_num;
u8 hilink_version;
};
struct hnae3_client_ops {
int (*init_instance)(struct hnae3_handle *handle);
void (*uninit_instance)(struct hnae3_handle *handle, bool reset);
void (*link_status_change)(struct hnae3_handle *handle, bool state);
int (*reset_notify)(struct hnae3_handle *handle,
enum hnae3_reset_notify_type type);
void (*process_hw_error)(struct hnae3_handle *handle,
enum hnae3_hw_error_type);
};
#define HNAE3_CLIENT_NAME_LENGTH 16
struct hnae3_client {
char name[HNAE3_CLIENT_NAME_LENGTH];
unsigned long state;
enum hnae3_client_type type;
const struct hnae3_client_ops *ops;
struct list_head node;
};
#define HNAE3_DEV_CAPS_MAX_NUM 96
struct hnae3_ae_dev {
struct pci_dev *pdev;
const struct hnae3_ae_ops *ops;
struct list_head node;
u32 flag;
unsigned long hw_err_reset_req;
struct hnae3_dev_specs dev_specs;
u32 dev_version;
DECLARE_BITMAP(caps, HNAE3_DEV_CAPS_MAX_NUM);
void *priv;
struct hnae3_handle *handle;
};
typedef int (*read_func)(struct seq_file *s, void *data);
/* This struct defines the operation on the handle.
*
* init_ae_dev(): (mandatory)
* Get PF configure from pci_dev and initialize PF hardware
* uninit_ae_dev()
* Disable PF device and release PF resource
* register_client
* Register client to ae_dev
* unregister_client()
* Unregister client from ae_dev
* start()
* Enable the hardware
* stop()
* Disable the hardware
* start_client()
* Inform the hclge that client has been started
* stop_client()
* Inform the hclge that client has been stopped
* get_status()
* Get the carrier state of the back channel of the handle, 1 for ok, 0 for
* non-ok
* get_ksettings_an_result()
* Get negotiation status,speed and duplex
* get_media_type()
* Get media type of MAC
* check_port_speed()
* Check target speed whether is supported
* adjust_link()
* Adjust link status
* set_loopback()
* Set loopback
* set_promisc_mode
* Set promisc mode
* request_update_promisc_mode
* request to hclge(vf) to update promisc mode
* set_mtu()
* set mtu
* get_pauseparam()
* get tx and rx of pause frame use
* set_pauseparam()
* set tx and rx of pause frame use
* set_autoneg()
* set auto autonegotiation of pause frame use
* get_autoneg()
* get auto autonegotiation of pause frame use
* restart_autoneg()
* restart autonegotiation
* halt_autoneg()
* halt/resume autonegotiation when autonegotiation on
* get_coalesce_usecs()
* get usecs to delay a TX interrupt after a packet is sent
* get_rx_max_coalesced_frames()
* get Maximum number of packets to be sent before a TX interrupt.
* set_coalesce_usecs()
* set usecs to delay a TX interrupt after a packet is sent
* set_coalesce_frames()
* set Maximum number of packets to be sent before a TX interrupt.
* get_mac_addr()
* get mac address
* set_mac_addr()
* set mac address
* add_uc_addr
* Add unicast addr to mac table
* rm_uc_addr
* Remove unicast addr from mac table
* set_mc_addr()
* Set multicast address
* add_mc_addr
* Add multicast address to mac table
* rm_mc_addr
* Remove multicast address from mac table
* update_stats()
* Update Old network device statistics
* get_mac_stats()
* get mac pause statistics including tx_cnt and rx_cnt
* get_ethtool_stats()
* Get ethtool network device statistics
* get_strings()
* Get a set of strings that describe the requested objects
* get_sset_count()
* Get number of strings that @get_strings will write
* update_led_status()
* Update the led status
* set_led_id()
* Set led id
* get_regs()
* Get regs dump
* get_regs_len()
* Get the len of the regs dump
* get_rss_key_size()
* Get rss key size
* get_rss()
* Get rss table
* set_rss()
* Set rss table
* get_tc_size()
* Get tc size of handle
* get_vector()
* Get vector number and vector information
* put_vector()
* Put the vector in hdev
* map_ring_to_vector()
* Map rings to vector
* unmap_ring_from_vector()
* Unmap rings from vector
* reset_queue()
* Reset queue
* get_fw_version()
* Get firmware version
* get_mdix_mode()
* Get media typr of phy
* enable_vlan_filter()
* Enable vlan filter
* set_vlan_filter()
* Set vlan filter config of Ports
* set_vf_vlan_filter()
* Set vlan filter config of vf
* enable_hw_strip_rxvtag()
* Enable/disable hardware strip vlan tag of packets received
* set_gro_en
* Enable/disable HW GRO
* add_arfs_entry
* Check the 5-tuples of flow, and create flow director rule
* get_vf_config
* Get the VF configuration setting by the host
* set_vf_link_state
* Set VF link status
* set_vf_spoofchk
* Enable/disable spoof check for specified vf
* set_vf_trust
* Enable/disable trust for specified vf, if the vf being trusted, then
* it can enable promisc mode
* set_vf_rate
* Set the max tx rate of specified vf.
* set_vf_mac
* Configure the default MAC for specified VF
* get_module_eeprom
* Get the optical module eeprom info.
* add_cls_flower
* Add clsflower rule
* del_cls_flower
* Delete clsflower rule
* cls_flower_active
* Check if any cls flower rule exist
* set_tx_hwts_info
* Save information for 1588 tx packet
* get_rx_hwts
* Get 1588 rx hwstamp
* get_ts_info
* Get phc info
* clean_vf_config
* Clean residual vf info after disable sriov
* get_wol
* Get wake on lan info
* set_wol
* Config wake on lan
* dbg_get_read_func
* Return the read func for debugfs seq file
*/
struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
void (*uninit_ae_dev)(struct hnae3_ae_dev *ae_dev);
void (*reset_prepare)(struct hnae3_ae_dev *ae_dev,
enum hnae3_reset_type rst_type);
void (*reset_done)(struct hnae3_ae_dev *ae_dev);
int (*init_client_instance)(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev);
void (*uninit_client_instance)(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev);
int (*start)(struct hnae3_handle *handle);
void (*stop)(struct hnae3_handle *handle);
int (*client_start)(struct hnae3_handle *handle);
void (*client_stop)(struct hnae3_handle *handle);
int (*get_status)(struct hnae3_handle *handle);
void (*get_ksettings_an_result)(struct hnae3_handle *handle,
u8 *auto_neg, u32 *speed, u8 *duplex,
u32 *lane_num);
int (*cfg_mac_speed_dup_h)(struct hnae3_handle *handle, int speed,
u8 duplex, u8 lane_num);
void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type,
u8 *module_type);
int (*check_port_speed)(struct hnae3_handle *handle, u32 speed);
void (*get_fec_stats)(struct hnae3_handle *handle,
struct ethtool_fec_stats *fec_stats);
void (*get_fec)(struct hnae3_handle *handle, u8 *fec_ability,
u8 *fec_mode);
int (*set_fec)(struct hnae3_handle *handle, u32 fec_mode);
void (*adjust_link)(struct hnae3_handle *handle, int speed, int duplex);
int (*set_loopback)(struct hnae3_handle *handle,
enum hnae3_loop loop_mode, bool en);
int (*set_promisc_mode)(struct hnae3_handle *handle, bool en_uc_pmc,
bool en_mc_pmc);
void (*request_update_promisc_mode)(struct hnae3_handle *handle);
int (*set_mtu)(struct hnae3_handle *handle, int new_mtu);
void (*get_pauseparam)(struct hnae3_handle *handle,
u32 *auto_neg, u32 *rx_en, u32 *tx_en);
int (*set_pauseparam)(struct hnae3_handle *handle,
u32 auto_neg, u32 rx_en, u32 tx_en);
int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
int (*get_autoneg)(struct hnae3_handle *handle);
int (*restart_autoneg)(struct hnae3_handle *handle);
int (*halt_autoneg)(struct hnae3_handle *handle, bool halt);
void (*get_coalesce_usecs)(struct hnae3_handle *handle,
u32 *tx_usecs, u32 *rx_usecs);
void (*get_rx_max_coalesced_frames)(struct hnae3_handle *handle,
u32 *tx_frames, u32 *rx_frames);
int (*set_coalesce_usecs)(struct hnae3_handle *handle, u32 timeout);
int (*set_coalesce_frames)(struct hnae3_handle *handle,
u32 coalesce_frames);
void (*get_coalesce_range)(struct hnae3_handle *handle,
u32 *tx_frames_low, u32 *rx_frames_low,
u32 *tx_frames_high, u32 *rx_frames_high,
u32 *tx_usecs_low, u32 *rx_usecs_low,
u32 *tx_usecs_high, u32 *rx_usecs_high);
void (*get_mac_addr)(struct hnae3_handle *handle, u8 *p);
int (*set_mac_addr)(struct hnae3_handle *handle, const void *p,
bool is_first);
int (*do_ioctl)(struct hnae3_handle *handle,
struct ifreq *ifr, int cmd);
int (*add_uc_addr)(struct hnae3_handle *handle,
const unsigned char *addr);
int (*rm_uc_addr)(struct hnae3_handle *handle,
const unsigned char *addr);
int (*set_mc_addr)(struct hnae3_handle *handle, void *addr);
int (*add_mc_addr)(struct hnae3_handle *handle,
const unsigned char *addr);
int (*rm_mc_addr)(struct hnae3_handle *handle,
const unsigned char *addr);
void (*set_tso_stats)(struct hnae3_handle *handle, int enable);
void (*update_stats)(struct hnae3_handle *handle);
void (*get_stats)(struct hnae3_handle *handle, u64 *data);
void (*get_mac_stats)(struct hnae3_handle *handle,
struct hns3_mac_stats *mac_stats);
void (*get_strings)(struct hnae3_handle *handle,
u32 stringset, u8 **data);
int (*get_sset_count)(struct hnae3_handle *handle, int stringset);
void (*get_regs)(struct hnae3_handle *handle, u32 *version,
void *data);
int (*get_regs_len)(struct hnae3_handle *handle);
u32 (*get_rss_key_size)(struct hnae3_handle *handle);
int (*get_rss)(struct hnae3_handle *handle, u32 *indir, u8 *key,
u8 *hfunc);
int (*set_rss)(struct hnae3_handle *handle, const u32 *indir,
const u8 *key, const u8 hfunc);
int (*set_rss_tuple)(struct hnae3_handle *handle,
const struct ethtool_rxfh_fields *cmd);
int (*get_rss_tuple)(struct hnae3_handle *handle,
struct ethtool_rxfh_fields *cmd);
int (*get_tc_size)(struct hnae3_handle *handle);
int (*get_vector)(struct hnae3_handle *handle, u16 vector_num,
struct hnae3_vector_info *vector_info);
int (*put_vector)(struct hnae3_handle *handle, int vector_num);
int (*map_ring_to_vector)(struct hnae3_handle *handle,
int vector_num,
struct hnae3_ring_chain_node *vr_chain);
int (*unmap_ring_from_vector)(struct hnae3_handle *handle,
int vector_num,
struct hnae3_ring_chain_node *vr_chain);
int (*reset_queue)(struct hnae3_handle *handle);
u32 (*get_fw_version)(struct hnae3_handle *handle);
void (*get_mdix_mode)(struct hnae3_handle *handle,
u8 *tp_mdix_ctrl, u8 *tp_mdix);
int (*enable_vlan_filter)(struct hnae3_handle *handle, bool enable);
int (*set_vlan_filter)(struct hnae3_handle *handle, __be16 proto,
u16 vlan_id, bool is_kill);
int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
u16 vlan, u8 qos, __be16 proto);
int (*enable_hw_strip_rxvtag)(struct hnae3_handle *handle, bool enable);
void (*reset_event)(struct pci_dev *pdev, struct hnae3_handle *handle);
enum hnae3_reset_type (*get_reset_level)(struct hnae3_ae_dev *ae_dev,
unsigned long *addr);
void (*set_default_reset_request)(struct hnae3_ae_dev *ae_dev,
enum hnae3_reset_type rst_type);
void (*get_channels)(struct hnae3_handle *handle,
struct ethtool_channels *ch);
void (*get_tqps_and_rss_info)(struct hnae3_handle *h,
u16 *alloc_tqps, u16 *max_rss_size);
int (*set_channels)(struct hnae3_handle *handle, u32 new_tqps_num,
bool rxfh_configured);
void (*get_flowctrl_adv)(struct hnae3_handle *handle,
u32 *flowctrl_adv);
int (*set_led_id)(struct hnae3_handle *handle,
enum ethtool_phys_id_state status);
void (*get_link_mode)(struct hnae3_handle *handle,
unsigned long *supported,
unsigned long *advertising);
int (*add_fd_entry)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*del_fd_entry)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*get_fd_rule_cnt)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*get_fd_rule_info)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*get_fd_all_rules)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd, u32 *rule_locs);
void (*enable_fd)(struct hnae3_handle *handle, bool enable);
int (*add_arfs_entry)(struct hnae3_handle *handle, u16 queue_id,
u16 flow_id, struct flow_keys *fkeys);
pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev);
bool (*get_hw_reset_stat)(struct hnae3_handle *handle);
bool (*ae_dev_resetting)(struct hnae3_handle *handle);
unsigned long (*ae_dev_reset_cnt)(struct hnae3_handle *handle);
int (*set_gro_en)(struct hnae3_handle *handle, bool enable);
u16 (*get_global_queue_id)(struct hnae3_handle *handle, u16 queue_id);
void (*set_timer_task)(struct hnae3_handle *handle, bool enable);
int (*mac_connect_phy)(struct hnae3_handle *handle);
void (*mac_disconnect_phy)(struct hnae3_handle *handle);
int (*get_vf_config)(struct hnae3_handle *handle, int vf,
struct ifla_vf_info *ivf);
int (*set_vf_link_state)(struct hnae3_handle *handle, int vf,
int link_state);
int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf,
bool enable);
int (*set_vf_trust)(struct hnae3_handle *handle, int vf, bool enable);
int (*set_vf_rate)(struct hnae3_handle *handle, int vf,
int min_tx_rate, int max_tx_rate, bool force);
int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p);
int (*get_module_eeprom)(struct hnae3_handle *handle, u32 offset,
u32 len, u8 *data);
bool (*get_cmdq_stat)(struct hnae3_handle *handle);
int (*add_cls_flower)(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower);
int (*del_cls_flower)(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower);
bool (*cls_flower_active)(struct hnae3_handle *handle);
int (*get_phy_link_ksettings)(struct hnae3_handle *handle,
struct ethtool_link_ksettings *cmd);
int (*set_phy_link_ksettings)(struct hnae3_handle *handle,
const struct ethtool_link_ksettings *cmd);
bool (*set_tx_hwts_info)(struct hnae3_handle *handle,
struct sk_buff *skb);
void (*get_rx_hwts)(struct hnae3_handle *handle, struct sk_buff *skb,
u32 nsec, u32 sec);
int (*get_ts_info)(struct hnae3_handle *handle,
struct kernel_ethtool_ts_info *info);
int (*get_link_diagnosis_info)(struct hnae3_handle *handle,
u32 *status_code);
void (*clean_vf_config)(struct hnae3_ae_dev *ae_dev, int num_vfs);
int (*get_dscp_prio)(struct hnae3_handle *handle, u8 dscp,
u8 *tc_map_mode, u8 *priority);
void (*get_wol)(struct hnae3_handle *handle,
struct ethtool_wolinfo *wol);
int (*set_wol)(struct hnae3_handle *handle,
struct ethtool_wolinfo *wol);
int (*dbg_get_read_func)(struct hnae3_handle *handle,
enum hnae3_dbg_cmd cmd,
read_func *func);
int (*hwtstamp_get)(struct hnae3_handle *handle,
struct kernel_hwtstamp_config *config);
int (*hwtstamp_set)(struct hnae3_handle *handle,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
};
struct hnae3_dcb_ops {
/* IEEE 802.1Qaz std */
int (*ieee_getets)(struct hnae3_handle *, struct ieee_ets *);
int (*ieee_setets)(struct hnae3_handle *, struct ieee_ets *);
int (*ieee_getpfc)(struct hnae3_handle *, struct ieee_pfc *);
int (*ieee_setpfc)(struct hnae3_handle *, struct ieee_pfc *);
int (*ieee_setapp)(struct hnae3_handle *h, struct dcb_app *app);
int (*ieee_delapp)(struct hnae3_handle *h, struct dcb_app *app);
/* DCBX configuration */
u8 (*getdcbx)(struct hnae3_handle *);
u8 (*setdcbx)(struct hnae3_handle *, u8);
int (*setup_tc)(struct hnae3_handle *handle,
struct tc_mqprio_qopt_offload *mqprio_qopt);
};
struct hnae3_ae_algo {
const struct hnae3_ae_ops *ops;
struct list_head node;
const struct pci_device_id *pdev_id_table;
};
#define HNAE3_INT_NAME_LEN 32
#define HNAE3_ITR_COUNTDOWN_START 100
#define HNAE3_MAX_TC 8
#define HNAE3_MAX_USER_PRIO 8
struct hnae3_tc_info {
u8 prio_tc[HNAE3_MAX_USER_PRIO]; /* TC indexed by prio */
u16 tqp_count[HNAE3_MAX_TC];
u16 tqp_offset[HNAE3_MAX_TC];
u8 max_tc; /* Total number of TCs */
u8 num_tc; /* Total number of enabled TCs */
bool mqprio_active;
bool mqprio_destroy;
bool dcb_ets_active;
};
#define HNAE3_MAX_DSCP 64
#define HNAE3_PRIO_ID_INVALID 0xff
struct hnae3_knic_private_info {
struct net_device *netdev; /* Set by KNIC client when init instance */
u16 rss_size; /* Allocated RSS queues */
u16 req_rss_size;
u16 rx_buf_len;
u16 num_tx_desc;
u16 num_rx_desc;
u32 tx_spare_buf_size;
struct hnae3_tc_info tc_info;
u8 tc_map_mode;
u8 dscp_app_cnt;
u8 dscp_prio[HNAE3_MAX_DSCP];
u16 num_tqps; /* total number of TQPs in this handle */
struct hnae3_queue **tqp; /* array base of all TQPs in this instance */
const struct hnae3_dcb_ops *dcb_ops;
u16 int_rl_setting;
void __iomem *io_base;
};
struct hnae3_roce_private_info {
struct net_device *netdev;
void __iomem *roce_io_base;
void __iomem *roce_mem_base;
int base_vector;
int num_vectors;
/* The below attributes defined for RoCE client, hnae3 gives
* initial values to them, and RoCE client can modify and use
* them.
*/
unsigned long reset_state;
unsigned long instance_state;
unsigned long state;
};
#define HNAE3_SUPPORT_APP_LOOPBACK BIT(0)
#define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1)
#define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2)
#define HNAE3_SUPPORT_VF BIT(3)
#define HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK BIT(4)
#define HNAE3_SUPPORT_EXTERNAL_LOOPBACK BIT(5)
#define HNAE3_USER_UPE BIT(0) /* unicast promisc enabled by user */
#define HNAE3_USER_MPE BIT(1) /* mulitcast promisc enabled by user */
#define HNAE3_BPE BIT(2) /* broadcast promisc enable */
#define HNAE3_OVERFLOW_UPE BIT(3) /* unicast mac vlan overflow */
#define HNAE3_OVERFLOW_MPE BIT(4) /* multicast mac vlan overflow */
#define HNAE3_UPE (HNAE3_USER_UPE | HNAE3_OVERFLOW_UPE)
#define HNAE3_MPE (HNAE3_USER_MPE | HNAE3_OVERFLOW_MPE)
enum hnae3_pflag {
HNAE3_PFLAG_LIMIT_PROMISC,
HNAE3_PFLAG_MAX
};
struct hnae3_handle {
struct hnae3_client *client;
struct pci_dev *pdev;
void *priv;
struct hnae3_ae_algo *ae_algo; /* the class who provides this handle */
u64 flags; /* Indicate the capabilities for this handle */
union {
struct net_device *netdev; /* first member */
struct hnae3_knic_private_info kinfo;
struct hnae3_roce_private_info rinfo;
};
nodemask_t numa_node_mask; /* for multi-chip support */
enum hnae3_port_base_vlan_state port_base_vlan_state;
u8 netdev_flags;
struct dentry *hnae3_dbgfs;
/* Network interface message level enabled bits */
u32 msg_enable;
unsigned long supported_pflags;
unsigned long priv_flags;
};
#define hnae3_set_field(origin, mask, shift, val) \
do { \
(origin) &= (~(mask)); \
(origin) |= ((val) << (shift)) & (mask); \
} while (0)
#define hnae3_get_field(origin, mask, shift) (((origin) & (mask)) >> (shift))
#define hnae3_set_bit(origin, shift, val) \
hnae3_set_field(origin, 0x1 << (shift), shift, val)
#define hnae3_get_bit(origin, shift) \
hnae3_get_field(origin, 0x1 << (shift), shift)
#define HNAE3_FORMAT_MAC_ADDR_LEN 18
#define HNAE3_FORMAT_MAC_ADDR_OFFSET_0 0
#define HNAE3_FORMAT_MAC_ADDR_OFFSET_4 4
#define HNAE3_FORMAT_MAC_ADDR_OFFSET_5 5
static inline void hnae3_format_mac_addr(char *format_mac_addr,
const u8 *mac_addr)
{
snprintf(format_mac_addr, HNAE3_FORMAT_MAC_ADDR_LEN, "%02x:**:**:**:%02x:%02x",
mac_addr[HNAE3_FORMAT_MAC_ADDR_OFFSET_0],
mac_addr[HNAE3_FORMAT_MAC_ADDR_OFFSET_4],
mac_addr[HNAE3_FORMAT_MAC_ADDR_OFFSET_5]);
}
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_algo_prepare(struct hnae3_ae_algo *ae_algo);
void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo);
void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo);
void hnae3_unregister_client(struct hnae3_client *client);
int hnae3_register_client(struct hnae3_client *client);
void hnae3_set_client_init_flag(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev,
unsigned int inited);
void hnae3_acquire_unload_lock(void);
void hnae3_release_unload_lock(void);
#endif
@@ -0,0 +1,685 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2021-2021 Hisilicon Limited.
#include "hnae3.h"
#include "hclge_comm_cmd.h"
static void hclge_comm_cmd_config_regs(struct hclge_comm_hw *hw,
struct hclge_comm_cmq_ring *ring)
{
dma_addr_t dma = ring->desc_dma_addr;
u32 reg_val;
if (ring->ring_type == HCLGE_COMM_TYPE_CSQ) {
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG,
lower_32_bits(dma));
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG,
upper_32_bits(dma));
reg_val = hclge_comm_read_dev(hw, HCLGE_COMM_NIC_CSQ_DEPTH_REG);
reg_val &= HCLGE_COMM_NIC_SW_RST_RDY;
reg_val |= ring->desc_num >> HCLGE_COMM_NIC_CMQ_DESC_NUM_S;
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_DEPTH_REG, reg_val);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_HEAD_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_TAIL_REG, 0);
} else {
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG,
lower_32_bits(dma));
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG,
upper_32_bits(dma));
reg_val = ring->desc_num >> HCLGE_COMM_NIC_CMQ_DESC_NUM_S;
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_DEPTH_REG, reg_val);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_HEAD_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_TAIL_REG, 0);
}
}
void hclge_comm_cmd_init_regs(struct hclge_comm_hw *hw)
{
hclge_comm_cmd_config_regs(hw, &hw->cmq.csq);
hclge_comm_cmd_config_regs(hw, &hw->cmq.crq);
}
void hclge_comm_cmd_reuse_desc(struct hclge_desc *desc, bool is_read)
{
desc->flag = cpu_to_le16(HCLGE_COMM_CMD_FLAG_NO_INTR |
HCLGE_COMM_CMD_FLAG_IN);
if (is_read)
desc->flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_WR);
else
desc->flag &= cpu_to_le16(~HCLGE_COMM_CMD_FLAG_WR);
}
EXPORT_SYMBOL_GPL(hclge_comm_cmd_reuse_desc);
static void hclge_comm_set_default_capability(struct hnae3_ae_dev *ae_dev,
bool is_pf)
{
set_bit(HNAE3_DEV_SUPPORT_GRO_B, ae_dev->caps);
if (is_pf) {
set_bit(HNAE3_DEV_SUPPORT_FD_B, ae_dev->caps);
set_bit(HNAE3_DEV_SUPPORT_FEC_B, ae_dev->caps);
set_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps);
}
}
void hclge_comm_cmd_setup_basic_desc(struct hclge_desc *desc,
enum hclge_opcode_type opcode,
bool is_read)
{
memset((void *)desc, 0, sizeof(struct hclge_desc));
desc->opcode = cpu_to_le16(opcode);
desc->flag = cpu_to_le16(HCLGE_COMM_CMD_FLAG_NO_INTR |
HCLGE_COMM_CMD_FLAG_IN);
if (is_read)
desc->flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_WR);
}
EXPORT_SYMBOL_GPL(hclge_comm_cmd_setup_basic_desc);
int hclge_comm_firmware_compat_config(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw, bool en)
{
struct hclge_comm_firmware_compat_cmd *req;
struct hclge_desc desc;
u32 compat = 0;
hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_COMPAT_CFG, false);
if (en) {
req = (struct hclge_comm_firmware_compat_cmd *)desc.data;
hnae3_set_bit(compat, HCLGE_COMM_LINK_EVENT_REPORT_EN_B, 1);
hnae3_set_bit(compat, HCLGE_COMM_NCSI_ERROR_REPORT_EN_B, 1);
if (hclge_comm_dev_phy_imp_supported(ae_dev))
hnae3_set_bit(compat, HCLGE_COMM_PHY_IMP_EN_B, 1);
hnae3_set_bit(compat, HCLGE_COMM_MAC_STATS_EXT_EN_B, 1);
hnae3_set_bit(compat, HCLGE_COMM_SYNC_RX_RING_HEAD_EN_B, 1);
hnae3_set_bit(compat, HCLGE_COMM_LLRS_FEC_EN_B, 1);
req->compat = cpu_to_le32(compat);
}
return hclge_comm_cmd_send(hw, &desc, 1);
}
void hclge_comm_free_cmd_desc(struct hclge_comm_cmq_ring *ring)
{
int size = ring->desc_num * sizeof(struct hclge_desc);
if (!ring->desc)
return;
dma_free_coherent(&ring->pdev->dev, size,
ring->desc, ring->desc_dma_addr);
ring->desc = NULL;
}
static int hclge_comm_alloc_cmd_desc(struct hclge_comm_cmq_ring *ring)
{
int size = ring->desc_num * sizeof(struct hclge_desc);
ring->desc = dma_alloc_coherent(&ring->pdev->dev,
size, &ring->desc_dma_addr, GFP_KERNEL);
if (!ring->desc)
return -ENOMEM;
return 0;
}
static __le32 hclge_comm_build_api_caps(void)
{
u32 api_caps = 0;
hnae3_set_bit(api_caps, HCLGE_COMM_API_CAP_FLEX_RSS_TBL_B, 1);
return cpu_to_le32(api_caps);
}
static const struct hclge_comm_caps_bit_map hclge_pf_cmd_caps[] = {
{HCLGE_COMM_CAP_UDP_GSO_B, HNAE3_DEV_SUPPORT_UDP_GSO_B},
{HCLGE_COMM_CAP_PTP_B, HNAE3_DEV_SUPPORT_PTP_B},
{HCLGE_COMM_CAP_INT_QL_B, HNAE3_DEV_SUPPORT_INT_QL_B},
{HCLGE_COMM_CAP_TQP_TXRX_INDEP_B, HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B},
{HCLGE_COMM_CAP_HW_TX_CSUM_B, HNAE3_DEV_SUPPORT_HW_TX_CSUM_B},
{HCLGE_COMM_CAP_UDP_TUNNEL_CSUM_B, HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B},
{HCLGE_COMM_CAP_FD_FORWARD_TC_B, HNAE3_DEV_SUPPORT_FD_FORWARD_TC_B},
{HCLGE_COMM_CAP_FEC_B, HNAE3_DEV_SUPPORT_FEC_B},
{HCLGE_COMM_CAP_PAUSE_B, HNAE3_DEV_SUPPORT_PAUSE_B},
{HCLGE_COMM_CAP_PHY_IMP_B, HNAE3_DEV_SUPPORT_PHY_IMP_B},
{HCLGE_COMM_CAP_QB_B, HNAE3_DEV_SUPPORT_QB_B},
{HCLGE_COMM_CAP_TX_PUSH_B, HNAE3_DEV_SUPPORT_TX_PUSH_B},
{HCLGE_COMM_CAP_RAS_IMP_B, HNAE3_DEV_SUPPORT_RAS_IMP_B},
{HCLGE_COMM_CAP_RXD_ADV_LAYOUT_B, HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B},
{HCLGE_COMM_CAP_PORT_VLAN_BYPASS_B,
HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B},
{HCLGE_COMM_CAP_PORT_VLAN_BYPASS_B, HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B},
{HCLGE_COMM_CAP_CQ_B, HNAE3_DEV_SUPPORT_CQ_B},
{HCLGE_COMM_CAP_GRO_B, HNAE3_DEV_SUPPORT_GRO_B},
{HCLGE_COMM_CAP_FD_B, HNAE3_DEV_SUPPORT_FD_B},
{HCLGE_COMM_CAP_FEC_STATS_B, HNAE3_DEV_SUPPORT_FEC_STATS_B},
{HCLGE_COMM_CAP_LANE_NUM_B, HNAE3_DEV_SUPPORT_LANE_NUM_B},
{HCLGE_COMM_CAP_WOL_B, HNAE3_DEV_SUPPORT_WOL_B},
{HCLGE_COMM_CAP_TM_FLUSH_B, HNAE3_DEV_SUPPORT_TM_FLUSH_B},
{HCLGE_COMM_CAP_VF_FAULT_B, HNAE3_DEV_SUPPORT_VF_FAULT_B},
{HCLGE_COMM_CAP_ERR_MOD_GEN_REG_B, HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B},
};
static const struct hclge_comm_caps_bit_map hclge_vf_cmd_caps[] = {
{HCLGE_COMM_CAP_UDP_GSO_B, HNAE3_DEV_SUPPORT_UDP_GSO_B},
{HCLGE_COMM_CAP_INT_QL_B, HNAE3_DEV_SUPPORT_INT_QL_B},
{HCLGE_COMM_CAP_TQP_TXRX_INDEP_B, HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B},
{HCLGE_COMM_CAP_HW_TX_CSUM_B, HNAE3_DEV_SUPPORT_HW_TX_CSUM_B},
{HCLGE_COMM_CAP_UDP_TUNNEL_CSUM_B, HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B},
{HCLGE_COMM_CAP_QB_B, HNAE3_DEV_SUPPORT_QB_B},
{HCLGE_COMM_CAP_TX_PUSH_B, HNAE3_DEV_SUPPORT_TX_PUSH_B},
{HCLGE_COMM_CAP_RXD_ADV_LAYOUT_B, HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B},
{HCLGE_COMM_CAP_CQ_B, HNAE3_DEV_SUPPORT_CQ_B},
{HCLGE_COMM_CAP_GRO_B, HNAE3_DEV_SUPPORT_GRO_B},
};
static void
hclge_comm_capability_to_bitmap(unsigned long *bitmap, __le32 *caps)
{
const unsigned int words = HCLGE_COMM_QUERY_CAP_LENGTH;
u32 val[HCLGE_COMM_QUERY_CAP_LENGTH];
unsigned int i;
for (i = 0; i < words; i++)
val[i] = __le32_to_cpu(caps[i]);
bitmap_from_arr32(bitmap, val,
HCLGE_COMM_QUERY_CAP_LENGTH * BITS_PER_TYPE(u32));
}
static void
hclge_comm_parse_capability(struct hnae3_ae_dev *ae_dev, bool is_pf,
struct hclge_comm_query_version_cmd *cmd)
{
const struct hclge_comm_caps_bit_map *caps_map =
is_pf ? hclge_pf_cmd_caps : hclge_vf_cmd_caps;
u32 size = is_pf ? ARRAY_SIZE(hclge_pf_cmd_caps) :
ARRAY_SIZE(hclge_vf_cmd_caps);
DECLARE_BITMAP(caps, HCLGE_COMM_QUERY_CAP_LENGTH * BITS_PER_TYPE(u32));
u32 i;
hclge_comm_capability_to_bitmap(caps, cmd->caps);
for (i = 0; i < size; i++)
if (test_bit(caps_map[i].imp_bit, caps))
set_bit(caps_map[i].local_bit, ae_dev->caps);
}
int hclge_comm_alloc_cmd_queue(struct hclge_comm_hw *hw, int ring_type)
{
struct hclge_comm_cmq_ring *ring =
(ring_type == HCLGE_COMM_TYPE_CSQ) ? &hw->cmq.csq :
&hw->cmq.crq;
int ret;
ring->ring_type = ring_type;
ret = hclge_comm_alloc_cmd_desc(ring);
if (ret)
dev_err(&ring->pdev->dev, "descriptor %s alloc error %d\n",
(ring_type == HCLGE_COMM_TYPE_CSQ) ? "CSQ" : "CRQ",
ret);
return ret;
}
int hclge_comm_cmd_query_version_and_capability(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw,
u32 *fw_version, bool is_pf)
{
struct hclge_comm_query_version_cmd *resp;
struct hclge_desc desc;
int ret;
hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_FW_VER, 1);
resp = (struct hclge_comm_query_version_cmd *)desc.data;
resp->api_caps = hclge_comm_build_api_caps();
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret)
return ret;
*fw_version = le32_to_cpu(resp->firmware);
ae_dev->dev_version = le32_to_cpu(resp->hardware) <<
HNAE3_PCI_REVISION_BIT_SIZE;
ae_dev->dev_version |= ae_dev->pdev->revision;
if (ae_dev->dev_version == HNAE3_DEVICE_VERSION_V2) {
hclge_comm_set_default_capability(ae_dev, is_pf);
return 0;
}
hclge_comm_parse_capability(ae_dev, is_pf, resp);
return ret;
}
static const u16 spec_opcode[] = { HCLGE_OPC_STATS_64_BIT,
HCLGE_OPC_STATS_32_BIT,
HCLGE_OPC_STATS_MAC,
HCLGE_OPC_STATS_MAC_ALL,
HCLGE_OPC_QUERY_32_BIT_REG,
HCLGE_OPC_QUERY_64_BIT_REG,
HCLGE_QUERY_CLEAR_MPF_RAS_INT,
HCLGE_QUERY_CLEAR_PF_RAS_INT,
HCLGE_QUERY_CLEAR_ALL_MPF_MSIX_INT,
HCLGE_QUERY_CLEAR_ALL_PF_MSIX_INT,
HCLGE_QUERY_ALL_ERR_INFO };
static bool hclge_comm_is_special_opcode(u16 opcode)
{
/* these commands have several descriptors,
* and use the first one to save opcode and return value
*/
u32 i;
for (i = 0; i < ARRAY_SIZE(spec_opcode); i++)
if (spec_opcode[i] == opcode)
return true;
return false;
}
static int hclge_comm_ring_space(struct hclge_comm_cmq_ring *ring)
{
int ntc = ring->next_to_clean;
int ntu = ring->next_to_use;
int used = (ntu - ntc + ring->desc_num) % ring->desc_num;
return ring->desc_num - used - 1;
}
static void hclge_comm_cmd_copy_desc(struct hclge_comm_hw *hw,
struct hclge_desc *desc, int num)
{
struct hclge_desc *desc_to_use;
int handle = 0;
while (handle < num) {
desc_to_use = &hw->cmq.csq.desc[hw->cmq.csq.next_to_use];
*desc_to_use = desc[handle];
(hw->cmq.csq.next_to_use)++;
if (hw->cmq.csq.next_to_use >= hw->cmq.csq.desc_num)
hw->cmq.csq.next_to_use = 0;
handle++;
}
}
static int hclge_comm_is_valid_csq_clean_head(struct hclge_comm_cmq_ring *ring,
int head)
{
int ntc = ring->next_to_clean;
int ntu = ring->next_to_use;
if (ntu > ntc)
return head >= ntc && head <= ntu;
return head >= ntc || head <= ntu;
}
static int hclge_comm_cmd_csq_clean(struct hclge_comm_hw *hw)
{
struct hclge_comm_cmq_ring *csq = &hw->cmq.csq;
int clean;
u32 head;
head = hclge_comm_read_dev(hw, HCLGE_COMM_NIC_CSQ_HEAD_REG);
rmb(); /* Make sure head is ready before touch any data */
if (!hclge_comm_is_valid_csq_clean_head(csq, head)) {
dev_warn(&hw->cmq.csq.pdev->dev, "wrong cmd head (%u, %d-%d)\n",
head, csq->next_to_use, csq->next_to_clean);
dev_warn(&hw->cmq.csq.pdev->dev,
"Disabling any further commands to IMP firmware\n");
set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hw->comm_state);
dev_warn(&hw->cmq.csq.pdev->dev,
"IMP firmware watchdog reset soon expected!\n");
return -EIO;
}
clean = (head - csq->next_to_clean + csq->desc_num) % csq->desc_num;
csq->next_to_clean = head;
return clean;
}
static int hclge_comm_cmd_csq_done(struct hclge_comm_hw *hw)
{
u32 head = hclge_comm_read_dev(hw, HCLGE_COMM_NIC_CSQ_HEAD_REG);
return head == (u32)hw->cmq.csq.next_to_use;
}
static u32 hclge_get_cmdq_tx_timeout(u16 opcode, u32 tx_timeout)
{
static const struct hclge_cmdq_tx_timeout_map cmdq_tx_timeout_map[] = {
{HCLGE_OPC_CFG_RST_TRIGGER, HCLGE_COMM_CMDQ_CFG_RST_TIMEOUT},
};
u32 i;
for (i = 0; i < ARRAY_SIZE(cmdq_tx_timeout_map); i++)
if (cmdq_tx_timeout_map[i].opcode == opcode)
return cmdq_tx_timeout_map[i].tx_timeout;
return tx_timeout;
}
static void hclge_comm_wait_for_resp(struct hclge_comm_hw *hw, u16 opcode,
bool *is_completed)
{
u32 cmdq_tx_timeout = hclge_get_cmdq_tx_timeout(opcode,
hw->cmq.tx_timeout);
u32 timeout = 0;
do {
if (hclge_comm_cmd_csq_done(hw)) {
*is_completed = true;
break;
}
udelay(1);
timeout++;
} while (timeout < cmdq_tx_timeout);
}
static int hclge_comm_cmd_convert_err_code(u16 desc_ret)
{
struct hclge_comm_errcode hclge_comm_cmd_errcode[] = {
{ HCLGE_COMM_CMD_EXEC_SUCCESS, 0 },
{ HCLGE_COMM_CMD_NO_AUTH, -EPERM },
{ HCLGE_COMM_CMD_NOT_SUPPORTED, -EOPNOTSUPP },
{ HCLGE_COMM_CMD_QUEUE_FULL, -EXFULL },
{ HCLGE_COMM_CMD_NEXT_ERR, -ENOSR },
{ HCLGE_COMM_CMD_UNEXE_ERR, -ENOTBLK },
{ HCLGE_COMM_CMD_PARA_ERR, -EINVAL },
{ HCLGE_COMM_CMD_RESULT_ERR, -ERANGE },
{ HCLGE_COMM_CMD_TIMEOUT, -ETIME },
{ HCLGE_COMM_CMD_HILINK_ERR, -ENOLINK },
{ HCLGE_COMM_CMD_QUEUE_ILLEGAL, -ENXIO },
{ HCLGE_COMM_CMD_INVALID, -EBADR },
};
u32 errcode_count = ARRAY_SIZE(hclge_comm_cmd_errcode);
u32 i;
for (i = 0; i < errcode_count; i++)
if (hclge_comm_cmd_errcode[i].imp_errcode == desc_ret)
return hclge_comm_cmd_errcode[i].common_errno;
return -EIO;
}
static int hclge_comm_cmd_check_retval(struct hclge_comm_hw *hw,
struct hclge_desc *desc, int num,
int ntc)
{
u16 opcode, desc_ret;
int handle;
opcode = le16_to_cpu(desc[0].opcode);
for (handle = 0; handle < num; handle++) {
desc[handle] = hw->cmq.csq.desc[ntc];
ntc++;
if (ntc >= hw->cmq.csq.desc_num)
ntc = 0;
}
if (likely(!hclge_comm_is_special_opcode(opcode)))
desc_ret = le16_to_cpu(desc[num - 1].retval);
else
desc_ret = le16_to_cpu(desc[0].retval);
hw->cmq.last_status = desc_ret;
return hclge_comm_cmd_convert_err_code(desc_ret);
}
static int hclge_comm_cmd_check_result(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int num, int ntc)
{
bool is_completed = false;
int handle, ret;
/* If the command is sync, wait for the firmware to write back,
* if multi descriptors to be sent, use the first one to check
*/
if (HCLGE_COMM_SEND_SYNC(le16_to_cpu(desc->flag)))
hclge_comm_wait_for_resp(hw, le16_to_cpu(desc->opcode),
&is_completed);
if (!is_completed)
ret = -EBADE;
else
ret = hclge_comm_cmd_check_retval(hw, desc, num, ntc);
/* Clean the command send queue */
handle = hclge_comm_cmd_csq_clean(hw);
if (handle < 0)
ret = handle;
else if (handle != num)
dev_warn(&hw->cmq.csq.pdev->dev,
"cleaned %d, need to clean %d\n", handle, num);
return ret;
}
/**
* hclge_comm_cmd_send - send command to command queue
* @hw: pointer to the hw struct
* @desc: prefilled descriptor for describing the command
* @num : the number of descriptors to be sent
*
* This is the main send command for command queue, it
* sends the queue, cleans the queue, etc
**/
int hclge_comm_cmd_send(struct hclge_comm_hw *hw, struct hclge_desc *desc,
int num)
{
bool is_special = hclge_comm_is_special_opcode(le16_to_cpu(desc->opcode));
struct hclge_comm_cmq_ring *csq = &hw->cmq.csq;
int ret;
int ntc;
if (hw->cmq.ops.trace_cmd_send)
hw->cmq.ops.trace_cmd_send(hw, desc, num, is_special);
spin_lock_bh(&hw->cmq.csq.lock);
if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hw->comm_state)) {
spin_unlock_bh(&hw->cmq.csq.lock);
return -EBUSY;
}
if (num > hclge_comm_ring_space(&hw->cmq.csq)) {
/* If CMDQ ring is full, SW HEAD and HW HEAD may be different,
* need update the SW HEAD pointer csq->next_to_clean
*/
csq->next_to_clean =
hclge_comm_read_dev(hw, HCLGE_COMM_NIC_CSQ_HEAD_REG);
spin_unlock_bh(&hw->cmq.csq.lock);
return -EBUSY;
}
/**
* Record the location of desc in the ring for this time
* which will be use for hardware to write back
*/
ntc = hw->cmq.csq.next_to_use;
hclge_comm_cmd_copy_desc(hw, desc, num);
/* Write to hardware */
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_TAIL_REG,
hw->cmq.csq.next_to_use);
ret = hclge_comm_cmd_check_result(hw, desc, num, ntc);
spin_unlock_bh(&hw->cmq.csq.lock);
if (hw->cmq.ops.trace_cmd_get)
hw->cmq.ops.trace_cmd_get(hw, desc, num, is_special);
return ret;
}
EXPORT_SYMBOL_GPL(hclge_comm_cmd_send);
static void hclge_comm_cmd_uninit_regs(struct hclge_comm_hw *hw)
{
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_DEPTH_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_HEAD_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CSQ_TAIL_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_DEPTH_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_HEAD_REG, 0);
hclge_comm_write_dev(hw, HCLGE_COMM_NIC_CRQ_TAIL_REG, 0);
}
void hclge_comm_cmd_uninit(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw)
{
struct hclge_comm_cmq *cmdq = &hw->cmq;
hclge_comm_firmware_compat_config(ae_dev, hw, false);
set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hw->comm_state);
/* wait to ensure that the firmware completes the possible left
* over commands.
*/
msleep(HCLGE_COMM_CMDQ_CLEAR_WAIT_TIME);
spin_lock_bh(&cmdq->csq.lock);
spin_lock(&cmdq->crq.lock);
hclge_comm_cmd_uninit_regs(hw);
spin_unlock(&cmdq->crq.lock);
spin_unlock_bh(&cmdq->csq.lock);
hclge_comm_free_cmd_desc(&cmdq->csq);
hclge_comm_free_cmd_desc(&cmdq->crq);
}
EXPORT_SYMBOL_GPL(hclge_comm_cmd_uninit);
int hclge_comm_cmd_queue_init(struct pci_dev *pdev, struct hclge_comm_hw *hw)
{
struct hclge_comm_cmq *cmdq = &hw->cmq;
int ret;
/* Setup the lock for command queue */
spin_lock_init(&cmdq->csq.lock);
spin_lock_init(&cmdq->crq.lock);
cmdq->csq.pdev = pdev;
cmdq->crq.pdev = pdev;
/* Setup the queue entries for use cmd queue */
cmdq->csq.desc_num = HCLGE_COMM_NIC_CMQ_DESC_NUM;
cmdq->crq.desc_num = HCLGE_COMM_NIC_CMQ_DESC_NUM;
/* Setup Tx write back timeout */
cmdq->tx_timeout = HCLGE_COMM_CMDQ_TX_TIMEOUT_DEFAULT;
/* Setup queue rings */
ret = hclge_comm_alloc_cmd_queue(hw, HCLGE_COMM_TYPE_CSQ);
if (ret) {
dev_err(&pdev->dev, "CSQ ring setup error %d\n", ret);
return ret;
}
ret = hclge_comm_alloc_cmd_queue(hw, HCLGE_COMM_TYPE_CRQ);
if (ret) {
dev_err(&pdev->dev, "CRQ ring setup error %d\n", ret);
goto err_csq;
}
return 0;
err_csq:
hclge_comm_free_cmd_desc(&hw->cmq.csq);
return ret;
}
EXPORT_SYMBOL_GPL(hclge_comm_cmd_queue_init);
void hclge_comm_cmd_init_ops(struct hclge_comm_hw *hw,
const struct hclge_comm_cmq_ops *ops)
{
struct hclge_comm_cmq *cmdq = &hw->cmq;
if (ops) {
cmdq->ops.trace_cmd_send = ops->trace_cmd_send;
cmdq->ops.trace_cmd_get = ops->trace_cmd_get;
}
}
EXPORT_SYMBOL_GPL(hclge_comm_cmd_init_ops);
int hclge_comm_cmd_init(struct hnae3_ae_dev *ae_dev, struct hclge_comm_hw *hw,
u32 *fw_version, bool is_pf,
unsigned long reset_pending)
{
struct hclge_comm_cmq *cmdq = &hw->cmq;
int ret;
spin_lock_bh(&cmdq->csq.lock);
spin_lock(&cmdq->crq.lock);
cmdq->csq.next_to_clean = 0;
cmdq->csq.next_to_use = 0;
cmdq->crq.next_to_clean = 0;
cmdq->crq.next_to_use = 0;
hclge_comm_cmd_init_regs(hw);
spin_unlock(&cmdq->crq.lock);
spin_unlock_bh(&cmdq->csq.lock);
clear_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hw->comm_state);
/* Check if there is new reset pending, because the higher level
* reset may happen when lower level reset is being processed.
*/
if (reset_pending) {
ret = -EBUSY;
goto err_cmd_init;
}
/* get version and device capabilities */
ret = hclge_comm_cmd_query_version_and_capability(ae_dev, hw,
fw_version, is_pf);
if (ret) {
dev_err(&ae_dev->pdev->dev,
"failed to query version and capabilities, ret = %d\n",
ret);
goto err_cmd_init;
}
dev_info(&ae_dev->pdev->dev,
"The firmware version is %lu.%lu.%lu.%lu\n",
hnae3_get_field(*fw_version, HNAE3_FW_VERSION_BYTE3_MASK,
HNAE3_FW_VERSION_BYTE3_SHIFT),
hnae3_get_field(*fw_version, HNAE3_FW_VERSION_BYTE2_MASK,
HNAE3_FW_VERSION_BYTE2_SHIFT),
hnae3_get_field(*fw_version, HNAE3_FW_VERSION_BYTE1_MASK,
HNAE3_FW_VERSION_BYTE1_SHIFT),
hnae3_get_field(*fw_version, HNAE3_FW_VERSION_BYTE0_MASK,
HNAE3_FW_VERSION_BYTE0_SHIFT));
if (!is_pf && ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3)
return 0;
/* ask the firmware to enable some features, driver can work without
* it.
*/
ret = hclge_comm_firmware_compat_config(ae_dev, hw, true);
if (ret)
dev_warn(&ae_dev->pdev->dev,
"Firmware compatible features not enabled(%d).\n",
ret);
return 0;
err_cmd_init:
set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hw->comm_state);
return ret;
}
EXPORT_SYMBOL_GPL(hclge_comm_cmd_init);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("HNS3: Hisilicon Ethernet PF/VF Common Library");
MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
@@ -0,0 +1,500 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2021-2021 Hisilicon Limited.
#ifndef __HCLGE_COMM_CMD_H
#define __HCLGE_COMM_CMD_H
#include <linux/types.h>
#include "hnae3.h"
#define HCLGE_COMM_CMD_FLAG_IN BIT(0)
#define HCLGE_COMM_CMD_FLAG_NEXT BIT(2)
#define HCLGE_COMM_CMD_FLAG_WR BIT(3)
#define HCLGE_COMM_CMD_FLAG_NO_INTR BIT(4)
#define HCLGE_COMM_SEND_SYNC(flag) \
((flag) & HCLGE_COMM_CMD_FLAG_NO_INTR)
#define HCLGE_COMM_LINK_EVENT_REPORT_EN_B 0
#define HCLGE_COMM_NCSI_ERROR_REPORT_EN_B 1
#define HCLGE_COMM_PHY_IMP_EN_B 2
#define HCLGE_COMM_MAC_STATS_EXT_EN_B 3
#define HCLGE_COMM_SYNC_RX_RING_HEAD_EN_B 4
#define HCLGE_COMM_LLRS_FEC_EN_B 5
#define hclge_comm_dev_phy_imp_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, (ae_dev)->caps)
#define HCLGE_COMM_TYPE_CRQ 0
#define HCLGE_COMM_TYPE_CSQ 1
#define HCLGE_COMM_CMDQ_CLEAR_WAIT_TIME 200
/* bar registers for cmdq */
#define HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG 0x27000
#define HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG 0x27004
#define HCLGE_COMM_NIC_CSQ_DEPTH_REG 0x27008
#define HCLGE_COMM_NIC_CSQ_TAIL_REG 0x27010
#define HCLGE_COMM_NIC_CSQ_HEAD_REG 0x27014
#define HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG 0x27018
#define HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG 0x2701C
#define HCLGE_COMM_NIC_CRQ_DEPTH_REG 0x27020
#define HCLGE_COMM_NIC_CRQ_TAIL_REG 0x27024
#define HCLGE_COMM_NIC_CRQ_HEAD_REG 0x27028
/* Vector0 interrupt CMDQ event source register(RW) */
#define HCLGE_COMM_VECTOR0_CMDQ_SRC_REG 0x27100
/* Vector0 interrupt CMDQ event status register(RO) */
#define HCLGE_COMM_VECTOR0_CMDQ_STATE_REG 0x27104
#define HCLGE_COMM_CMDQ_INTR_EN_REG 0x27108
#define HCLGE_COMM_CMDQ_INTR_GEN_REG 0x2710C
#define HCLGE_COMM_CMDQ_INTR_STS_REG 0x27104
/* this bit indicates that the driver is ready for hardware reset */
#define HCLGE_COMM_NIC_SW_RST_RDY_B 16
#define HCLGE_COMM_NIC_SW_RST_RDY BIT(HCLGE_COMM_NIC_SW_RST_RDY_B)
#define HCLGE_COMM_NIC_CMQ_DESC_NUM_S 3
#define HCLGE_COMM_NIC_CMQ_DESC_NUM 1024
#define HCLGE_COMM_CMDQ_TX_TIMEOUT_DEFAULT 30000
#define HCLGE_COMM_CMDQ_CFG_RST_TIMEOUT 1000000
enum hclge_opcode_type {
/* Generic commands */
HCLGE_OPC_QUERY_FW_VER = 0x0001,
HCLGE_OPC_CFG_RST_TRIGGER = 0x0020,
HCLGE_OPC_GBL_RST_STATUS = 0x0021,
HCLGE_OPC_QUERY_FUNC_STATUS = 0x0022,
HCLGE_OPC_QUERY_PF_RSRC = 0x0023,
HCLGE_OPC_QUERY_VF_RSRC = 0x0024,
HCLGE_OPC_GET_CFG_PARAM = 0x0025,
HCLGE_OPC_PF_RST_DONE = 0x0026,
HCLGE_OPC_QUERY_VF_RST_RDY = 0x0027,
HCLGE_OPC_STATS_64_BIT = 0x0030,
HCLGE_OPC_STATS_32_BIT = 0x0031,
HCLGE_OPC_STATS_MAC = 0x0032,
HCLGE_OPC_QUERY_MAC_REG_NUM = 0x0033,
HCLGE_OPC_STATS_MAC_ALL = 0x0034,
HCLGE_OPC_QUERY_REG_NUM = 0x0040,
HCLGE_OPC_QUERY_32_BIT_REG = 0x0041,
HCLGE_OPC_QUERY_64_BIT_REG = 0x0042,
HCLGE_OPC_DFX_BD_NUM = 0x0043,
HCLGE_OPC_DFX_BIOS_COMMON_REG = 0x0044,
HCLGE_OPC_DFX_SSU_REG_0 = 0x0045,
HCLGE_OPC_DFX_SSU_REG_1 = 0x0046,
HCLGE_OPC_DFX_IGU_EGU_REG = 0x0047,
HCLGE_OPC_DFX_RPU_REG_0 = 0x0048,
HCLGE_OPC_DFX_RPU_REG_1 = 0x0049,
HCLGE_OPC_DFX_NCSI_REG = 0x004A,
HCLGE_OPC_DFX_RTC_REG = 0x004B,
HCLGE_OPC_DFX_PPP_REG = 0x004C,
HCLGE_OPC_DFX_RCB_REG = 0x004D,
HCLGE_OPC_DFX_TQP_REG = 0x004E,
HCLGE_OPC_DFX_SSU_REG_2 = 0x004F,
HCLGE_OPC_DFX_GEN_REG = 0x7038,
HCLGE_OPC_QUERY_DEV_SPECS = 0x0050,
HCLGE_OPC_GET_QUEUE_ERR_VF = 0x0067,
/* MAC command */
HCLGE_OPC_CONFIG_MAC_MODE = 0x0301,
HCLGE_OPC_CONFIG_AN_MODE = 0x0304,
HCLGE_OPC_QUERY_LINK_STATUS = 0x0307,
HCLGE_OPC_CONFIG_MAX_FRM_SIZE = 0x0308,
HCLGE_OPC_CONFIG_SPEED_DUP = 0x0309,
HCLGE_OPC_QUERY_MAC_TNL_INT = 0x0310,
HCLGE_OPC_MAC_TNL_INT_EN = 0x0311,
HCLGE_OPC_CLEAR_MAC_TNL_INT = 0x0312,
HCLGE_OPC_COMMON_LOOPBACK = 0x0315,
HCLGE_OPC_QUERY_FEC_STATS = 0x0316,
HCLGE_OPC_CONFIG_FEC_MODE = 0x031A,
HCLGE_OPC_QUERY_ROH_TYPE_INFO = 0x0389,
/* PTP commands */
HCLGE_OPC_PTP_INT_EN = 0x0501,
HCLGE_OPC_PTP_MODE_CFG = 0x0507,
/* PFC/Pause commands */
HCLGE_OPC_CFG_MAC_PAUSE_EN = 0x0701,
HCLGE_OPC_CFG_PFC_PAUSE_EN = 0x0702,
HCLGE_OPC_CFG_MAC_PARA = 0x0703,
HCLGE_OPC_CFG_PFC_PARA = 0x0704,
HCLGE_OPC_QUERY_MAC_TX_PKT_CNT = 0x0705,
HCLGE_OPC_QUERY_MAC_RX_PKT_CNT = 0x0706,
HCLGE_OPC_QUERY_PFC_TX_PKT_CNT = 0x0707,
HCLGE_OPC_QUERY_PFC_RX_PKT_CNT = 0x0708,
HCLGE_OPC_PRI_TO_TC_MAPPING = 0x0709,
HCLGE_OPC_QOS_MAP = 0x070A,
/* ETS/scheduler commands */
HCLGE_OPC_TM_PG_TO_PRI_LINK = 0x0804,
HCLGE_OPC_TM_QS_TO_PRI_LINK = 0x0805,
HCLGE_OPC_TM_NQ_TO_QS_LINK = 0x0806,
HCLGE_OPC_TM_RQ_TO_QS_LINK = 0x0807,
HCLGE_OPC_TM_PORT_WEIGHT = 0x0808,
HCLGE_OPC_TM_PG_WEIGHT = 0x0809,
HCLGE_OPC_TM_QS_WEIGHT = 0x080A,
HCLGE_OPC_TM_PRI_WEIGHT = 0x080B,
HCLGE_OPC_TM_PRI_C_SHAPPING = 0x080C,
HCLGE_OPC_TM_PRI_P_SHAPPING = 0x080D,
HCLGE_OPC_TM_PG_C_SHAPPING = 0x080E,
HCLGE_OPC_TM_PG_P_SHAPPING = 0x080F,
HCLGE_OPC_TM_PORT_SHAPPING = 0x0810,
HCLGE_OPC_TM_PG_SCH_MODE_CFG = 0x0812,
HCLGE_OPC_TM_PRI_SCH_MODE_CFG = 0x0813,
HCLGE_OPC_TM_QS_SCH_MODE_CFG = 0x0814,
HCLGE_OPC_TM_BP_TO_QSET_MAPPING = 0x0815,
HCLGE_OPC_TM_NODES = 0x0816,
HCLGE_OPC_ETS_TC_WEIGHT = 0x0843,
HCLGE_OPC_QSET_DFX_STS = 0x0844,
HCLGE_OPC_PRI_DFX_STS = 0x0845,
HCLGE_OPC_PG_DFX_STS = 0x0846,
HCLGE_OPC_PORT_DFX_STS = 0x0847,
HCLGE_OPC_SCH_NQ_CNT = 0x0848,
HCLGE_OPC_SCH_RQ_CNT = 0x0849,
HCLGE_OPC_TM_INTERNAL_STS = 0x0850,
HCLGE_OPC_TM_INTERNAL_CNT = 0x0851,
HCLGE_OPC_TM_INTERNAL_STS_1 = 0x0852,
HCLGE_OPC_TM_FLUSH = 0x0872,
/* Packet buffer allocate commands */
HCLGE_OPC_TX_BUFF_ALLOC = 0x0901,
HCLGE_OPC_RX_PRIV_BUFF_ALLOC = 0x0902,
HCLGE_OPC_RX_PRIV_WL_ALLOC = 0x0903,
HCLGE_OPC_RX_COM_THRD_ALLOC = 0x0904,
HCLGE_OPC_RX_COM_WL_ALLOC = 0x0905,
HCLGE_OPC_RX_GBL_PKT_CNT = 0x0906,
/* TQP management command */
HCLGE_OPC_SET_TQP_MAP = 0x0A01,
/* TQP commands */
HCLGE_OPC_CFG_TX_QUEUE = 0x0B01,
HCLGE_OPC_QUERY_TX_POINTER = 0x0B02,
HCLGE_OPC_QUERY_TX_STATS = 0x0B03,
HCLGE_OPC_TQP_TX_QUEUE_TC = 0x0B04,
HCLGE_OPC_CFG_RX_QUEUE = 0x0B11,
HCLGE_OPC_QUERY_RX_POINTER = 0x0B12,
HCLGE_OPC_QUERY_RX_STATS = 0x0B13,
HCLGE_OPC_STASH_RX_QUEUE_LRO = 0x0B16,
HCLGE_OPC_CFG_RX_QUEUE_LRO = 0x0B17,
HCLGE_OPC_CFG_COM_TQP_QUEUE = 0x0B20,
HCLGE_OPC_RESET_TQP_QUEUE = 0x0B22,
/* PPU commands */
HCLGE_OPC_PPU_PF_OTHER_INT_DFX = 0x0B4A,
/* TSO command */
HCLGE_OPC_TSO_GENERIC_CONFIG = 0x0C01,
HCLGE_OPC_GRO_GENERIC_CONFIG = 0x0C10,
/* RSS commands */
HCLGE_OPC_RSS_GENERIC_CONFIG = 0x0D01,
HCLGE_OPC_RSS_INDIR_TABLE = 0x0D07,
HCLGE_OPC_RSS_TC_MODE = 0x0D08,
HCLGE_OPC_RSS_INPUT_TUPLE = 0x0D02,
/* Promisuous mode command */
HCLGE_OPC_CFG_PROMISC_MODE = 0x0E01,
/* Vlan offload commands */
HCLGE_OPC_VLAN_PORT_TX_CFG = 0x0F01,
HCLGE_OPC_VLAN_PORT_RX_CFG = 0x0F02,
/* Interrupts commands */
HCLGE_OPC_ADD_RING_TO_VECTOR = 0x1503,
HCLGE_OPC_DEL_RING_TO_VECTOR = 0x1504,
/* MAC commands */
HCLGE_OPC_MAC_VLAN_ADD = 0x1000,
HCLGE_OPC_MAC_VLAN_REMOVE = 0x1001,
HCLGE_OPC_MAC_VLAN_TYPE_ID = 0x1002,
HCLGE_OPC_MAC_VLAN_INSERT = 0x1003,
HCLGE_OPC_MAC_VLAN_ALLOCATE = 0x1004,
HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010,
HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011,
/* MAC VLAN commands */
HCLGE_OPC_MAC_VLAN_SWITCH_PARAM = 0x1033,
/* VLAN commands */
HCLGE_OPC_VLAN_FILTER_CTRL = 0x1100,
HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101,
HCLGE_OPC_VLAN_FILTER_VF_CFG = 0x1102,
HCLGE_OPC_PORT_VLAN_BYPASS = 0x1103,
/* Flow Director commands */
HCLGE_OPC_FD_MODE_CTRL = 0x1200,
HCLGE_OPC_FD_GET_ALLOCATION = 0x1201,
HCLGE_OPC_FD_KEY_CONFIG = 0x1202,
HCLGE_OPC_FD_TCAM_OP = 0x1203,
HCLGE_OPC_FD_AD_OP = 0x1204,
HCLGE_OPC_FD_CNT_OP = 0x1205,
HCLGE_OPC_FD_USER_DEF_OP = 0x1207,
HCLGE_OPC_FD_QB_CTRL = 0x1210,
HCLGE_OPC_FD_QB_AD_OP = 0x1211,
/* MDIO command */
HCLGE_OPC_MDIO_CONFIG = 0x1900,
/* QCN commands */
HCLGE_OPC_QCN_MOD_CFG = 0x1A01,
HCLGE_OPC_QCN_GRP_TMPLT_CFG = 0x1A02,
HCLGE_OPC_QCN_SHAPPING_CFG = 0x1A03,
HCLGE_OPC_QCN_SHAPPING_BS_CFG = 0x1A04,
HCLGE_OPC_QCN_QSET_LINK_CFG = 0x1A05,
HCLGE_OPC_QCN_RP_STATUS_GET = 0x1A06,
HCLGE_OPC_QCN_AJUST_INIT = 0x1A07,
HCLGE_OPC_QCN_DFX_CNT_STATUS = 0x1A08,
/* SCC commands */
HCLGE_OPC_QUERY_SCC_VER = 0x1A84,
/* Mailbox command */
HCLGEVF_OPC_MBX_PF_TO_VF = 0x2000,
HCLGEVF_OPC_MBX_VF_TO_PF = 0x2001,
/* Led command */
HCLGE_OPC_LED_STATUS_CFG = 0xB000,
/* clear hardware resource command */
HCLGE_OPC_CLEAR_HW_RESOURCE = 0x700B,
/* NCL config command */
HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011,
/* IMP stats command */
HCLGE_OPC_IMP_STATS_BD = 0x7012,
HCLGE_OPC_IMP_STATS_INFO = 0x7013,
HCLGE_OPC_IMP_COMPAT_CFG = 0x701A,
/* SFP command */
HCLGE_OPC_GET_SFP_EEPROM = 0x7100,
HCLGE_OPC_GET_SFP_EXIST = 0x7101,
HCLGE_OPC_GET_SFP_INFO = 0x7104,
/* Error INT commands */
HCLGE_MAC_COMMON_INT_EN = 0x030E,
HCLGE_TM_SCH_ECC_INT_EN = 0x0829,
HCLGE_SSU_ECC_INT_CMD = 0x0989,
HCLGE_SSU_COMMON_INT_CMD = 0x098C,
HCLGE_PPU_MPF_ECC_INT_CMD = 0x0B40,
HCLGE_PPU_MPF_OTHER_INT_CMD = 0x0B41,
HCLGE_PPU_PF_OTHER_INT_CMD = 0x0B42,
HCLGE_COMMON_ECC_INT_CFG = 0x1505,
HCLGE_QUERY_RAS_INT_STS_BD_NUM = 0x1510,
HCLGE_QUERY_CLEAR_MPF_RAS_INT = 0x1511,
HCLGE_QUERY_CLEAR_PF_RAS_INT = 0x1512,
HCLGE_QUERY_MSIX_INT_STS_BD_NUM = 0x1513,
HCLGE_QUERY_CLEAR_ALL_MPF_MSIX_INT = 0x1514,
HCLGE_QUERY_CLEAR_ALL_PF_MSIX_INT = 0x1515,
HCLGE_QUERY_ALL_ERR_BD_NUM = 0x1516,
HCLGE_QUERY_ALL_ERR_INFO = 0x1517,
HCLGE_CONFIG_ROCEE_RAS_INT_EN = 0x1580,
HCLGE_QUERY_CLEAR_ROCEE_RAS_INT = 0x1581,
HCLGE_ROCEE_PF_RAS_INT_CMD = 0x1584,
HCLGE_QUERY_ROCEE_ECC_RAS_INFO_CMD = 0x1585,
HCLGE_QUERY_ROCEE_AXI_RAS_INFO_CMD = 0x1586,
HCLGE_IGU_EGU_TNL_INT_EN = 0x1803,
HCLGE_IGU_COMMON_INT_EN = 0x1806,
HCLGE_TM_QCN_MEM_INT_CFG = 0x1A14,
HCLGE_PPP_CMD0_INT_CMD = 0x2100,
HCLGE_PPP_CMD1_INT_CMD = 0x2101,
HCLGE_MAC_ETHERTYPE_IDX_RD = 0x2105,
HCLGE_OPC_WOL_GET_SUPPORTED_MODE = 0x2201,
HCLGE_OPC_WOL_CFG = 0x2202,
HCLGE_NCSI_INT_EN = 0x2401,
/* ROH MAC commands */
HCLGE_OPC_MAC_ADDR_CHECK = 0x9004,
/* PHY command */
HCLGE_OPC_PHY_LINK_KSETTING = 0x7025,
HCLGE_OPC_PHY_REG = 0x7026,
/* Query link diagnosis info command */
HCLGE_OPC_QUERY_LINK_DIAGNOSIS = 0x702A,
};
enum hclge_comm_cmd_return_status {
HCLGE_COMM_CMD_EXEC_SUCCESS = 0,
HCLGE_COMM_CMD_NO_AUTH = 1,
HCLGE_COMM_CMD_NOT_SUPPORTED = 2,
HCLGE_COMM_CMD_QUEUE_FULL = 3,
HCLGE_COMM_CMD_NEXT_ERR = 4,
HCLGE_COMM_CMD_UNEXE_ERR = 5,
HCLGE_COMM_CMD_PARA_ERR = 6,
HCLGE_COMM_CMD_RESULT_ERR = 7,
HCLGE_COMM_CMD_TIMEOUT = 8,
HCLGE_COMM_CMD_HILINK_ERR = 9,
HCLGE_COMM_CMD_QUEUE_ILLEGAL = 10,
HCLGE_COMM_CMD_INVALID = 11,
};
enum HCLGE_COMM_CAP_BITS {
HCLGE_COMM_CAP_UDP_GSO_B,
HCLGE_COMM_CAP_QB_B,
HCLGE_COMM_CAP_FD_FORWARD_TC_B,
HCLGE_COMM_CAP_PTP_B,
HCLGE_COMM_CAP_INT_QL_B,
HCLGE_COMM_CAP_HW_TX_CSUM_B,
HCLGE_COMM_CAP_TX_PUSH_B,
HCLGE_COMM_CAP_PHY_IMP_B,
HCLGE_COMM_CAP_TQP_TXRX_INDEP_B,
HCLGE_COMM_CAP_HW_PAD_B,
HCLGE_COMM_CAP_STASH_B,
HCLGE_COMM_CAP_UDP_TUNNEL_CSUM_B,
HCLGE_COMM_CAP_RAS_IMP_B = 12,
HCLGE_COMM_CAP_FEC_B = 13,
HCLGE_COMM_CAP_PAUSE_B = 14,
HCLGE_COMM_CAP_RXD_ADV_LAYOUT_B = 15,
HCLGE_COMM_CAP_PORT_VLAN_BYPASS_B = 17,
HCLGE_COMM_CAP_CQ_B = 18,
HCLGE_COMM_CAP_GRO_B = 20,
HCLGE_COMM_CAP_FD_B = 21,
HCLGE_COMM_CAP_FEC_STATS_B = 25,
HCLGE_COMM_CAP_VF_FAULT_B = 26,
HCLGE_COMM_CAP_LANE_NUM_B = 27,
HCLGE_COMM_CAP_WOL_B = 28,
HCLGE_COMM_CAP_TM_FLUSH_B = 31,
HCLGE_COMM_CAP_ERR_MOD_GEN_REG_B = 32,
};
enum HCLGE_COMM_API_CAP_BITS {
HCLGE_COMM_API_CAP_FLEX_RSS_TBL_B,
};
/* capabilities bits map between imp firmware and local driver */
struct hclge_comm_caps_bit_map {
u16 imp_bit;
u16 local_bit;
};
struct hclge_cmdq_tx_timeout_map {
u32 opcode;
u32 tx_timeout;
};
struct hclge_comm_firmware_compat_cmd {
__le32 compat;
u8 rsv[20];
};
enum hclge_comm_cmd_state {
HCLGE_COMM_STATE_CMD_DISABLE,
};
struct hclge_comm_errcode {
u32 imp_errcode;
int common_errno;
};
#define HCLGE_COMM_QUERY_CAP_LENGTH 3
struct hclge_comm_query_version_cmd {
__le32 firmware;
__le32 hardware;
__le32 api_caps;
__le32 caps[HCLGE_COMM_QUERY_CAP_LENGTH]; /* capabilities of device */
};
struct hclge_comm_query_scc_cmd {
__le32 scc_version;
u8 rsv[20];
};
#define HCLGE_DESC_DATA_LEN 6
struct hclge_desc {
__le16 opcode;
__le16 flag;
__le16 retval;
__le16 rsv;
__le32 data[HCLGE_DESC_DATA_LEN];
};
struct hclge_comm_cmq_ring {
dma_addr_t desc_dma_addr;
struct hclge_desc *desc;
struct pci_dev *pdev;
u32 head;
u32 tail;
u16 buf_size;
u16 desc_num;
int next_to_use;
int next_to_clean;
u8 ring_type; /* cmq ring type */
spinlock_t lock; /* Command queue lock */
};
enum hclge_comm_cmd_status {
HCLGE_COMM_STATUS_SUCCESS = 0,
HCLGE_COMM_ERR_CSQ_FULL = -1,
HCLGE_COMM_ERR_CSQ_TIMEOUT = -2,
HCLGE_COMM_ERR_CSQ_ERROR = -3,
};
struct hclge_comm_hw;
struct hclge_comm_cmq_ops {
void (*trace_cmd_send)(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int num, bool is_special);
void (*trace_cmd_get)(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int num, bool is_special);
};
struct hclge_comm_cmq {
struct hclge_comm_cmq_ring csq;
struct hclge_comm_cmq_ring crq;
u16 tx_timeout;
enum hclge_comm_cmd_status last_status;
struct hclge_comm_cmq_ops ops;
};
struct hclge_comm_hw {
void __iomem *io_base;
void __iomem *mem_base;
struct hclge_comm_cmq cmq;
unsigned long comm_state;
};
static inline void hclge_comm_write_reg(void __iomem *base, u32 reg, u32 value)
{
writel(value, base + reg);
}
static inline u32 hclge_comm_read_reg(u8 __iomem *base, u32 reg)
{
u8 __iomem *reg_addr = READ_ONCE(base);
return readl(reg_addr + reg);
}
#define hclge_comm_write_dev(a, reg, value) \
hclge_comm_write_reg((a)->io_base, reg, value)
#define hclge_comm_read_dev(a, reg) \
hclge_comm_read_reg((a)->io_base, reg)
void hclge_comm_cmd_init_regs(struct hclge_comm_hw *hw);
int hclge_comm_cmd_query_version_and_capability(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw,
u32 *fw_version, bool is_pf);
int hclge_comm_alloc_cmd_queue(struct hclge_comm_hw *hw, int ring_type);
int hclge_comm_cmd_send(struct hclge_comm_hw *hw, struct hclge_desc *desc,
int num);
void hclge_comm_cmd_reuse_desc(struct hclge_desc *desc, bool is_read);
int hclge_comm_firmware_compat_config(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw, bool en);
void hclge_comm_free_cmd_desc(struct hclge_comm_cmq_ring *ring);
void hclge_comm_cmd_setup_basic_desc(struct hclge_desc *desc,
enum hclge_opcode_type opcode,
bool is_read);
void hclge_comm_cmd_uninit(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw);
int hclge_comm_cmd_queue_init(struct pci_dev *pdev, struct hclge_comm_hw *hw);
int hclge_comm_cmd_init(struct hnae3_ae_dev *ae_dev, struct hclge_comm_hw *hw,
u32 *fw_version, bool is_pf,
unsigned long reset_pending);
void hclge_comm_cmd_init_ops(struct hclge_comm_hw *hw,
const struct hclge_comm_cmq_ops *ops);
#endif
@@ -0,0 +1,518 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2021-2021 Hisilicon Limited.
#include <linux/skbuff.h>
#include "hnae3.h"
#include "hclge_comm_cmd.h"
#include "hclge_comm_rss.h"
static const u8 hclge_comm_hash_key[] = {
0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA
};
static void
hclge_comm_init_rss_tuple(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_tuple_cfg *rss_tuple_cfg)
{
rss_tuple_cfg->ipv4_tcp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
rss_tuple_cfg->ipv4_udp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
rss_tuple_cfg->ipv4_sctp_en = HCLGE_COMM_RSS_INPUT_TUPLE_SCTP;
rss_tuple_cfg->ipv4_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
rss_tuple_cfg->ipv6_tcp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
rss_tuple_cfg->ipv6_udp_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
rss_tuple_cfg->ipv6_sctp_en =
ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2 ?
HCLGE_COMM_RSS_INPUT_TUPLE_SCTP_NO_PORT :
HCLGE_COMM_RSS_INPUT_TUPLE_SCTP;
rss_tuple_cfg->ipv6_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
}
int hclge_comm_rss_init_cfg(struct hnae3_handle *nic,
struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_cfg *rss_cfg)
{
u16 rss_ind_tbl_size = ae_dev->dev_specs.rss_ind_tbl_size;
int rss_algo = HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ;
u16 *rss_ind_tbl;
if (nic->flags & HNAE3_SUPPORT_VF)
rss_cfg->rss_size = nic->kinfo.rss_size;
if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2)
rss_algo = HCLGE_COMM_RSS_HASH_ALGO_SIMPLE;
hclge_comm_init_rss_tuple(ae_dev, &rss_cfg->rss_tuple_sets);
rss_cfg->rss_algo = rss_algo;
rss_ind_tbl = devm_kcalloc(&ae_dev->pdev->dev, rss_ind_tbl_size,
sizeof(*rss_ind_tbl), GFP_KERNEL);
if (!rss_ind_tbl)
return -ENOMEM;
rss_cfg->rss_indirection_tbl = rss_ind_tbl;
memcpy(rss_cfg->rss_hash_key, hclge_comm_hash_key,
HCLGE_COMM_RSS_KEY_SIZE);
hclge_comm_rss_indir_init_cfg(ae_dev, rss_cfg);
return 0;
}
EXPORT_SYMBOL_GPL(hclge_comm_rss_init_cfg);
void hclge_comm_get_rss_tc_info(u16 rss_size, u8 hw_tc_map, u16 *tc_offset,
u16 *tc_valid, u16 *tc_size)
{
u16 roundup_size;
u32 i;
roundup_size = roundup_pow_of_two(rss_size);
roundup_size = ilog2(roundup_size);
for (i = 0; i < HCLGE_COMM_MAX_TC_NUM; i++) {
tc_valid[i] = 1;
tc_size[i] = roundup_size;
tc_offset[i] = (hw_tc_map & BIT(i)) ? rss_size * i : 0;
}
}
EXPORT_SYMBOL_GPL(hclge_comm_get_rss_tc_info);
int hclge_comm_set_rss_tc_mode(struct hclge_comm_hw *hw, u16 *tc_offset,
u16 *tc_valid, u16 *tc_size)
{
struct hclge_comm_rss_tc_mode_cmd *req;
struct hclge_desc desc;
unsigned int i;
int ret;
req = (struct hclge_comm_rss_tc_mode_cmd *)desc.data;
hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_TC_MODE, false);
for (i = 0; i < HCLGE_COMM_MAX_TC_NUM; i++) {
u16 mode = 0;
hnae3_set_bit(mode, HCLGE_COMM_RSS_TC_VALID_B,
(tc_valid[i] & 0x1));
hnae3_set_field(mode, HCLGE_COMM_RSS_TC_SIZE_M,
HCLGE_COMM_RSS_TC_SIZE_S, tc_size[i]);
hnae3_set_bit(mode, HCLGE_COMM_RSS_TC_SIZE_MSB_B,
tc_size[i] >> HCLGE_COMM_RSS_TC_SIZE_MSB_OFFSET &
0x1);
hnae3_set_field(mode, HCLGE_COMM_RSS_TC_OFFSET_M,
HCLGE_COMM_RSS_TC_OFFSET_S, tc_offset[i]);
req->rss_tc_mode[i] = cpu_to_le16(mode);
}
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret)
dev_err(&hw->cmq.csq.pdev->dev,
"failed to set rss tc mode, ret = %d.\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(hclge_comm_set_rss_tc_mode);
int hclge_comm_set_rss_hash_key(struct hclge_comm_rss_cfg *rss_cfg,
struct hclge_comm_hw *hw, const u8 *key,
const u8 hfunc)
{
u8 hash_algo;
int ret;
ret = hclge_comm_parse_rss_hfunc(rss_cfg, hfunc, &hash_algo);
if (ret)
return ret;
/* Set the RSS Hash Key if specififed by the user */
if (key) {
ret = hclge_comm_set_rss_algo_key(hw, hash_algo, key);
if (ret)
return ret;
/* Update the shadow RSS key with user specified qids */
memcpy(rss_cfg->rss_hash_key, key, HCLGE_COMM_RSS_KEY_SIZE);
} else {
ret = hclge_comm_set_rss_algo_key(hw, hash_algo,
rss_cfg->rss_hash_key);
if (ret)
return ret;
}
rss_cfg->rss_algo = hash_algo;
return 0;
}
EXPORT_SYMBOL_GPL(hclge_comm_set_rss_hash_key);
int hclge_comm_set_rss_tuple(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw,
struct hclge_comm_rss_cfg *rss_cfg,
const struct ethtool_rxfh_fields *nfc)
{
struct hclge_comm_rss_input_tuple_cmd *req;
struct hclge_desc desc;
int ret;
if (nfc->data &
~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3))
return -EINVAL;
req = (struct hclge_comm_rss_input_tuple_cmd *)desc.data;
hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_INPUT_TUPLE,
false);
ret = hclge_comm_init_rss_tuple_cmd(rss_cfg, nfc, ae_dev, req);
if (ret) {
dev_err(&hw->cmq.csq.pdev->dev,
"failed to init rss tuple cmd, ret = %d.\n", ret);
return ret;
}
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret) {
dev_err(&hw->cmq.csq.pdev->dev,
"failed to set rss tuple, ret = %d.\n", ret);
return ret;
}
rss_cfg->rss_tuple_sets.ipv4_tcp_en = req->ipv4_tcp_en;
rss_cfg->rss_tuple_sets.ipv4_udp_en = req->ipv4_udp_en;
rss_cfg->rss_tuple_sets.ipv4_sctp_en = req->ipv4_sctp_en;
rss_cfg->rss_tuple_sets.ipv4_fragment_en = req->ipv4_fragment_en;
rss_cfg->rss_tuple_sets.ipv6_tcp_en = req->ipv6_tcp_en;
rss_cfg->rss_tuple_sets.ipv6_udp_en = req->ipv6_udp_en;
rss_cfg->rss_tuple_sets.ipv6_sctp_en = req->ipv6_sctp_en;
rss_cfg->rss_tuple_sets.ipv6_fragment_en = req->ipv6_fragment_en;
return 0;
}
EXPORT_SYMBOL_GPL(hclge_comm_set_rss_tuple);
u32 hclge_comm_get_rss_key_size(struct hnae3_handle *handle)
{
return HCLGE_COMM_RSS_KEY_SIZE;
}
EXPORT_SYMBOL_GPL(hclge_comm_get_rss_key_size);
int hclge_comm_parse_rss_hfunc(struct hclge_comm_rss_cfg *rss_cfg,
const u8 hfunc, u8 *hash_algo)
{
switch (hfunc) {
case ETH_RSS_HASH_TOP:
*hash_algo = HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ;
return 0;
case ETH_RSS_HASH_XOR:
*hash_algo = HCLGE_COMM_RSS_HASH_ALGO_SIMPLE;
return 0;
case ETH_RSS_HASH_NO_CHANGE:
*hash_algo = rss_cfg->rss_algo;
return 0;
default:
return -EINVAL;
}
}
void hclge_comm_rss_indir_init_cfg(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_cfg *rss_cfg)
{
u16 i;
/* Initialize RSS indirect table */
for (i = 0; i < ae_dev->dev_specs.rss_ind_tbl_size; i++)
rss_cfg->rss_indirection_tbl[i] = i % rss_cfg->rss_size;
}
EXPORT_SYMBOL_GPL(hclge_comm_rss_indir_init_cfg);
int hclge_comm_get_rss_tuple(struct hclge_comm_rss_cfg *rss_cfg, int flow_type,
u8 *tuple_sets)
{
switch (flow_type) {
case TCP_V4_FLOW:
*tuple_sets = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
break;
case UDP_V4_FLOW:
*tuple_sets = rss_cfg->rss_tuple_sets.ipv4_udp_en;
break;
case TCP_V6_FLOW:
*tuple_sets = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
break;
case UDP_V6_FLOW:
*tuple_sets = rss_cfg->rss_tuple_sets.ipv6_udp_en;
break;
case SCTP_V4_FLOW:
*tuple_sets = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
break;
case SCTP_V6_FLOW:
*tuple_sets = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
break;
case IPV4_FLOW:
case IPV6_FLOW:
*tuple_sets = HCLGE_COMM_S_IP_BIT | HCLGE_COMM_D_IP_BIT;
break;
default:
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(hclge_comm_get_rss_tuple);
static void
hclge_comm_append_rss_msb_info(struct hclge_comm_rss_ind_tbl_cmd *req,
u16 qid, u32 j)
{
u8 rss_msb_oft;
u8 rss_msb_val;
rss_msb_oft =
j * HCLGE_COMM_RSS_CFG_TBL_BW_H / BITS_PER_BYTE;
rss_msb_val = (qid >> HCLGE_COMM_RSS_CFG_TBL_BW_L & 0x1) <<
(j * HCLGE_COMM_RSS_CFG_TBL_BW_H % BITS_PER_BYTE);
req->rss_qid_h[rss_msb_oft] |= rss_msb_val;
}
int hclge_comm_set_rss_indir_table(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw, const u16 *indir)
{
struct hclge_comm_rss_ind_tbl_cmd *req;
struct hclge_desc desc;
u16 rss_cfg_tbl_num;
int ret;
u16 qid;
u16 i;
u32 j;
req = (struct hclge_comm_rss_ind_tbl_cmd *)desc.data;
rss_cfg_tbl_num = ae_dev->dev_specs.rss_ind_tbl_size /
HCLGE_COMM_RSS_CFG_TBL_SIZE;
for (i = 0; i < rss_cfg_tbl_num; i++) {
hclge_comm_cmd_setup_basic_desc(&desc,
HCLGE_OPC_RSS_INDIR_TABLE,
false);
req->start_table_index =
cpu_to_le16(i * HCLGE_COMM_RSS_CFG_TBL_SIZE);
req->rss_set_bitmap =
cpu_to_le16(HCLGE_COMM_RSS_SET_BITMAP_MSK);
for (j = 0; j < HCLGE_COMM_RSS_CFG_TBL_SIZE; j++) {
qid = indir[i * HCLGE_COMM_RSS_CFG_TBL_SIZE + j];
req->rss_qid_l[j] = qid & 0xff;
hclge_comm_append_rss_msb_info(req, qid, j);
}
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret) {
dev_err(&hw->cmq.csq.pdev->dev,
"failed to configure rss table, ret = %d.\n",
ret);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(hclge_comm_set_rss_indir_table);
int hclge_comm_set_rss_input_tuple(struct hclge_comm_hw *hw,
struct hclge_comm_rss_cfg *rss_cfg)
{
struct hclge_comm_rss_input_tuple_cmd *req;
struct hclge_desc desc;
int ret;
hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_INPUT_TUPLE,
false);
req = (struct hclge_comm_rss_input_tuple_cmd *)desc.data;
req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en;
req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en;
req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en;
req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en;
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret)
dev_err(&hw->cmq.csq.pdev->dev,
"failed to configure rss input, ret = %d.\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(hclge_comm_set_rss_input_tuple);
void hclge_comm_get_rss_hash_info(struct hclge_comm_rss_cfg *rss_cfg, u8 *key,
u8 *hfunc)
{
/* Get hash algorithm */
if (hfunc) {
switch (rss_cfg->rss_algo) {
case HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ:
*hfunc = ETH_RSS_HASH_TOP;
break;
case HCLGE_COMM_RSS_HASH_ALGO_SIMPLE:
*hfunc = ETH_RSS_HASH_XOR;
break;
default:
*hfunc = ETH_RSS_HASH_UNKNOWN;
break;
}
}
/* Get the RSS Key required by the user */
if (key)
memcpy(key, rss_cfg->rss_hash_key, HCLGE_COMM_RSS_KEY_SIZE);
}
EXPORT_SYMBOL_GPL(hclge_comm_get_rss_hash_info);
void hclge_comm_get_rss_indir_tbl(struct hclge_comm_rss_cfg *rss_cfg,
u32 *indir, u16 rss_ind_tbl_size)
{
u16 i;
if (!indir)
return;
for (i = 0; i < rss_ind_tbl_size; i++)
indir[i] = rss_cfg->rss_indirection_tbl[i];
}
EXPORT_SYMBOL_GPL(hclge_comm_get_rss_indir_tbl);
int hclge_comm_set_rss_algo_key(struct hclge_comm_hw *hw, const u8 hfunc,
const u8 *key)
{
struct hclge_comm_rss_config_cmd *req;
unsigned int key_offset = 0;
struct hclge_desc desc;
int key_counts;
int key_size;
int ret;
key_counts = HCLGE_COMM_RSS_KEY_SIZE;
req = (struct hclge_comm_rss_config_cmd *)desc.data;
while (key_counts) {
hclge_comm_cmd_setup_basic_desc(&desc,
HCLGE_OPC_RSS_GENERIC_CONFIG,
false);
req->hash_config |= (hfunc & HCLGE_COMM_RSS_HASH_ALGO_MASK);
req->hash_config |=
(key_offset << HCLGE_COMM_RSS_HASH_KEY_OFFSET_B);
key_size = min(HCLGE_COMM_RSS_HASH_KEY_NUM, key_counts);
memcpy(req->hash_key,
key + key_offset * HCLGE_COMM_RSS_HASH_KEY_NUM,
key_size);
key_counts -= key_size;
key_offset++;
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret) {
dev_err(&hw->cmq.csq.pdev->dev,
"failed to configure RSS key, ret = %d.\n",
ret);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(hclge_comm_set_rss_algo_key);
static u8 hclge_comm_get_rss_hash_bits(const struct ethtool_rxfh_fields *nfc)
{
u8 hash_sets = nfc->data & RXH_L4_B_0_1 ? HCLGE_COMM_S_PORT_BIT : 0;
if (nfc->data & RXH_L4_B_2_3)
hash_sets |= HCLGE_COMM_D_PORT_BIT;
else
hash_sets &= ~HCLGE_COMM_D_PORT_BIT;
if (nfc->data & RXH_IP_SRC)
hash_sets |= HCLGE_COMM_S_IP_BIT;
else
hash_sets &= ~HCLGE_COMM_S_IP_BIT;
if (nfc->data & RXH_IP_DST)
hash_sets |= HCLGE_COMM_D_IP_BIT;
else
hash_sets &= ~HCLGE_COMM_D_IP_BIT;
if (nfc->flow_type == SCTP_V4_FLOW || nfc->flow_type == SCTP_V6_FLOW)
hash_sets |= HCLGE_COMM_V_TAG_BIT;
return hash_sets;
}
int hclge_comm_init_rss_tuple_cmd(struct hclge_comm_rss_cfg *rss_cfg,
const struct ethtool_rxfh_fields *nfc,
struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_input_tuple_cmd *req)
{
u8 tuple_sets;
req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en;
req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en;
req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en;
req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en;
tuple_sets = hclge_comm_get_rss_hash_bits(nfc);
switch (nfc->flow_type) {
case TCP_V4_FLOW:
req->ipv4_tcp_en = tuple_sets;
break;
case TCP_V6_FLOW:
req->ipv6_tcp_en = tuple_sets;
break;
case UDP_V4_FLOW:
req->ipv4_udp_en = tuple_sets;
break;
case UDP_V6_FLOW:
req->ipv6_udp_en = tuple_sets;
break;
case SCTP_V4_FLOW:
req->ipv4_sctp_en = tuple_sets;
break;
case SCTP_V6_FLOW:
if (ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2 &&
(nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)))
return -EINVAL;
req->ipv6_sctp_en = tuple_sets;
break;
case IPV4_FLOW:
req->ipv4_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
break;
case IPV6_FLOW:
req->ipv6_fragment_en = HCLGE_COMM_RSS_INPUT_TUPLE_OTHER;
break;
default:
return -EINVAL;
}
return 0;
}
u64 hclge_comm_convert_rss_tuple(u8 tuple_sets)
{
u64 tuple_data = 0;
if (tuple_sets & HCLGE_COMM_D_PORT_BIT)
tuple_data |= RXH_L4_B_2_3;
if (tuple_sets & HCLGE_COMM_S_PORT_BIT)
tuple_data |= RXH_L4_B_0_1;
if (tuple_sets & HCLGE_COMM_D_IP_BIT)
tuple_data |= RXH_IP_DST;
if (tuple_sets & HCLGE_COMM_S_IP_BIT)
tuple_data |= RXH_IP_SRC;
return tuple_data;
}
EXPORT_SYMBOL_GPL(hclge_comm_convert_rss_tuple);
@@ -0,0 +1,133 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2021-2021 Hisilicon Limited.
#ifndef __HCLGE_COMM_RSS_H
#define __HCLGE_COMM_RSS_H
#include <linux/types.h>
#include "hnae3.h"
#include "hclge_comm_cmd.h"
#define HCLGE_COMM_RSS_HASH_ALGO_TOEPLITZ 0
#define HCLGE_COMM_RSS_HASH_ALGO_SIMPLE 1
#define HCLGE_COMM_RSS_HASH_ALGO_SYMMETRIC 2
#define HCLGE_COMM_RSS_INPUT_TUPLE_OTHER GENMASK(3, 0)
#define HCLGE_COMM_RSS_INPUT_TUPLE_SCTP GENMASK(4, 0)
#define HCLGE_COMM_D_PORT_BIT BIT(0)
#define HCLGE_COMM_S_PORT_BIT BIT(1)
#define HCLGE_COMM_D_IP_BIT BIT(2)
#define HCLGE_COMM_S_IP_BIT BIT(3)
#define HCLGE_COMM_V_TAG_BIT BIT(4)
#define HCLGE_COMM_RSS_INPUT_TUPLE_SCTP_NO_PORT \
(HCLGE_COMM_D_IP_BIT | HCLGE_COMM_S_IP_BIT | HCLGE_COMM_V_TAG_BIT)
#define HCLGE_COMM_MAX_TC_NUM 8
#define HCLGE_COMM_RSS_TC_OFFSET_S 0
#define HCLGE_COMM_RSS_TC_OFFSET_M GENMASK(10, 0)
#define HCLGE_COMM_RSS_TC_SIZE_MSB_B 11
#define HCLGE_COMM_RSS_TC_SIZE_S 12
#define HCLGE_COMM_RSS_TC_SIZE_M GENMASK(14, 12)
#define HCLGE_COMM_RSS_TC_VALID_B 15
#define HCLGE_COMM_RSS_TC_SIZE_MSB_OFFSET 3
struct hclge_comm_rss_tuple_cfg {
u8 ipv4_tcp_en;
u8 ipv4_udp_en;
u8 ipv4_sctp_en;
u8 ipv4_fragment_en;
u8 ipv6_tcp_en;
u8 ipv6_udp_en;
u8 ipv6_sctp_en;
u8 ipv6_fragment_en;
};
#define HCLGE_COMM_RSS_KEY_SIZE 40
#define HCLGE_COMM_RSS_CFG_TBL_SIZE 16
#define HCLGE_COMM_RSS_CFG_TBL_BW_H 2U
#define HCLGE_COMM_RSS_CFG_TBL_BW_L 8U
#define HCLGE_COMM_RSS_CFG_TBL_SIZE_H 4
#define HCLGE_COMM_RSS_SET_BITMAP_MSK GENMASK(15, 0)
#define HCLGE_COMM_RSS_HASH_ALGO_MASK GENMASK(3, 0)
#define HCLGE_COMM_RSS_HASH_KEY_OFFSET_B 4
#define HCLGE_COMM_RSS_HASH_KEY_NUM 16
struct hclge_comm_rss_config_cmd {
u8 hash_config;
u8 rsv[7];
u8 hash_key[HCLGE_COMM_RSS_HASH_KEY_NUM];
};
struct hclge_comm_rss_cfg {
u8 rss_hash_key[HCLGE_COMM_RSS_KEY_SIZE]; /* user configured hash keys */
/* shadow table */
u16 *rss_indirection_tbl;
u32 rss_algo;
struct hclge_comm_rss_tuple_cfg rss_tuple_sets;
u32 rss_size;
};
struct hclge_comm_rss_input_tuple_cmd {
u8 ipv4_tcp_en;
u8 ipv4_udp_en;
u8 ipv4_sctp_en;
u8 ipv4_fragment_en;
u8 ipv6_tcp_en;
u8 ipv6_udp_en;
u8 ipv6_sctp_en;
u8 ipv6_fragment_en;
u8 rsv[16];
};
struct hclge_comm_rss_ind_tbl_cmd {
__le16 start_table_index;
__le16 rss_set_bitmap;
u8 rss_qid_h[HCLGE_COMM_RSS_CFG_TBL_SIZE_H];
u8 rss_qid_l[HCLGE_COMM_RSS_CFG_TBL_SIZE];
};
struct hclge_comm_rss_tc_mode_cmd {
__le16 rss_tc_mode[HCLGE_COMM_MAX_TC_NUM];
u8 rsv[8];
};
u32 hclge_comm_get_rss_key_size(struct hnae3_handle *handle);
void hclge_comm_rss_indir_init_cfg(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_cfg *rss_cfg);
int hclge_comm_get_rss_tuple(struct hclge_comm_rss_cfg *rss_cfg, int flow_type,
u8 *tuple_sets);
int hclge_comm_parse_rss_hfunc(struct hclge_comm_rss_cfg *rss_cfg,
const u8 hfunc, u8 *hash_algo);
void hclge_comm_get_rss_hash_info(struct hclge_comm_rss_cfg *rss_cfg, u8 *key,
u8 *hfunc);
void hclge_comm_get_rss_indir_tbl(struct hclge_comm_rss_cfg *rss_cfg,
u32 *indir, u16 rss_ind_tbl_size);
int hclge_comm_set_rss_algo_key(struct hclge_comm_hw *hw, const u8 hfunc,
const u8 *key);
int hclge_comm_init_rss_tuple_cmd(struct hclge_comm_rss_cfg *rss_cfg,
const struct ethtool_rxfh_fields *nfc,
struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_input_tuple_cmd *req);
u64 hclge_comm_convert_rss_tuple(u8 tuple_sets);
int hclge_comm_set_rss_input_tuple(struct hclge_comm_hw *hw,
struct hclge_comm_rss_cfg *rss_cfg);
int hclge_comm_set_rss_indir_table(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw, const u16 *indir);
int hclge_comm_rss_init_cfg(struct hnae3_handle *nic,
struct hnae3_ae_dev *ae_dev,
struct hclge_comm_rss_cfg *rss_cfg);
void hclge_comm_get_rss_tc_info(u16 rss_size, u8 hw_tc_map, u16 *tc_offset,
u16 *tc_valid, u16 *tc_size);
int hclge_comm_set_rss_tc_mode(struct hclge_comm_hw *hw, u16 *tc_offset,
u16 *tc_valid, u16 *tc_size);
int hclge_comm_set_rss_hash_key(struct hclge_comm_rss_cfg *rss_cfg,
struct hclge_comm_hw *hw, const u8 *key,
const u8 hfunc);
int hclge_comm_set_rss_tuple(struct hnae3_ae_dev *ae_dev,
struct hclge_comm_hw *hw,
struct hclge_comm_rss_cfg *rss_cfg,
const struct ethtool_rxfh_fields *nfc);
#endif
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2021-2021 Hisilicon Limited.
#include <linux/err.h>
#include "hnae3.h"
#include "hclge_comm_cmd.h"
#include "hclge_comm_tqp_stats.h"
u64 *hclge_comm_tqps_get_stats(struct hnae3_handle *handle, u64 *data)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclge_comm_tqp *tqp;
u64 *buff = data;
u16 i;
for (i = 0; i < kinfo->num_tqps; i++) {
tqp = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q);
*buff++ = tqp->tqp_stats.rcb_tx_ring_pktnum_rcd;
}
for (i = 0; i < kinfo->num_tqps; i++) {
tqp = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q);
*buff++ = tqp->tqp_stats.rcb_rx_ring_pktnum_rcd;
}
return buff;
}
EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_stats);
int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
return kinfo->num_tqps * HCLGE_COMM_QUEUE_PAIR_SIZE;
}
EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_sset_count);
void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
u16 i;
for (i = 0; i < kinfo->num_tqps; i++) {
struct hclge_comm_tqp *tqp =
container_of(kinfo->tqp[i], struct hclge_comm_tqp, q);
ethtool_sprintf(data, "txq%u_pktnum_rcd", tqp->index);
}
for (i = 0; i < kinfo->num_tqps; i++) {
struct hclge_comm_tqp *tqp =
container_of(kinfo->tqp[i], struct hclge_comm_tqp, q);
ethtool_sprintf(data, "rxq%u_pktnum_rcd", tqp->index);
}
}
EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_strings);
int hclge_comm_tqps_update_stats(struct hnae3_handle *handle,
struct hclge_comm_hw *hw)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclge_comm_tqp *tqp;
struct hclge_desc desc;
int ret;
u16 i;
for (i = 0; i < kinfo->num_tqps; i++) {
tqp = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q);
hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_RX_STATS,
true);
desc.data[0] = cpu_to_le32(tqp->index);
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret) {
dev_err(&hw->cmq.csq.pdev->dev,
"failed to get tqp stat, ret = %d, rx = %u.\n",
ret, i);
return ret;
}
tqp->tqp_stats.rcb_rx_ring_pktnum_rcd +=
le32_to_cpu(desc.data[1]);
hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_TX_STATS,
true);
desc.data[0] = cpu_to_le32(tqp->index);
ret = hclge_comm_cmd_send(hw, &desc, 1);
if (ret) {
dev_err(&hw->cmq.csq.pdev->dev,
"failed to get tqp stat, ret = %d, tx = %u.\n",
ret, i);
return ret;
}
tqp->tqp_stats.rcb_tx_ring_pktnum_rcd +=
le32_to_cpu(desc.data[1]);
}
return 0;
}
EXPORT_SYMBOL_GPL(hclge_comm_tqps_update_stats);
void hclge_comm_reset_tqp_stats(struct hnae3_handle *handle)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclge_comm_tqp *tqp;
struct hnae3_queue *queue;
u16 i;
for (i = 0; i < kinfo->num_tqps; i++) {
queue = kinfo->tqp[i];
tqp = container_of(queue, struct hclge_comm_tqp, q);
memset(&tqp->tqp_stats, 0, sizeof(tqp->tqp_stats));
}
}
EXPORT_SYMBOL_GPL(hclge_comm_reset_tqp_stats);
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2021-2021 Hisilicon Limited.
#ifndef __HCLGE_COMM_TQP_STATS_H
#define __HCLGE_COMM_TQP_STATS_H
#include <linux/types.h>
#include <linux/etherdevice.h>
#include "hnae3.h"
/* each tqp has TX & RX two queues */
#define HCLGE_COMM_QUEUE_PAIR_SIZE 2
/* TQP stats */
struct hclge_comm_tqp_stats {
/* query_tqp_tx_queue_statistics ,opcode id: 0x0B03 */
u64 rcb_tx_ring_pktnum_rcd; /* 32bit */
/* query_tqp_rx_queue_statistics ,opcode id: 0x0B13 */
u64 rcb_rx_ring_pktnum_rcd; /* 32bit */
};
struct hclge_comm_tqp {
/* copy of device pointer from pci_dev,
* used when perform DMA mapping
*/
struct device *dev;
struct hnae3_queue q;
struct hclge_comm_tqp_stats tqp_stats;
u16 index; /* Global index in a NIC controller */
bool alloced;
};
u64 *hclge_comm_tqps_get_stats(struct hnae3_handle *handle, u64 *data);
int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle);
void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data);
void hclge_comm_reset_tqp_stats(struct hnae3_handle *handle);
int hclge_comm_tqps_update_stats(struct hnae3_handle *handle,
struct hclge_comm_hw *hw);
#endif
@@ -0,0 +1,130 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hnae3.h"
#include "hns3_enet.h"
static int hns3_dcbnl_ieee_getets(struct net_device *ndev, struct ieee_ets *ets)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (hns3_nic_resetting(ndev))
return -EBUSY;
if (h->kinfo.dcb_ops->ieee_getets)
return h->kinfo.dcb_ops->ieee_getets(h, ets);
return -EOPNOTSUPP;
}
static int hns3_dcbnl_ieee_setets(struct net_device *ndev, struct ieee_ets *ets)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (hns3_nic_resetting(ndev))
return -EBUSY;
if (h->kinfo.dcb_ops->ieee_setets)
return h->kinfo.dcb_ops->ieee_setets(h, ets);
return -EOPNOTSUPP;
}
static int hns3_dcbnl_ieee_getpfc(struct net_device *ndev, struct ieee_pfc *pfc)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (hns3_nic_resetting(ndev))
return -EBUSY;
if (h->kinfo.dcb_ops->ieee_getpfc)
return h->kinfo.dcb_ops->ieee_getpfc(h, pfc);
return -EOPNOTSUPP;
}
static int hns3_dcbnl_ieee_setpfc(struct net_device *ndev, struct ieee_pfc *pfc)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (hns3_nic_resetting(ndev))
return -EBUSY;
if (h->kinfo.dcb_ops->ieee_setpfc)
return h->kinfo.dcb_ops->ieee_setpfc(h, pfc);
return -EOPNOTSUPP;
}
static int hns3_dcbnl_ieee_setapp(struct net_device *ndev, struct dcb_app *app)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (hns3_nic_resetting(ndev))
return -EBUSY;
if (h->kinfo.dcb_ops->ieee_setapp)
return h->kinfo.dcb_ops->ieee_setapp(h, app);
return -EOPNOTSUPP;
}
static int hns3_dcbnl_ieee_delapp(struct net_device *ndev, struct dcb_app *app)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (hns3_nic_resetting(ndev))
return -EBUSY;
if (h->kinfo.dcb_ops->ieee_delapp)
return h->kinfo.dcb_ops->ieee_delapp(h, app);
return -EOPNOTSUPP;
}
/* DCBX configuration */
static u8 hns3_dcbnl_getdcbx(struct net_device *ndev)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (h->kinfo.dcb_ops->getdcbx)
return h->kinfo.dcb_ops->getdcbx(h);
return 0;
}
/* return 0 if successful, otherwise fail */
static u8 hns3_dcbnl_setdcbx(struct net_device *ndev, u8 mode)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
if (h->kinfo.dcb_ops->setdcbx)
return h->kinfo.dcb_ops->setdcbx(h, mode);
return 1;
}
static const struct dcbnl_rtnl_ops hns3_dcbnl_ops = {
.ieee_getets = hns3_dcbnl_ieee_getets,
.ieee_setets = hns3_dcbnl_ieee_setets,
.ieee_getpfc = hns3_dcbnl_ieee_getpfc,
.ieee_setpfc = hns3_dcbnl_ieee_setpfc,
.ieee_setapp = hns3_dcbnl_ieee_setapp,
.ieee_delapp = hns3_dcbnl_ieee_delapp,
.getdcbx = hns3_dcbnl_getdcbx,
.setdcbx = hns3_dcbnl_setdcbx,
};
/* hclge_dcbnl_setup - DCBNL setup
* @handle: the corresponding vport handle
* Set up DCBNL
*/
void hns3_dcbnl_setup(struct hnae3_handle *handle)
{
struct net_device *dev = handle->kinfo.netdev;
if ((!handle->kinfo.dcb_ops) || (handle->flags & HNAE3_SUPPORT_VF))
return;
dev->dcbnl_ops = &hns3_dcbnl_ops;
}
@@ -0,0 +1,991 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2018-2019 Hisilicon Limited. */
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/seq_file.h>
#include <linux/string_choices.h>
#include "hnae3.h"
#include "hns3_debugfs.h"
#include "hns3_enet.h"
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"
},
{
.name = "reg"
},
{
.name = "queue"
},
{
.name = "fd"
},
/* keep common at the bottom and add new directory above */
{
.name = "common"
},
};
static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, u32 cmd);
static int hns3_dbg_common_init_t1(struct hnae3_handle *handle, u32 cmd);
static int hns3_dbg_common_init_t2(struct hnae3_handle *handle, u32 cmd);
static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = {
{
.name = "tm_nodes",
.cmd = HNAE3_DBG_CMD_TM_NODES,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "tm_priority",
.cmd = HNAE3_DBG_CMD_TM_PRI,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "tm_qset",
.cmd = HNAE3_DBG_CMD_TM_QSET,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "tm_map",
.cmd = HNAE3_DBG_CMD_TM_MAP,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "tm_pg",
.cmd = HNAE3_DBG_CMD_TM_PG,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "tm_port",
.cmd = HNAE3_DBG_CMD_TM_PORT,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "tc_sch_info",
.cmd = HNAE3_DBG_CMD_TC_SCH_INFO,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "qos_pause_cfg",
.cmd = HNAE3_DBG_CMD_QOS_PAUSE_CFG,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "qos_pri_map",
.cmd = HNAE3_DBG_CMD_QOS_PRI_MAP,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "qos_dscp_map",
.cmd = HNAE3_DBG_CMD_QOS_DSCP_MAP,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "qos_buf_cfg",
.cmd = HNAE3_DBG_CMD_QOS_BUF_CFG,
.dentry = HNS3_DBG_DENTRY_TM,
.init = hns3_dbg_common_init_t2,
},
{
.name = "dev_info",
.cmd = HNAE3_DBG_CMD_DEV_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t1,
},
{
.name = "tx_bd_queue",
.cmd = HNAE3_DBG_CMD_TX_BD,
.dentry = HNS3_DBG_DENTRY_TX_BD,
.init = hns3_dbg_bd_file_init,
},
{
.name = "rx_bd_queue",
.cmd = HNAE3_DBG_CMD_RX_BD,
.dentry = HNS3_DBG_DENTRY_RX_BD,
.init = hns3_dbg_bd_file_init,
},
{
.name = "uc",
.cmd = HNAE3_DBG_CMD_MAC_UC,
.dentry = HNS3_DBG_DENTRY_MAC,
.init = hns3_dbg_common_init_t2,
},
{
.name = "mc",
.cmd = HNAE3_DBG_CMD_MAC_MC,
.dentry = HNS3_DBG_DENTRY_MAC,
.init = hns3_dbg_common_init_t2,
},
{
.name = "mng_tbl",
.cmd = HNAE3_DBG_CMD_MNG_TBL,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "loopback",
.cmd = HNAE3_DBG_CMD_LOOPBACK,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "interrupt_info",
.cmd = HNAE3_DBG_CMD_INTERRUPT_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "reset_info",
.cmd = HNAE3_DBG_CMD_RESET_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "imp_info",
.cmd = HNAE3_DBG_CMD_IMP_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "ncl_config",
.cmd = HNAE3_DBG_CMD_NCL_CONFIG,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "mac_tnl_status",
.cmd = HNAE3_DBG_CMD_MAC_TNL_STATUS,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "bios_common",
.cmd = HNAE3_DBG_CMD_REG_BIOS_COMMON,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "ssu",
.cmd = HNAE3_DBG_CMD_REG_SSU,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "igu_egu",
.cmd = HNAE3_DBG_CMD_REG_IGU_EGU,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "rpu",
.cmd = HNAE3_DBG_CMD_REG_RPU,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "ncsi",
.cmd = HNAE3_DBG_CMD_REG_NCSI,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "rtc",
.cmd = HNAE3_DBG_CMD_REG_RTC,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "ppp",
.cmd = HNAE3_DBG_CMD_REG_PPP,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "rcb",
.cmd = HNAE3_DBG_CMD_REG_RCB,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "tqp",
.cmd = HNAE3_DBG_CMD_REG_TQP,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "mac",
.cmd = HNAE3_DBG_CMD_REG_MAC,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "dcb",
.cmd = HNAE3_DBG_CMD_REG_DCB,
.dentry = HNS3_DBG_DENTRY_REG,
.init = hns3_dbg_common_init_t2,
},
{
.name = "queue_map",
.cmd = HNAE3_DBG_CMD_QUEUE_MAP,
.dentry = HNS3_DBG_DENTRY_QUEUE,
.init = hns3_dbg_common_init_t1,
},
{
.name = "rx_queue_info",
.cmd = HNAE3_DBG_CMD_RX_QUEUE_INFO,
.dentry = HNS3_DBG_DENTRY_QUEUE,
.init = hns3_dbg_common_init_t1,
},
{
.name = "tx_queue_info",
.cmd = HNAE3_DBG_CMD_TX_QUEUE_INFO,
.dentry = HNS3_DBG_DENTRY_QUEUE,
.init = hns3_dbg_common_init_t1,
},
{
.name = "fd_tcam",
.cmd = HNAE3_DBG_CMD_FD_TCAM,
.dentry = HNS3_DBG_DENTRY_FD,
.init = hns3_dbg_common_init_t2,
},
{
.name = "fd_rule",
.cmd = HNAE3_DBG_CMD_FD_RULE,
.dentry = HNS3_DBG_DENTRY_FD,
.init = hns3_dbg_common_init_t2,
},
{
.name = "service_task_info",
.cmd = HNAE3_DBG_CMD_SERV_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "vlan_config",
.cmd = HNAE3_DBG_CMD_VLAN_CONFIG,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "ptp_info",
.cmd = HNAE3_DBG_CMD_PTP_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "fd_counter",
.cmd = HNAE3_DBG_CMD_FD_COUNTER,
.dentry = HNS3_DBG_DENTRY_FD,
.init = hns3_dbg_common_init_t2,
},
{
.name = "umv_info",
.cmd = HNAE3_DBG_CMD_UMV_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t2,
},
{
.name = "page_pool_info",
.cmd = HNAE3_DBG_CMD_PAGE_POOL_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t1,
},
{
.name = "coalesce_info",
.cmd = HNAE3_DBG_CMD_COAL_INFO,
.dentry = HNS3_DBG_DENTRY_COMMON,
.init = hns3_dbg_common_init_t1,
},
};
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 imp-controlled RAS",
.cap_bit = HNAE3_DEV_SUPPORT_RAS_IMP_B,
}, {
.name = "support rxd advanced layout",
.cap_bit = HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
}, {
.name = "support port vlan bypass",
.cap_bit = HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
}, {
.name = "support modify vlan filter state",
.cap_bit = HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B,
}, {
.name = "support FEC statistics",
.cap_bit = HNAE3_DEV_SUPPORT_FEC_STATS_B,
}, {
.name = "support lane num",
.cap_bit = HNAE3_DEV_SUPPORT_LANE_NUM_B,
}, {
.name = "support wake on lan",
.cap_bit = HNAE3_DEV_SUPPORT_WOL_B,
}, {
.name = "support tm flush",
.cap_bit = HNAE3_DEV_SUPPORT_TM_FLUSH_B,
}, {
.name = "support vf fault detect",
.cap_bit = HNAE3_DEV_SUPPORT_VF_FAULT_B,
}
};
static const char * const dim_cqe_mode_str[] = { "EQE", "CQE" };
static const char * const dim_state_str[] = { "START", "IN_PROG", "APPLY" };
static const char * const
dim_tune_stat_str[] = { "ON_TOP", "TIRED", "RIGHT", "LEFT" };
static void hns3_get_coal_info(struct hns3_enet_tqp_vector *tqp_vector,
struct seq_file *s, int i, bool is_tx)
{
unsigned int gl_offset, ql_offset;
struct hns3_enet_coalesce *coal;
unsigned int reg_val;
struct dim *dim;
bool ql_enable;
if (is_tx) {
coal = &tqp_vector->tx_group.coal;
dim = &tqp_vector->tx_group.dim;
gl_offset = HNS3_VECTOR_GL1_OFFSET;
ql_offset = HNS3_VECTOR_TX_QL_OFFSET;
ql_enable = tqp_vector->tx_group.coal.ql_enable;
} else {
coal = &tqp_vector->rx_group.coal;
dim = &tqp_vector->rx_group.dim;
gl_offset = HNS3_VECTOR_GL0_OFFSET;
ql_offset = HNS3_VECTOR_RX_QL_OFFSET;
ql_enable = tqp_vector->rx_group.coal.ql_enable;
}
seq_printf(s, "%-8d", i);
seq_printf(s, "%-12s", dim->state < ARRAY_SIZE(dim_state_str) ?
dim_state_str[dim->state] : "unknown");
seq_printf(s, "%-12u", dim->profile_ix);
seq_printf(s, "%-10s", dim->mode < ARRAY_SIZE(dim_cqe_mode_str) ?
dim_cqe_mode_str[dim->mode] : "unknown");
seq_printf(s, "%-12s", dim->tune_state < ARRAY_SIZE(dim_tune_stat_str) ?
dim_tune_stat_str[dim->tune_state] : "unknown");
seq_printf(s, "%-12u%-13u%-7u%-7u%-7u", dim->steps_left,
dim->steps_right, dim->tired, coal->int_gl, coal->int_ql);
reg_val = readl(tqp_vector->mask_addr + gl_offset) &
HNS3_VECTOR_GL_MASK;
seq_printf(s, "%-7u", reg_val);
if (ql_enable) {
reg_val = readl(tqp_vector->mask_addr + ql_offset) &
HNS3_VECTOR_QL_MASK;
seq_printf(s, "%u\n", reg_val);
} else {
seq_puts(s, "NA\n");
}
}
static void hns3_dump_coal_info(struct seq_file *s, bool is_tx)
{
struct hnae3_handle *h = hnae3_seq_file_to_handle(s);
struct hns3_enet_tqp_vector *tqp_vector;
struct hns3_nic_priv *priv = h->priv;
unsigned int i;
seq_printf(s, "%s interrupt coalesce info:\n", is_tx ? "tx" : "rx");
seq_puts(s, "VEC_ID ALGO_STATE PROFILE_ID CQE_MODE TUNE_STATE ");
seq_puts(s, "STEPS_LEFT STEPS_RIGHT TIRED SW_GL SW_QL ");
seq_puts(s, "HW_GL HW_QL\n");
for (i = 0; i < priv->vector_num; i++) {
tqp_vector = &priv->tqp_vector[i];
hns3_get_coal_info(tqp_vector, s, i, is_tx);
}
}
static int hns3_dbg_coal_info(struct seq_file *s, void *data)
{
hns3_dump_coal_info(s, true);
seq_puts(s, "\n");
hns3_dump_coal_info(s, false);
return 0;
}
static void hns3_dump_rx_queue_info(struct hns3_enet_ring *ring,
struct seq_file *s, u32 index)
{
struct hnae3_ae_dev *ae_dev = hnae3_seq_file_to_ae_dev(s);
void __iomem *base = ring->tqp->io_base;
u32 base_add_l, base_add_h;
seq_printf(s, "%-10u", index);
seq_printf(s, "%-8u",
readl_relaxed(base + HNS3_RING_RX_RING_BD_NUM_REG));
seq_printf(s, "%-8u",
readl_relaxed(base + HNS3_RING_RX_RING_BD_LEN_REG));
seq_printf(s, "%-6u",
readl_relaxed(base + HNS3_RING_RX_RING_TAIL_REG));
seq_printf(s, "%-6u",
readl_relaxed(base + HNS3_RING_RX_RING_HEAD_REG));
seq_printf(s, "%-8u",
readl_relaxed(base + HNS3_RING_RX_RING_FBDNUM_REG));
seq_printf(s, "%-11u", readl_relaxed(base +
HNS3_RING_RX_RING_PKTNUM_RECORD_REG));
seq_printf(s, "%-11u", ring->rx_copybreak);
seq_printf(s, "%-9s",
str_on_off(readl_relaxed(base + HNS3_RING_EN_REG)));
if (hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev))
seq_printf(s, "%-12s", str_on_off(readl_relaxed(base +
HNS3_RING_RX_EN_REG)));
else
seq_printf(s, "%-12s", "NA");
base_add_h = readl_relaxed(base + HNS3_RING_RX_RING_BASEADDR_H_REG);
base_add_l = readl_relaxed(base + HNS3_RING_RX_RING_BASEADDR_L_REG);
seq_printf(s, "0x%08x%08x\n", base_add_h, base_add_l);
}
static int hns3_dbg_rx_queue_info(struct seq_file *s, void *data)
{
struct hnae3_handle *h = hnae3_seq_file_to_handle(s);
struct hns3_nic_priv *priv = h->priv;
struct hns3_enet_ring *ring;
u32 i;
if (!priv->ring) {
dev_err(&h->pdev->dev, "priv->ring is NULL\n");
return -EFAULT;
}
seq_puts(s, "QUEUE_ID BD_NUM BD_LEN TAIL HEAD FBDNUM ");
seq_puts(s, "PKTNUM COPYBREAK RING_EN RX_RING_EN BASE_ADDR\n");
for (i = 0; i < h->kinfo.num_tqps; i++) {
/* Each cycle needs to determine whether the instance is reset,
* to prevent reference to invalid memory. And need to ensure
* that the following code is executed within 100ms.
*/
if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
test_bit(HNS3_NIC_STATE_RESETTING, &priv->state))
return -EPERM;
ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)];
hns3_dump_rx_queue_info(ring, s, i);
}
return 0;
}
static void hns3_dump_tx_queue_info(struct hns3_enet_ring *ring,
struct seq_file *s, u32 index)
{
struct hnae3_ae_dev *ae_dev = hnae3_seq_file_to_ae_dev(s);
void __iomem *base = ring->tqp->io_base;
u32 base_add_l, base_add_h;
seq_printf(s, "%-10u", index);
seq_printf(s, "%-8u",
readl_relaxed(base + HNS3_RING_TX_RING_BD_NUM_REG));
seq_printf(s, "%-4u", readl_relaxed(base + HNS3_RING_TX_RING_TC_REG));
seq_printf(s, "%-6u", readl_relaxed(base + HNS3_RING_TX_RING_TAIL_REG));
seq_printf(s, "%-6u", readl_relaxed(base + HNS3_RING_TX_RING_HEAD_REG));
seq_printf(s, "%-8u",
readl_relaxed(base + HNS3_RING_TX_RING_FBDNUM_REG));
seq_printf(s, "%-8u",
readl_relaxed(base + HNS3_RING_TX_RING_OFFSET_REG));
seq_printf(s, "%-11u",
readl_relaxed(base + HNS3_RING_TX_RING_PKTNUM_RECORD_REG));
seq_printf(s, "%-9s",
str_on_off(readl_relaxed(base + HNS3_RING_EN_REG)));
if (hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev))
seq_printf(s, "%-12s",
str_on_off(readl_relaxed(base +
HNS3_RING_TX_EN_REG)));
else
seq_printf(s, "%-12s", "NA");
base_add_h = readl_relaxed(base + HNS3_RING_TX_RING_BASEADDR_H_REG);
base_add_l = readl_relaxed(base + HNS3_RING_TX_RING_BASEADDR_L_REG);
seq_printf(s, "0x%08x%08x\n", base_add_h, base_add_l);
}
static int hns3_dbg_tx_queue_info(struct seq_file *s, void *data)
{
struct hnae3_handle *h = hnae3_seq_file_to_handle(s);
struct hns3_nic_priv *priv = h->priv;
struct hns3_enet_ring *ring;
u32 i;
if (!priv->ring) {
dev_err(&h->pdev->dev, "priv->ring is NULL\n");
return -EFAULT;
}
seq_puts(s, "QUEUE_ID BD_NUM TC TAIL HEAD FBDNUM OFFSET ");
seq_puts(s, "PKTNUM RING_EN TX_RING_EN BASE_ADDR\n");
for (i = 0; i < h->kinfo.num_tqps; i++) {
/* Each cycle needs to determine whether the instance is reset,
* to prevent reference to invalid memory. And need to ensure
* that the following code is executed within 100ms.
*/
if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
test_bit(HNS3_NIC_STATE_RESETTING, &priv->state))
return -EPERM;
ring = &priv->ring[i];
hns3_dump_tx_queue_info(ring, s, i);
}
return 0;
}
static int hns3_dbg_queue_map(struct seq_file *s, void *data)
{
struct hnae3_handle *h = hnae3_seq_file_to_handle(s);
struct hns3_nic_priv *priv = h->priv;
u32 i;
if (!h->ae_algo->ops->get_global_queue_id)
return -EOPNOTSUPP;
seq_puts(s, "local_queue_id global_queue_id vector_id\n");
for (i = 0; i < h->kinfo.num_tqps; i++) {
if (!priv->ring || !priv->ring[i].tqp_vector)
continue;
seq_printf(s, "%-16u%-17u%d\n", i,
h->ae_algo->ops->get_global_queue_id(h, i),
priv->ring[i].tqp_vector->vector_irq);
}
return 0;
}
static void hns3_dump_rx_bd_info(struct hns3_nic_priv *priv,
struct hns3_desc *desc, struct seq_file *s,
int idx)
{
seq_printf(s, "%-9d%#-11x%-10u%-8u%#-12x%-7u%-10u%-17u%-13u%#-14x",
idx, le32_to_cpu(desc->rx.l234_info),
le16_to_cpu(desc->rx.pkt_len), le16_to_cpu(desc->rx.size),
le32_to_cpu(desc->rx.rss_hash), le16_to_cpu(desc->rx.fd_id),
le16_to_cpu(desc->rx.vlan_tag),
le16_to_cpu(desc->rx.o_dm_vlan_id_fb),
le16_to_cpu(desc->rx.ot_vlan_tag),
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);
seq_printf(s, "%-7lu%-9u\n",
hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
HNS3_RXD_PTYPE_S),
le16_to_cpu(desc->csum));
} else {
seq_puts(s, "NA NA\n");
}
}
static int hns3_dbg_rx_bd_info(struct seq_file *s, void *private)
{
struct hns3_dbg_data *data = s->private;
struct hnae3_handle *h = data->handle;
struct hns3_nic_priv *priv = h->priv;
struct hns3_enet_ring *ring;
struct hns3_desc *desc;
unsigned int i;
if (data->qid >= h->kinfo.num_tqps) {
dev_err(&h->pdev->dev, "queue%u is not in use\n", data->qid);
return -EINVAL;
}
seq_printf(s, "Queue %u rx bd info:\n", data->qid);
seq_puts(s, "BD_IDX L234_INFO PKT_LEN SIZE ");
seq_puts(s, "RSS_HASH FD_ID VLAN_TAG O_DM_VLAN_ID_FB ");
seq_puts(s, "OT_VLAN_TAG BD_BASE_INFO PTYPE HW_CSUM\n");
ring = &priv->ring[data->qid + data->handle->kinfo.num_tqps];
for (i = 0; i < ring->desc_num; i++) {
desc = &ring->desc[i];
hns3_dump_rx_bd_info(priv, desc, s, i);
}
return 0;
}
static void hns3_dump_tx_bd_info(struct hns3_desc *desc, struct seq_file *s,
int idx)
{
seq_printf(s, "%-8d%#-20llx%-10u%-6u%#-15x%-14u%-7u%-16u%#-14x%#-14x%-11u\n",
idx, le64_to_cpu(desc->addr),
le16_to_cpu(desc->tx.vlan_tag),
le16_to_cpu(desc->tx.send_size),
le32_to_cpu(desc->tx.type_cs_vlan_tso_len),
le16_to_cpu(desc->tx.outer_vlan_tag),
le16_to_cpu(desc->tx.tv),
le32_to_cpu(desc->tx.ol_type_vlan_len_msec),
le32_to_cpu(desc->tx.paylen_ol4cs),
le16_to_cpu(desc->tx.bdtp_fe_sc_vld_ra_ri),
le16_to_cpu(desc->tx.mss_hw_csum));
}
static int hns3_dbg_tx_bd_info(struct seq_file *s, void *private)
{
struct hns3_dbg_data *data = s->private;
struct hnae3_handle *h = data->handle;
struct hns3_nic_priv *priv = h->priv;
struct hns3_enet_ring *ring;
struct hns3_desc *desc;
unsigned int i;
if (data->qid >= h->kinfo.num_tqps) {
dev_err(&h->pdev->dev, "queue%u is not in use\n", data->qid);
return -EINVAL;
}
seq_printf(s, "Queue %u tx bd info:\n", data->qid);
seq_puts(s, "BD_IDX ADDRESS VLAN_TAG SIZE ");
seq_puts(s, "T_CS_VLAN_TSO OT_VLAN_TAG TV OLT_VLAN_LEN ");
seq_puts(s, "PAYLEN_OL4CS BD_FE_SC_VLD MSS_HW_CSUM\n");
ring = &priv->ring[data->qid];
for (i = 0; i < ring->desc_num; i++) {
desc = &ring->desc[i];
hns3_dump_tx_bd_info(desc, s, i);
}
return 0;
}
static void hns3_dbg_dev_caps(struct hnae3_handle *h, struct seq_file *s)
{
struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(h);
unsigned long *caps = ae_dev->caps;
u32 i, state;
seq_puts(s, "dev capability:\n");
for (i = 0; i < ARRAY_SIZE(hns3_dbg_cap); i++) {
state = test_bit(hns3_dbg_cap[i].cap_bit, caps);
seq_printf(s, "%s: %s\n", hns3_dbg_cap[i].name,
str_yes_no(state));
}
seq_puts(s, "\n");
}
static void hns3_dbg_dev_specs(struct hnae3_handle *h, struct seq_file *s)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
struct hnae3_dev_specs *dev_specs = &ae_dev->dev_specs;
struct hnae3_knic_private_info *kinfo = &h->kinfo;
struct net_device *dev = kinfo->netdev;
seq_puts(s, "dev_spec:\n");
seq_printf(s, "MAC entry num: %u\n", dev_specs->mac_entry_num);
seq_printf(s, "MNG entry num: %u\n", dev_specs->mng_entry_num);
seq_printf(s, "MAX non tso bd num: %u\n",
dev_specs->max_non_tso_bd_num);
seq_printf(s, "RSS ind tbl size: %u\n", dev_specs->rss_ind_tbl_size);
seq_printf(s, "RSS key size: %u\n", dev_specs->rss_key_size);
seq_printf(s, "RSS size: %u\n", kinfo->rss_size);
seq_printf(s, "Allocated RSS size: %u\n", kinfo->req_rss_size);
seq_printf(s, "Task queue pairs numbers: %u\n", kinfo->num_tqps);
seq_printf(s, "RX buffer length: %u\n", kinfo->rx_buf_len);
seq_printf(s, "Desc num per TX queue: %u\n", kinfo->num_tx_desc);
seq_printf(s, "Desc num per RX queue: %u\n", kinfo->num_rx_desc);
seq_printf(s, "Total number of enabled TCs: %u\n",
kinfo->tc_info.num_tc);
seq_printf(s, "MAX INT QL: %u\n", dev_specs->int_ql_max);
seq_printf(s, "MAX INT GL: %u\n", dev_specs->max_int_gl);
seq_printf(s, "MAX TM RATE: %u\n", dev_specs->max_tm_rate);
seq_printf(s, "MAX QSET number: %u\n", dev_specs->max_qset_num);
seq_printf(s, "umv size: %u\n", dev_specs->umv_size);
seq_printf(s, "mc mac size: %u\n", dev_specs->mc_mac_size);
seq_printf(s, "MAC statistics number: %u\n", dev_specs->mac_stats_num);
seq_printf(s, "TX timeout threshold: %d seconds\n",
dev->watchdog_timeo / HZ);
seq_printf(s, "mac tunnel number: %u\n", dev_specs->tnl_num);
seq_printf(s, "Hilink Version: %u\n", dev_specs->hilink_version);
}
static int hns3_dbg_dev_info(struct seq_file *s, void *data)
{
struct hnae3_handle *h = hnae3_seq_file_to_handle(s);
hns3_dbg_dev_caps(h, s);
hns3_dbg_dev_specs(h, s);
return 0;
}
static void hns3_dump_page_pool_info(struct hns3_enet_ring *ring,
struct seq_file *s, u32 index)
{
seq_printf(s, "%-10u%-14u%-14d%-21u%-7u%-9d%uK\n",
index,
READ_ONCE(ring->page_pool->pages_state_hold_cnt),
atomic_read(&ring->page_pool->pages_state_release_cnt),
ring->page_pool->p.pool_size,
ring->page_pool->p.order,
ring->page_pool->p.nid,
ring->page_pool->p.max_len / 1024);
}
static int hns3_dbg_page_pool_info(struct seq_file *s, void *data)
{
struct hnae3_handle *h = hnae3_seq_file_to_handle(s);
struct hns3_nic_priv *priv = h->priv;
struct hns3_enet_ring *ring;
u32 i;
if (!priv->ring) {
dev_err(&h->pdev->dev, "priv->ring is NULL\n");
return -EFAULT;
}
if (!priv->ring[h->kinfo.num_tqps].page_pool) {
dev_err(&h->pdev->dev, "page pool is not initialized\n");
return -EFAULT;
}
seq_puts(s, "QUEUE_ID ALLOCATE_CNT FREE_CNT ");
seq_puts(s, "POOL_SIZE(PAGE_NUM) ORDER NUMA_ID MAX_LEN\n");
for (i = 0; i < h->kinfo.num_tqps; i++) {
if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
test_bit(HNS3_NIC_STATE_RESETTING, &priv->state))
return -EPERM;
ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)];
hns3_dump_page_pool_info(ring, s, i);
}
return 0;
}
static int hns3_dbg_bd_info_show(struct seq_file *s, void *private)
{
struct hns3_dbg_data *data = s->private;
struct hnae3_handle *h = data->handle;
struct hns3_nic_priv *priv = h->priv;
if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
test_bit(HNS3_NIC_STATE_RESETTING, &priv->state))
return -EBUSY;
if (data->cmd == HNAE3_DBG_CMD_TX_BD)
return hns3_dbg_tx_bd_info(s, private);
else if (data->cmd == HNAE3_DBG_CMD_RX_BD)
return hns3_dbg_rx_bd_info(s, private);
return -EOPNOTSUPP;
}
DEFINE_SHOW_ATTRIBUTE(hns3_dbg_bd_info);
static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, u32 cmd)
{
struct hns3_dbg_data *data;
struct dentry *entry_dir;
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_kcalloc(&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].cmd = hns3_dbg_cmd[cmd].cmd;
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_bd_info_fops);
}
return 0;
}
static int hns3_dbg_common_init_t1(struct hnae3_handle *handle, u32 cmd)
{
struct device *dev = &handle->pdev->dev;
struct dentry *entry_dir;
read_func func = NULL;
switch (hns3_dbg_cmd[cmd].cmd) {
case HNAE3_DBG_CMD_TX_QUEUE_INFO:
func = hns3_dbg_tx_queue_info;
break;
case HNAE3_DBG_CMD_RX_QUEUE_INFO:
func = hns3_dbg_rx_queue_info;
break;
case HNAE3_DBG_CMD_QUEUE_MAP:
func = hns3_dbg_queue_map;
break;
case HNAE3_DBG_CMD_PAGE_POOL_INFO:
func = hns3_dbg_page_pool_info;
break;
case HNAE3_DBG_CMD_COAL_INFO:
func = hns3_dbg_coal_info;
break;
case HNAE3_DBG_CMD_DEV_INFO:
func = hns3_dbg_dev_info;
break;
default:
return -EINVAL;
}
entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
debugfs_create_devm_seqfile(dev, hns3_dbg_cmd[cmd].name, entry_dir,
func);
return 0;
}
static int hns3_dbg_common_init_t2(struct hnae3_handle *handle, u32 cmd)
{
const struct hnae3_ae_ops *ops = hns3_get_ops(handle);
struct device *dev = &handle->pdev->dev;
struct dentry *entry_dir;
read_func func;
int ret;
if (!ops->dbg_get_read_func)
return 0;
ret = ops->dbg_get_read_func(handle, hns3_dbg_cmd[cmd].cmd, &func);
if (ret)
return ret;
entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
debugfs_create_devm_seqfile(dev, hns3_dbg_cmd[cmd].name, entry_dir,
func);
return 0;
}
int hns3_dbg_init(struct hnae3_handle *handle)
{
struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle);
const char *name = pci_name(handle->pdev);
int ret;
u32 i;
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;
for (i = 0; i < HNS3_DBG_DENTRY_COMMON; i++)
hns3_dbg_dentry[i].dentry =
debugfs_create_dir(hns3_dbg_dentry[i].name,
handle->hnae3_dbgfs);
for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
if ((hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_TM_NODES &&
ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2) ||
(hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_PTP_INFO &&
!test_bit(HNAE3_DEV_SUPPORT_PTP_B, ae_dev->caps)))
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)
{
debugfs_remove_recursive(handle->hnae3_dbgfs);
handle->hnae3_dbgfs = NULL;
}
void hns3_dbg_register_debugfs(const char *debugfs_dir_name)
{
hns3_dbgfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
}
void hns3_dbg_unregister_debugfs(void)
{
debugfs_remove_recursive(hns3_dbgfs_root);
hns3_dbgfs_root = NULL;
}
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Hisilicon Limited. */
#ifndef __HNS3_DEBUGFS_H
#define __HNS3_DEBUGFS_H
#include "hnae3.h"
#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;
enum hnae3_dbg_cmd cmd;
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_REG,
HNS3_DBG_DENTRY_QUEUE,
HNS3_DBG_DENTRY_FD,
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;
int (*init)(struct hnae3_handle *handle, unsigned int cmd);
};
struct hns3_dbg_cap_info {
const char *name;
enum HNAE3_DEV_CAP_BITS cap_bit;
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,761 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2016-2017 Hisilicon Limited.
#ifndef __HNS3_ENET_H
#define __HNS3_ENET_H
#include <linux/dim.h>
#include <linux/if_vlan.h>
#include <net/page_pool/types.h>
#include <asm/barrier.h>
#include "hnae3.h"
struct iphdr;
struct ipv6hdr;
enum hns3_nic_state {
HNS3_NIC_STATE_TESTING,
HNS3_NIC_STATE_RESETTING,
HNS3_NIC_STATE_INITED,
HNS3_NIC_STATE_DOWN,
HNS3_NIC_STATE_DISABLED,
HNS3_NIC_STATE_REMOVING,
HNS3_NIC_STATE_SERVICE_INITED,
HNS3_NIC_STATE_SERVICE_SCHED,
HNS3_NIC_STATE2_RESET_REQUESTED,
HNS3_NIC_STATE_HW_TX_CSUM_ENABLE,
HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE,
HNS3_NIC_STATE_TX_PUSH_ENABLE,
HNS3_NIC_STATE_MAX
};
#define HNS3_MAX_PUSH_BD_NUM 2
#define HNS3_RING_RX_RING_BASEADDR_L_REG 0x00000
#define HNS3_RING_RX_RING_BASEADDR_H_REG 0x00004
#define HNS3_RING_RX_RING_BD_NUM_REG 0x00008
#define HNS3_RING_RX_RING_BD_LEN_REG 0x0000C
#define HNS3_RING_RX_RING_TAIL_REG 0x00018
#define HNS3_RING_RX_RING_HEAD_REG 0x0001C
#define HNS3_RING_RX_RING_FBDNUM_REG 0x00020
#define HNS3_RING_RX_RING_PKTNUM_RECORD_REG 0x0002C
#define HNS3_RING_TX_RING_BASEADDR_L_REG 0x00040
#define HNS3_RING_TX_RING_BASEADDR_H_REG 0x00044
#define HNS3_RING_TX_RING_BD_NUM_REG 0x00048
#define HNS3_RING_TX_RING_TC_REG 0x00050
#define HNS3_RING_TX_RING_TAIL_REG 0x00058
#define HNS3_RING_TX_RING_HEAD_REG 0x0005C
#define HNS3_RING_TX_RING_FBDNUM_REG 0x00060
#define HNS3_RING_TX_RING_OFFSET_REG 0x00064
#define HNS3_RING_TX_RING_EBDNUM_REG 0x00068
#define HNS3_RING_TX_RING_PKTNUM_RECORD_REG 0x0006C
#define HNS3_RING_TX_RING_EBD_OFFSET_REG 0x00070
#define HNS3_RING_TX_RING_BD_ERR_REG 0x00074
#define HNS3_RING_EN_REG 0x00090
#define HNS3_RING_RX_EN_REG 0x00098
#define HNS3_RING_TX_EN_REG 0x000D4
#define HNS3_RX_HEAD_SIZE 256
#define HNS3_TX_TIMEOUT (5 * HZ)
#define HNS3_RING_NAME_LEN 16
#define HNS3_BUFFER_SIZE_2048 2048
#define HNS3_RING_MAX_PENDING 32760
#define HNS3_RING_MIN_PENDING 72
#define HNS3_RING_BD_MULTIPLE 8
/* max frame size of mac */
#define HNS3_MAX_MTU(max_frm_size) \
((max_frm_size) - (ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN))
#define HNS3_BD_SIZE_512_TYPE 0
#define HNS3_BD_SIZE_1024_TYPE 1
#define HNS3_BD_SIZE_2048_TYPE 2
#define HNS3_BD_SIZE_4096_TYPE 3
#define HNS3_RX_FLAG_VLAN_PRESENT 0x1
#define HNS3_RX_FLAG_L3ID_IPV4 0x0
#define HNS3_RX_FLAG_L3ID_IPV6 0x1
#define HNS3_RX_FLAG_L4ID_UDP 0x0
#define HNS3_RX_FLAG_L4ID_TCP 0x1
#define HNS3_RXD_DMAC_S 0
#define HNS3_RXD_DMAC_M (0x3 << HNS3_RXD_DMAC_S)
#define HNS3_RXD_VLAN_S 2
#define HNS3_RXD_VLAN_M (0x3 << HNS3_RXD_VLAN_S)
#define HNS3_RXD_L3ID_S 4
#define HNS3_RXD_L3ID_M (0xf << HNS3_RXD_L3ID_S)
#define HNS3_RXD_L4ID_S 8
#define HNS3_RXD_L4ID_M (0xf << HNS3_RXD_L4ID_S)
#define HNS3_RXD_FRAG_B 12
#define HNS3_RXD_STRP_TAGP_S 13
#define HNS3_RXD_STRP_TAGP_M (0x3 << HNS3_RXD_STRP_TAGP_S)
#define HNS3_RXD_L2E_B 16
#define HNS3_RXD_L3E_B 17
#define HNS3_RXD_L4E_B 18
#define HNS3_RXD_TRUNCAT_B 19
#define HNS3_RXD_HOI_B 20
#define HNS3_RXD_DOI_B 21
#define HNS3_RXD_OL3E_B 22
#define HNS3_RXD_OL4E_B 23
#define HNS3_RXD_GRO_COUNT_S 24
#define HNS3_RXD_GRO_COUNT_M (0x3f << HNS3_RXD_GRO_COUNT_S)
#define HNS3_RXD_GRO_FIXID_B 30
#define HNS3_RXD_GRO_ECN_B 31
#define HNS3_RXD_ODMAC_S 0
#define HNS3_RXD_ODMAC_M (0x3 << HNS3_RXD_ODMAC_S)
#define HNS3_RXD_OVLAN_S 2
#define HNS3_RXD_OVLAN_M (0x3 << HNS3_RXD_OVLAN_S)
#define HNS3_RXD_OL3ID_S 4
#define HNS3_RXD_OL3ID_M (0xf << HNS3_RXD_OL3ID_S)
#define HNS3_RXD_OL4ID_S 8
#define HNS3_RXD_OL4ID_M (0xf << HNS3_RXD_OL4ID_S)
#define HNS3_RXD_FBHI_S 12
#define HNS3_RXD_FBHI_M (0x3 << HNS3_RXD_FBHI_S)
#define HNS3_RXD_FBLI_S 14
#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_M (0xf << HNS3_RXD_BDTYPE_S)
#define HNS3_RXD_VLD_B 4
#define HNS3_RXD_UDP0_B 5
#define HNS3_RXD_EXTEND_B 7
#define HNS3_RXD_FE_B 8
#define HNS3_RXD_LUM_B 9
#define HNS3_RXD_CRCP_B 10
#define HNS3_RXD_L3L4P_B 11
#define HNS3_RXD_TSIDX_S 12
#define HNS3_RXD_TSIDX_M (0x3 << HNS3_RXD_TSIDX_S)
#define HNS3_RXD_TS_VLD_B 14
#define HNS3_RXD_LKBK_B 15
#define HNS3_RXD_GRO_SIZE_S 16
#define HNS3_RXD_GRO_SIZE_M (0x3fff << HNS3_RXD_GRO_SIZE_S)
#define HNS3_TXD_L3T_S 0
#define HNS3_TXD_L3T_M (0x3 << HNS3_TXD_L3T_S)
#define HNS3_TXD_L4T_S 2
#define HNS3_TXD_L4T_M (0x3 << HNS3_TXD_L4T_S)
#define HNS3_TXD_L3CS_B 4
#define HNS3_TXD_L4CS_B 5
#define HNS3_TXD_VLAN_B 6
#define HNS3_TXD_TSO_B 7
#define HNS3_TXD_L2LEN_S 8
#define HNS3_TXD_L2LEN_M (0xff << HNS3_TXD_L2LEN_S)
#define HNS3_TXD_L3LEN_S 16
#define HNS3_TXD_L3LEN_M (0xff << HNS3_TXD_L3LEN_S)
#define HNS3_TXD_L4LEN_S 24
#define HNS3_TXD_L4LEN_M (0xff << HNS3_TXD_L4LEN_S)
#define HNS3_TXD_CSUM_START_S 8
#define HNS3_TXD_CSUM_START_M (0xffff << HNS3_TXD_CSUM_START_S)
#define HNS3_TXD_OL3T_S 0
#define HNS3_TXD_OL3T_M (0x3 << HNS3_TXD_OL3T_S)
#define HNS3_TXD_OVLAN_B 2
#define HNS3_TXD_MACSEC_B 3
#define HNS3_TXD_TUNTYPE_S 4
#define HNS3_TXD_TUNTYPE_M (0xf << HNS3_TXD_TUNTYPE_S)
#define HNS3_TXD_CSUM_OFFSET_S 8
#define HNS3_TXD_CSUM_OFFSET_M (0xffff << HNS3_TXD_CSUM_OFFSET_S)
#define HNS3_TXD_BDTYPE_S 0
#define HNS3_TXD_BDTYPE_M (0xf << HNS3_TXD_BDTYPE_S)
#define HNS3_TXD_FE_B 4
#define HNS3_TXD_SC_S 5
#define HNS3_TXD_SC_M (0x3 << HNS3_TXD_SC_S)
#define HNS3_TXD_EXTEND_B 7
#define HNS3_TXD_VLD_B 8
#define HNS3_TXD_RI_B 9
#define HNS3_TXD_RA_B 10
#define HNS3_TXD_TSYN_B 11
#define HNS3_TXD_DECTTL_S 12
#define HNS3_TXD_DECTTL_M (0xf << HNS3_TXD_DECTTL_S)
#define HNS3_TXD_OL4CS_B 22
#define HNS3_TXD_MSS_S 0
#define HNS3_TXD_MSS_M (0x3fff << HNS3_TXD_MSS_S)
#define HNS3_TXD_HW_CS_B 14
#define HNS3_VECTOR_TX_IRQ BIT_ULL(0)
#define HNS3_VECTOR_RX_IRQ BIT_ULL(1)
#define HNS3_VECTOR_NOT_INITED 0
#define HNS3_VECTOR_INITED 1
#define HNS3_MAX_BD_SIZE 65535
#define HNS3_MAX_TSO_BD_NUM 63U
#define HNS3_MAX_TSO_SIZE 1048576U
#define HNS3_MAX_NON_TSO_SIZE 9728U
#define HNS3_VECTOR_GL_MASK GENMASK(11, 0)
#define HNS3_VECTOR_GL0_OFFSET 0x100
#define HNS3_VECTOR_GL1_OFFSET 0x200
#define HNS3_VECTOR_GL2_OFFSET 0x300
#define HNS3_VECTOR_RL_OFFSET 0x900
#define HNS3_VECTOR_RL_EN_B 6
#define HNS3_VECTOR_QL_MASK GENMASK(9, 0)
#define HNS3_VECTOR_TX_QL_OFFSET 0xe00
#define HNS3_VECTOR_RX_QL_OFFSET 0xf00
#define HNS3_RING_EN_B 0
#define HNS3_GL0_CQ_MODE_REG 0x20d00
#define HNS3_GL1_CQ_MODE_REG 0x20d04
#define HNS3_GL2_CQ_MODE_REG 0x20d08
#define HNS3_CQ_MODE_EQE 1U
#define HNS3_CQ_MODE_CQE 0U
#define HNS3_RESCHED_BD_NUM 1024
enum hns3_pkt_l2t_type {
HNS3_L2_TYPE_UNICAST,
HNS3_L2_TYPE_MULTICAST,
HNS3_L2_TYPE_BROADCAST,
HNS3_L2_TYPE_INVALID,
};
enum hns3_pkt_l3t_type {
HNS3_L3T_NONE,
HNS3_L3T_IPV6,
HNS3_L3T_IPV4,
HNS3_L3T_RESERVED
};
enum hns3_pkt_l4t_type {
HNS3_L4T_UNKNOWN,
HNS3_L4T_TCP,
HNS3_L4T_UDP,
HNS3_L4T_SCTP
};
enum hns3_pkt_ol3t_type {
HNS3_OL3T_NONE,
HNS3_OL3T_IPV6,
HNS3_OL3T_IPV4_NO_CSUM,
HNS3_OL3T_IPV4_CSUM
};
enum hns3_pkt_tun_type {
HNS3_TUN_NONE,
HNS3_TUN_MAC_IN_UDP,
HNS3_TUN_NVGRE,
HNS3_TUN_OTHER
};
/* hardware spec ring buffer format */
struct __packed hns3_desc {
union {
__le64 addr;
__le16 csum;
struct {
__le32 ts_nsec;
__le32 ts_sec;
};
};
union {
struct {
__le16 vlan_tag;
__le16 send_size;
union {
__le32 type_cs_vlan_tso_len;
struct {
__u8 type_cs_vlan_tso;
__u8 l2_len;
__u8 l3_len;
__u8 l4_len;
};
};
__le16 outer_vlan_tag;
__le16 tv;
union {
__le32 ol_type_vlan_len_msec;
struct {
__u8 ol_type_vlan_msec;
__u8 ol2_len;
__u8 ol3_len;
__u8 ol4_len;
};
};
__le32 paylen_ol4cs;
__le16 bdtp_fe_sc_vld_ra_ri;
__le16 mss_hw_csum;
} tx;
struct {
__le32 l234_info;
__le16 pkt_len;
__le16 size;
__le32 rss_hash;
__le16 fd_id;
__le16 vlan_tag;
union {
__le32 ol_info;
struct {
__le16 o_dm_vlan_id_fb;
__le16 ot_vlan_tag;
};
};
__le32 bd_base_info;
} rx;
};
};
enum hns3_desc_type {
DESC_TYPE_UNKNOWN = 0,
DESC_TYPE_SKB = 1 << 0,
DESC_TYPE_FRAGLIST_SKB = 1 << 1,
DESC_TYPE_PAGE = 1 << 2,
DESC_TYPE_BOUNCE_ALL = 1 << 3,
DESC_TYPE_BOUNCE_HEAD = 1 << 4,
DESC_TYPE_SGL_SKB = 1 << 5,
DESC_TYPE_PP_FRAG = 1 << 6,
};
struct hns3_desc_cb {
dma_addr_t dma; /* dma address of this desc */
void *buf; /* cpu addr for a desc */
/* priv data for the desc, e.g. skb when use with ip stack */
void *priv;
union {
u32 page_offset; /* for rx */
u32 send_bytes; /* for tx */
};
u32 length; /* length of the buffer */
u16 reuse_flag;
u16 refill;
/* desc type, used by the ring user to mark the type of the priv data */
u16 type;
u16 pagecnt_bias;
};
enum hns3_pkt_l3type {
HNS3_L3_TYPE_IPV4,
HNS3_L3_TYPE_IPV6,
HNS3_L3_TYPE_ARP,
HNS3_L3_TYPE_RARP,
HNS3_L3_TYPE_IPV4_OPT,
HNS3_L3_TYPE_IPV6_EXT,
HNS3_L3_TYPE_LLDP,
HNS3_L3_TYPE_BPDU,
HNS3_L3_TYPE_MAC_PAUSE,
HNS3_L3_TYPE_PFC_PAUSE, /* 0x9 */
/* reserved for 0xA~0xB */
HNS3_L3_TYPE_CNM = 0xc,
/* reserved for 0xD~0xE */
HNS3_L3_TYPE_PARSE_FAIL = 0xf /* must be last */
};
enum hns3_pkt_l4type {
HNS3_L4_TYPE_UDP,
HNS3_L4_TYPE_TCP,
HNS3_L4_TYPE_GRE,
HNS3_L4_TYPE_SCTP,
HNS3_L4_TYPE_IGMP,
HNS3_L4_TYPE_ICMP,
/* reserved for 0x6~0xE */
HNS3_L4_TYPE_PARSE_FAIL = 0xf /* must be last */
};
enum hns3_pkt_ol3type {
HNS3_OL3_TYPE_IPV4 = 0,
HNS3_OL3_TYPE_IPV6,
/* reserved for 0x2~0x3 */
HNS3_OL3_TYPE_IPV4_OPT = 4,
HNS3_OL3_TYPE_IPV6_EXT,
/* reserved for 0x6~0xE */
HNS3_OL3_TYPE_PARSE_FAIL = 0xf /* must be last */
};
enum hns3_pkt_ol4type {
HNS3_OL4_TYPE_NO_TUN,
HNS3_OL4_TYPE_MAC_IN_UDP,
HNS3_OL4_TYPE_NVGRE,
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;
u32 hash_type: 3;
};
struct ring_stats {
u64 sw_err_cnt;
u64 seg_pkt_cnt;
union {
struct {
u64 tx_pkts;
u64 tx_bytes;
u64 tx_more;
u64 tx_push;
u64 tx_mem_doorbell;
u64 restart_queue;
u64 tx_busy;
u64 tx_copy;
u64 tx_vlan_err;
u64 tx_l4_proto_err;
u64 tx_l2l3l4_err;
u64 tx_tso_err;
u64 over_max_recursion;
u64 hw_limitation;
u64 tx_bounce;
u64 tx_spare_full;
u64 copy_bits_err;
u64 tx_sgl;
u64 skb2sgl_err;
u64 map_sg_err;
};
struct {
u64 rx_pkts;
u64 rx_bytes;
u64 rx_err_cnt;
u64 reuse_pg_cnt;
u64 err_pkt_len;
u64 err_bd_num;
u64 l2_err;
u64 l3l4_csum_err;
u64 csum_complete;
u64 rx_multicast;
u64 non_reuse_pg;
u64 frag_alloc_err;
u64 frag_alloc;
};
__le16 csum;
};
};
struct hns3_tx_spare {
dma_addr_t dma;
void *buf;
u32 next_to_use;
u32 next_to_clean;
u32 last_to_clean;
u32 len;
};
struct hns3_enet_ring {
struct hns3_desc *desc; /* dma map address space */
struct hns3_desc_cb *desc_cb;
struct hns3_enet_ring *next;
struct hns3_enet_tqp_vector *tqp_vector;
struct hnae3_queue *tqp;
int queue_index;
struct device *dev; /* will be used for DMA mapping of descriptors */
struct page_pool *page_pool;
/* statistic */
struct ring_stats stats;
struct u64_stats_sync syncp;
dma_addr_t desc_dma_addr;
u32 buf_size; /* size for hnae_desc->addr, preset by AE */
u16 desc_num; /* total number of desc */
int next_to_use; /* idx of next spare desc */
/* idx of lastest sent desc, the ring is empty when equal to
* next_to_use
*/
int next_to_clean;
u32 flag; /* ring attribute */
int pending_buf;
union {
/* for Tx ring */
struct {
u32 fd_qb_tx_sample;
int last_to_use; /* last idx used by xmit */
u32 tx_copybreak;
struct hns3_tx_spare *tx_spare;
};
/* for Rx ring */
struct {
u32 pull_len; /* memcpy len for current rx packet */
u32 rx_copybreak;
u32 frag_num;
/* first buffer address for current packet */
unsigned char *va;
struct sk_buff *skb;
struct sk_buff *tail_skb;
};
};
} ____cacheline_internodealigned_in_smp;
enum hns3_flow_level_range {
HNS3_FLOW_LOW = 0,
HNS3_FLOW_MID = 1,
HNS3_FLOW_HIGH = 2,
HNS3_FLOW_ULTRA = 3,
};
#define HNS3_INT_GL_50K 0x0014
#define HNS3_INT_GL_20K 0x0032
#define HNS3_INT_GL_18K 0x0036
#define HNS3_INT_GL_8K 0x007C
#define HNS3_INT_GL_1US BIT(31)
#define HNS3_INT_RL_MAX 0x00EC
#define HNS3_INT_RL_ENABLE_MASK 0x40
#define HNS3_INT_QL_DEFAULT_CFG 0x20
struct hns3_enet_coalesce {
u16 int_gl;
u16 int_ql;
u16 int_ql_max;
u8 adapt_enable : 1;
u8 ql_enable : 1;
u8 unit_1us : 1;
enum hns3_flow_level_range flow_level;
};
struct hns3_enet_ring_group {
/* array of pointers to rings */
struct hns3_enet_ring *ring;
u64 total_bytes; /* total bytes processed this group */
u64 total_packets; /* total packets processed this group */
u16 count;
struct hns3_enet_coalesce coal;
struct dim dim;
};
struct hns3_enet_tqp_vector {
struct hnae3_handle *handle;
u8 __iomem *mask_addr;
int vector_irq;
int irq_init_flag;
u16 idx; /* index in the TQP vector array per handle. */
struct napi_struct napi;
struct hns3_enet_ring_group rx_group;
struct hns3_enet_ring_group tx_group;
cpumask_t affinity_mask;
u16 num_tqps; /* total number of tqps in TQP vector */
struct irq_affinity_notify affinity_notify;
char name[HNAE3_INT_NAME_LEN];
u64 event_cnt;
} ____cacheline_internodealigned_in_smp;
struct hns3_nic_priv {
struct hnae3_handle *ae_handle;
struct net_device *netdev;
struct device *dev;
/**
* the cb for nic to manage the ring buffer, the first half of the
* array is for tx_ring and vice versa for the second half
*/
struct hns3_enet_ring *ring;
struct hns3_enet_tqp_vector *tqp_vector;
u16 vector_num;
u8 max_non_tso_bd_num;
u64 tx_timeout_count;
unsigned long state;
enum dim_cq_period_mode tx_cqe_mode;
enum dim_cq_period_mode rx_cqe_mode;
struct hns3_enet_coalesce tx_coal;
struct hns3_enet_coalesce rx_coal;
u32 tx_copybreak;
u32 rx_copybreak;
u32 min_tx_copybreak;
u32 min_tx_spare_buf_size;
};
union l3_hdr_info {
struct iphdr *v4;
struct ipv6hdr *v6;
unsigned char *hdr;
};
union l4_hdr_info {
struct tcphdr *tcp;
struct udphdr *udp;
struct gre_base_hdr *gre;
unsigned char *hdr;
};
struct hns3_hw_error_info {
enum hnae3_hw_error_type type;
const char *msg;
};
struct hns3_reset_type_map {
enum ethtool_reset_flags rst_flags;
enum hnae3_reset_type rst_type;
};
static inline u32 ring_space(struct hns3_enet_ring *ring)
{
/* This smp_load_acquire() pairs with smp_store_release() in
* hns3_nic_reclaim_one_desc called by hns3_clean_tx_ring.
*/
int begin = smp_load_acquire(&ring->next_to_clean);
int end = READ_ONCE(ring->next_to_use);
return ((end >= begin) ? (ring->desc_num - end + begin) :
(begin - end)) - 1;
}
static inline u32 hns3_tqp_read_reg(struct hns3_enet_ring *ring, u32 reg)
{
return readl_relaxed(ring->tqp->io_base + reg);
}
static inline u32 hns3_read_reg(void __iomem *base, u32 reg)
{
return readl(base + reg);
}
static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
{
u8 __iomem *reg_addr = READ_ONCE(base);
writel(value, reg_addr + reg);
}
#define hns3_read_dev(a, reg) \
hns3_read_reg((a)->io_base, reg)
static inline bool hns3_nic_resetting(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
return test_bit(HNS3_NIC_STATE_RESETTING, &priv->state);
}
#define hns3_write_dev(a, reg, value) \
hns3_write_reg((a)->io_base, reg, value)
#define ring_to_dev(ring) ((ring)->dev)
#define ring_to_netdev(ring) ((ring)->tqp_vector->napi.dev)
#define ring_to_dma_dir(ring) (HNAE3_IS_TX_RING(ring) ? \
DMA_TO_DEVICE : DMA_FROM_DEVICE)
#define hns3_buf_size(_ring) ((_ring)->buf_size)
#define hns3_ring_stats_update(ring, cnt) do { \
typeof(ring) (tmp) = (ring); \
u64_stats_update_begin(&(tmp)->syncp); \
((tmp)->stats.cnt)++; \
u64_stats_update_end(&(tmp)->syncp); \
} while (0) \
static inline unsigned int hns3_page_order(struct hns3_enet_ring *ring)
{
#if (PAGE_SIZE < 8192)
if (ring->buf_size > (PAGE_SIZE / 2))
return 1;
#endif
return 0;
}
#define hns3_page_size(_ring) (PAGE_SIZE << hns3_page_order(_ring))
/* iterator for handling rings in ring group */
#define hns3_for_each_ring(pos, head) \
for ((pos) = (head).ring; (pos); (pos) = (pos)->next)
#define hns3_get_handle(ndev) \
(((struct hns3_nic_priv *)netdev_priv(ndev))->ae_handle)
#define hns3_get_ae_dev(handle) \
(pci_get_drvdata((handle)->pdev))
#define hns3_get_ops(handle) \
((handle)->ae_algo->ops)
#define hns3_gl_usec_to_reg(int_gl) ((int_gl) >> 1)
#define hns3_gl_round_down(int_gl) round_down(int_gl, 2)
#define hns3_rl_usec_to_reg(int_rl) ((int_rl) >> 2)
#define hns3_rl_round_down(int_rl) round_down(int_rl, 4)
void hns3_ethtool_set_ops(struct net_device *netdev);
int hns3_set_channels(struct net_device *netdev,
struct ethtool_channels *ch);
void hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget);
int hns3_init_all_ring(struct hns3_nic_priv *priv);
int hns3_nic_reset_all_ring(struct hnae3_handle *h);
void hns3_fini_ring(struct hns3_enet_ring *ring);
netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev);
bool hns3_is_phys_func(struct pci_dev *pdev);
int hns3_clean_rx_ring(
struct hns3_enet_ring *ring, int budget,
void (*rx_fn)(struct hns3_enet_ring *, struct sk_buff *));
void hns3_set_vector_coalesce_rx_gl(struct hns3_enet_tqp_vector *tqp_vector,
u32 gl_value);
void hns3_set_vector_coalesce_tx_gl(struct hns3_enet_tqp_vector *tqp_vector,
u32 gl_value);
void hns3_set_vector_coalesce_rl(struct hns3_enet_tqp_vector *tqp_vector,
u32 rl_value);
void hns3_set_vector_coalesce_rx_ql(struct hns3_enet_tqp_vector *tqp_vector,
u32 ql_value);
void hns3_set_vector_coalesce_tx_ql(struct hns3_enet_tqp_vector *tqp_vector,
u32 ql_value);
void hns3_request_update_promisc_mode(struct hnae3_handle *handle);
int hns3_reset_notify(struct hnae3_handle *handle,
enum hnae3_reset_notify_type type);
#ifdef CONFIG_HNS3_DCB
void hns3_dcbnl_setup(struct hnae3_handle *handle);
#else
static inline void hns3_dcbnl_setup(struct hnae3_handle *handle) {}
#endif
int hns3_dbg_init(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_unregister_debugfs(void);
void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size);
u16 hns3_get_max_available_channels(struct hnae3_handle *h);
void hns3_cq_period_mode_init(struct hns3_nic_priv *priv,
enum dim_cq_period_mode tx_mode,
enum dim_cq_period_mode rx_mode);
void hns3_external_lb_prepare(struct net_device *ndev, bool if_running);
void hns3_external_lb_restore(struct net_device *ndev, bool if_running);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2021 Hisilicon Limited.
#ifndef __HNS3_ETHTOOL_H
#define __HNS3_ETHTOOL_H
#include <linux/ethtool.h>
#include <linux/netdevice.h>
struct hns3_stats {
char stats_string[ETH_GSTRING_LEN];
int stats_offset;
};
struct hns3_sfp_type {
u8 type;
u8 ext_type;
};
struct hns3_pflag_desc {
char name[ETH_GSTRING_LEN];
void (*handler)(struct net_device *netdev, bool enable);
};
struct hns3_ethtool_link_ext_state_mapping {
u32 status_code;
enum ethtool_link_ext_state link_ext_state;
u8 link_ext_substate;
};
struct hns3_ring_param {
u32 tx_desc_num;
u32 rx_desc_num;
u32 rx_buf_len;
};
#endif
@@ -0,0 +1,138 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2019 Hisilicon Limited. */
/* This must be outside ifdef _HNS3_TRACE_H */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hns3
#if !defined(_HNS3_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _HNS3_TRACE_H_
#include <linux/tracepoint.h>
#define DESC_NR (sizeof(struct hns3_desc) / sizeof(u32))
DECLARE_EVENT_CLASS(hns3_skb_template,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb),
TP_STRUCT__entry(
__field(unsigned int, headlen)
__field(unsigned int, len)
__field(__u8, nr_frags)
__field(__u8, ip_summed)
__field(unsigned int, hdr_len)
__field(unsigned short, gso_size)
__field(unsigned short, gso_segs)
__field(unsigned int, gso_type)
__field(bool, fraglist)
__array(__u32, size, MAX_SKB_FRAGS)
),
TP_fast_assign(
__entry->headlen = skb_headlen(skb);
__entry->len = skb->len;
__entry->nr_frags = skb_shinfo(skb)->nr_frags;
__entry->gso_size = skb_shinfo(skb)->gso_size;
__entry->gso_segs = skb_shinfo(skb)->gso_segs;
__entry->gso_type = skb_shinfo(skb)->gso_type;
__entry->hdr_len = skb->encapsulation ?
skb_inner_tcp_all_headers(skb) : skb_tcp_all_headers(skb);
__entry->ip_summed = skb->ip_summed;
__entry->fraglist = skb_has_frag_list(skb);
hns3_shinfo_pack(skb_shinfo(skb), __entry->size);
),
TP_printk(
"len: %u, %u, %u, cs: %u, gso: %u, %u, %x, frag(%d %u): %s",
__entry->headlen, __entry->len, __entry->hdr_len,
__entry->ip_summed, __entry->gso_size, __entry->gso_segs,
__entry->gso_type, __entry->fraglist, __entry->nr_frags,
__print_array(__entry->size, MAX_SKB_FRAGS, sizeof(__u32))
)
);
DEFINE_EVENT(hns3_skb_template, hns3_over_max_bd,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb));
DEFINE_EVENT(hns3_skb_template, hns3_gro,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb));
DEFINE_EVENT(hns3_skb_template, hns3_tso,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb));
TRACE_EVENT(hns3_tx_desc,
TP_PROTO(struct hns3_enet_ring *ring, int cur_ntu),
TP_ARGS(ring, cur_ntu),
TP_STRUCT__entry(
__field(int, index)
__field(int, ntu)
__field(int, ntc)
__field(dma_addr_t, desc_dma)
__array(u32, desc, DESC_NR)
__string(devname, ring->tqp->handle->kinfo.netdev->name)
),
TP_fast_assign(
__entry->index = ring->tqp->tqp_index;
__entry->ntu = ring->next_to_use;
__entry->ntc = ring->next_to_clean;
__entry->desc_dma = ring->desc_dma_addr,
memcpy(__entry->desc, &ring->desc[cur_ntu],
sizeof(struct hns3_desc));
__assign_str(devname);
),
TP_printk(
"%s-%d-%d/%d desc(%pad): %s",
__get_str(devname), __entry->index, __entry->ntu,
__entry->ntc, &__entry->desc_dma,
__print_array(__entry->desc, DESC_NR, sizeof(u32))
)
);
TRACE_EVENT(hns3_rx_desc,
TP_PROTO(struct hns3_enet_ring *ring),
TP_ARGS(ring),
TP_STRUCT__entry(
__field(int, index)
__field(int, ntu)
__field(int, ntc)
__field(dma_addr_t, desc_dma)
__field(dma_addr_t, buf_dma)
__array(u32, desc, DESC_NR)
__string(devname, ring->tqp->handle->kinfo.netdev->name)
),
TP_fast_assign(
__entry->index = ring->tqp->tqp_index;
__entry->ntu = ring->next_to_use;
__entry->ntc = ring->next_to_clean;
__entry->desc_dma = ring->desc_dma_addr;
__entry->buf_dma = ring->desc_cb[ring->next_to_clean].dma;
memcpy(__entry->desc, &ring->desc[ring->next_to_clean],
sizeof(struct hns3_desc));
__assign_str(devname);
),
TP_printk(
"%s-%d-%d/%d desc(%pad) buf(%pad): %s",
__get_str(devname), __entry->index, __entry->ntu,
__entry->ntc, &__entry->desc_dma, &__entry->buf_dma,
__print_array(__entry->desc, DESC_NR, sizeof(u32))
)
);
#endif /* _HNS3_TRACE_H_ */
/* This must be outside ifdef _HNS3_TRACE_H */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE hns3_trace
#include <trace/define_trace.h>
@@ -0,0 +1,895 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2016-2017 Hisilicon Limited.
#ifndef __HCLGE_CMD_H
#define __HCLGE_CMD_H
#include <linux/types.h>
#include <linux/io.h>
#include <linux/etherdevice.h>
#include "hnae3.h"
#include "hclge_comm_cmd.h"
struct hclge_dev;
#define HCLGE_CMDQ_RX_INVLD_B 0
#define HCLGE_CMDQ_RX_OUTVLD_B 1
struct hclge_misc_vector {
u8 __iomem *addr;
int vector_irq;
char name[HNAE3_INT_NAME_LEN];
};
#define hclge_cmd_setup_basic_desc(desc, opcode, is_read) \
hclge_comm_cmd_setup_basic_desc(desc, opcode, is_read)
#define HCLGE_TQP_REG_OFFSET 0x80000
#define HCLGE_TQP_REG_SIZE 0x200
#define HCLGE_FD_COUNTER_MAX_SIZE_DEV_V2 128
#define HCLGE_TQP_MAX_SIZE_DEV_V2 1024
#define HCLGE_TQP_EXT_REG_OFFSET 0x100
#define HCLGE_RCB_INIT_QUERY_TIMEOUT 10
#define HCLGE_RCB_INIT_FLAG_EN_B 0
#define HCLGE_RCB_INIT_FLAG_FINI_B 8
struct hclge_config_rcb_init_cmd {
__le16 rcb_init_flag;
u8 rsv[22];
};
struct hclge_tqp_map_cmd {
__le16 tqp_id; /* Absolute tqp id for in this pf */
u8 tqp_vf; /* VF id */
#define HCLGE_TQP_MAP_TYPE_PF 0
#define HCLGE_TQP_MAP_TYPE_VF 1
#define HCLGE_TQP_MAP_TYPE_B 0
#define HCLGE_TQP_MAP_EN_B 1
u8 tqp_flag; /* Indicate it's pf or vf tqp */
__le16 tqp_vid; /* Virtual id in this pf/vf */
u8 rsv[18];
};
#define HCLGE_VECTOR_ELEMENTS_PER_CMD 10
enum hclge_int_type {
HCLGE_INT_TX,
HCLGE_INT_RX,
HCLGE_INT_EVENT,
};
struct hclge_ctrl_vector_chain_cmd {
#define HCLGE_VECTOR_ID_L_S 0
#define HCLGE_VECTOR_ID_L_M GENMASK(7, 0)
u8 int_vector_id_l;
u8 int_cause_num;
#define HCLGE_INT_TYPE_S 0
#define HCLGE_INT_TYPE_M GENMASK(1, 0)
#define HCLGE_TQP_ID_S 2
#define HCLGE_TQP_ID_M GENMASK(12, 2)
#define HCLGE_INT_GL_IDX_S 13
#define HCLGE_INT_GL_IDX_M GENMASK(14, 13)
__le16 tqp_type_and_id[HCLGE_VECTOR_ELEMENTS_PER_CMD];
u8 vfid;
#define HCLGE_VECTOR_ID_H_S 8
#define HCLGE_VECTOR_ID_H_M GENMASK(15, 8)
u8 int_vector_id_h;
};
#define HCLGE_MAX_TC_NUM 8
#define HCLGE_TC0_PRI_BUF_EN_B 15 /* Bit 15 indicate enable or not */
#define HCLGE_BUF_UNIT_S 7 /* Buf size is united by 128 bytes */
struct hclge_tx_buff_alloc_cmd {
__le16 tx_pkt_buff[HCLGE_MAX_TC_NUM];
u8 tx_buff_rsv[8];
};
struct hclge_rx_priv_buff_cmd {
__le16 buf_num[HCLGE_MAX_TC_NUM];
__le16 shared_buf;
u8 rsv[6];
};
#define HCLGE_RX_PRIV_EN_B 15
#define HCLGE_TC_NUM_ONE_DESC 4
struct hclge_priv_wl {
__le16 high;
__le16 low;
};
struct hclge_rx_priv_wl_buf {
struct hclge_priv_wl tc_wl[HCLGE_TC_NUM_ONE_DESC];
};
struct hclge_rx_com_thrd {
struct hclge_priv_wl com_thrd[HCLGE_TC_NUM_ONE_DESC];
};
struct hclge_rx_com_wl {
struct hclge_priv_wl com_wl;
};
struct hclge_waterline {
u32 low;
u32 high;
};
struct hclge_tc_thrd {
u32 low;
u32 high;
};
struct hclge_priv_buf {
struct hclge_waterline wl; /* Waterline for low and high */
u32 buf_size; /* TC private buffer size */
u32 tx_buf_size;
u32 enable; /* Enable TC private buffer or not */
};
struct hclge_shared_buf {
struct hclge_waterline self;
struct hclge_tc_thrd tc_thrd[HCLGE_MAX_TC_NUM];
u32 buf_size;
};
struct hclge_pkt_buf_alloc {
struct hclge_priv_buf priv_buf[HCLGE_MAX_TC_NUM];
struct hclge_shared_buf s_buf;
};
#define HCLGE_RX_COM_WL_EN_B 15
struct hclge_rx_com_wl_buf_cmd {
__le16 high_wl;
__le16 low_wl;
u8 rsv[20];
};
#define HCLGE_RX_PKT_EN_B 15
struct hclge_rx_pkt_buf_cmd {
__le16 high_pkt;
__le16 low_pkt;
u8 rsv[20];
};
#define HCLGE_PF_STATE_DONE_B 0
#define HCLGE_PF_STATE_MAIN_B 1
#define HCLGE_PF_STATE_BOND_B 2
#define HCLGE_PF_STATE_MAC_N_B 6
#define HCLGE_PF_MAC_NUM_MASK 0x3
#define HCLGE_PF_STATE_MAIN BIT(HCLGE_PF_STATE_MAIN_B)
#define HCLGE_PF_STATE_DONE BIT(HCLGE_PF_STATE_DONE_B)
#define HCLGE_VF_RST_STATUS_CMD 4
struct hclge_func_status_cmd {
__le32 vf_rst_state[HCLGE_VF_RST_STATUS_CMD];
u8 pf_state;
u8 mac_id;
u8 rsv1;
u8 pf_cnt_in_mac;
u8 pf_num;
u8 vf_num;
u8 rsv[2];
};
struct hclge_pf_res_cmd {
__le16 tqp_num;
__le16 buf_size;
__le16 msixcap_localid_ba_nic;
__le16 msixcap_localid_number_nic;
__le16 pf_intr_vector_number_roce;
__le16 pf_own_fun_number;
__le16 tx_buf_size;
__le16 dv_buf_size;
__le16 ext_tqp_num;
u8 rsv[6];
};
#define HCLGE_CFG_OFFSET_S 0
#define HCLGE_CFG_OFFSET_M GENMASK(19, 0)
#define HCLGE_CFG_RD_LEN_S 24
#define HCLGE_CFG_RD_LEN_M GENMASK(27, 24)
#define HCLGE_CFG_RD_LEN_BYTES 16
#define HCLGE_CFG_RD_LEN_UNIT 4
#define HCLGE_CFG_TC_NUM_S 8
#define HCLGE_CFG_TC_NUM_M GENMASK(15, 8)
#define HCLGE_CFG_TQP_DESC_N_S 16
#define HCLGE_CFG_TQP_DESC_N_M GENMASK(31, 16)
#define HCLGE_CFG_PHY_ADDR_S 0
#define HCLGE_CFG_PHY_ADDR_M GENMASK(7, 0)
#define HCLGE_CFG_MEDIA_TP_S 8
#define HCLGE_CFG_MEDIA_TP_M GENMASK(15, 8)
#define HCLGE_CFG_RX_BUF_LEN_S 16
#define HCLGE_CFG_RX_BUF_LEN_M GENMASK(31, 16)
#define HCLGE_CFG_MAC_ADDR_H_S 0
#define HCLGE_CFG_MAC_ADDR_H_M GENMASK(15, 0)
#define HCLGE_CFG_DEFAULT_SPEED_S 16
#define HCLGE_CFG_DEFAULT_SPEED_M GENMASK(23, 16)
#define HCLGE_CFG_RSS_SIZE_S 24
#define HCLGE_CFG_RSS_SIZE_M GENMASK(31, 24)
#define HCLGE_CFG_SPEED_ABILITY_S 0
#define HCLGE_CFG_SPEED_ABILITY_M GENMASK(7, 0)
#define HCLGE_CFG_SPEED_ABILITY_EXT_S 10
#define HCLGE_CFG_SPEED_ABILITY_EXT_M GENMASK(15, 10)
#define HCLGE_CFG_VLAN_FLTR_CAP_S 8
#define HCLGE_CFG_VLAN_FLTR_CAP_M GENMASK(9, 8)
#define HCLGE_CFG_UMV_TBL_SPACE_S 16
#define HCLGE_CFG_UMV_TBL_SPACE_M GENMASK(31, 16)
#define HCLGE_CFG_PF_RSS_SIZE_S 0
#define HCLGE_CFG_PF_RSS_SIZE_M GENMASK(3, 0)
#define HCLGE_CFG_TX_SPARE_BUF_SIZE_S 4
#define HCLGE_CFG_TX_SPARE_BUF_SIZE_M GENMASK(15, 4)
#define HCLGE_CFG_CMD_CNT 4
struct hclge_cfg_param_cmd {
__le32 offset;
__le32 rsv;
__le32 param[HCLGE_CFG_CMD_CNT];
};
#define HCLGE_MAC_MODE 0x0
#define HCLGE_DESC_NUM 0x40
#define HCLGE_ALLOC_VALID_B 0
struct hclge_vf_num_cmd {
u8 alloc_valid;
u8 rsv[23];
};
#define HCLGE_RSS_DEFAULT_OUTPORT_B 4
#define HCLGE_RSS_CFG_TBL_SIZE_H 4
#define HCLGE_RSS_CFG_TBL_BW_L 8U
#define HCLGE_RSS_TC_OFFSET_S 0
#define HCLGE_RSS_TC_OFFSET_M GENMASK(10, 0)
#define HCLGE_RSS_TC_SIZE_MSB_B 11
#define HCLGE_RSS_TC_SIZE_S 12
#define HCLGE_RSS_TC_SIZE_M GENMASK(14, 12)
#define HCLGE_RSS_TC_SIZE_MSB_OFFSET 3
#define HCLGE_RSS_TC_VALID_B 15
#define HCLGE_LINK_STATUS_UP_B 0
#define HCLGE_LINK_STATUS_UP_M BIT(HCLGE_LINK_STATUS_UP_B)
struct hclge_link_status_cmd {
u8 status;
u8 rsv[23];
};
/* for DEVICE_VERSION_V1/2, reference to promisc cmd byte8 */
#define HCLGE_PROMISC_EN_UC 1
#define HCLGE_PROMISC_EN_MC 2
#define HCLGE_PROMISC_EN_BC 3
#define HCLGE_PROMISC_TX_EN 4
#define HCLGE_PROMISC_RX_EN 5
/* for DEVICE_VERSION_V3, reference to promisc cmd byte10 */
#define HCLGE_PROMISC_UC_RX_EN 2
#define HCLGE_PROMISC_MC_RX_EN 3
#define HCLGE_PROMISC_BC_RX_EN 4
#define HCLGE_PROMISC_UC_TX_EN 5
#define HCLGE_PROMISC_MC_TX_EN 6
#define HCLGE_PROMISC_BC_TX_EN 7
struct hclge_promisc_cfg_cmd {
u8 promisc;
u8 vf_id;
u8 extend_promisc;
u8 rsv0[21];
};
enum hclge_promisc_type {
HCLGE_UNICAST = 1,
HCLGE_MULTICAST = 2,
HCLGE_BROADCAST = 3,
};
#define HCLGE_MAC_TX_EN_B 6
#define HCLGE_MAC_RX_EN_B 7
#define HCLGE_MAC_PAD_TX_B 11
#define HCLGE_MAC_PAD_RX_B 12
#define HCLGE_MAC_1588_TX_B 13
#define HCLGE_MAC_1588_RX_B 14
#define HCLGE_MAC_APP_LP_B 15
#define HCLGE_MAC_LINE_LP_B 16
#define HCLGE_MAC_FCS_TX_B 17
#define HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B 18
#define HCLGE_MAC_RX_FCS_STRIP_B 19
#define HCLGE_MAC_RX_FCS_B 20
#define HCLGE_MAC_TX_UNDER_MIN_ERR_B 21
#define HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B 22
struct hclge_config_mac_mode_cmd {
__le32 txrx_pad_fcs_loop_en;
u8 rsv[20];
};
struct hclge_pf_rst_sync_cmd {
#define HCLGE_PF_RST_ALL_VF_RDY_B 0
u8 all_vf_ready;
u8 rsv[23];
};
#define HCLGE_CFG_SPEED_S 0
#define HCLGE_CFG_SPEED_M GENMASK(5, 0)
#define HCLGE_CFG_DUPLEX_B 7
#define HCLGE_CFG_DUPLEX_M BIT(HCLGE_CFG_DUPLEX_B)
struct hclge_config_mac_speed_dup_cmd {
u8 speed_dup;
#define HCLGE_CFG_MAC_SPEED_CHANGE_EN_B 0
u8 mac_change_fec_en;
u8 rsv[4];
u8 lane_num;
u8 rsv1[17];
};
#define HCLGE_TQP_ENABLE_B 0
#define HCLGE_MAC_CFG_AN_EN_B 0
#define HCLGE_MAC_CFG_AN_INT_EN_B 1
#define HCLGE_MAC_CFG_AN_INT_MSK_B 2
#define HCLGE_MAC_CFG_AN_INT_CLR_B 3
#define HCLGE_MAC_CFG_AN_RST_B 4
#define HCLGE_MAC_CFG_AN_EN BIT(HCLGE_MAC_CFG_AN_EN_B)
struct hclge_config_auto_neg_cmd {
__le32 cfg_an_cmd_flag;
u8 rsv[20];
};
struct hclge_sfp_info_cmd {
__le32 speed;
u8 query_type; /* 0: sfp speed, 1: active speed */
u8 active_fec;
u8 autoneg; /* autoneg state */
u8 autoneg_ability; /* whether support autoneg */
__le32 speed_ability; /* speed ability for current media */
__le32 module_type;
u8 fec_ability;
u8 lane_num;
u8 rsv[6];
};
#define HCLGE_MAC_CFG_FEC_AUTO_EN_B 0
#define HCLGE_MAC_CFG_FEC_MODE_S 1
#define HCLGE_MAC_CFG_FEC_MODE_M GENMASK(3, 1)
#define HCLGE_MAC_CFG_FEC_SET_DEF_B 0
#define HCLGE_MAC_CFG_FEC_CLR_DEF_B 1
#define HCLGE_MAC_FEC_OFF 0
#define HCLGE_MAC_FEC_BASER 1
#define HCLGE_MAC_FEC_RS 2
#define HCLGE_MAC_FEC_LLRS 3
struct hclge_config_fec_cmd {
u8 fec_mode;
u8 default_config;
u8 rsv[22];
};
#define HCLGE_FEC_STATS_CMD_NUM 4
struct hclge_query_fec_stats_cmd {
/* fec rs mode total stats */
__le32 rs_fec_corr_blocks;
__le32 rs_fec_uncorr_blocks;
__le32 rs_fec_error_blocks;
/* fec base-r mode per lanes stats */
u8 base_r_lane_num;
u8 rsv[3];
__le32 base_r_fec_corr_blocks;
__le32 base_r_fec_uncorr_blocks;
};
#define HCLGE_MAC_UPLINK_PORT 0x100
struct hclge_config_max_frm_size_cmd {
__le16 max_frm_size;
u8 min_frm_size;
u8 rsv[21];
};
enum hclge_mac_vlan_tbl_opcode {
HCLGE_MAC_VLAN_ADD, /* Add new or modify mac_vlan */
HCLGE_MAC_VLAN_UPDATE, /* Modify other fields of this table */
HCLGE_MAC_VLAN_REMOVE, /* Remove a entry through mac_vlan key */
HCLGE_MAC_VLAN_LKUP, /* Lookup a entry through mac_vlan key */
};
enum hclge_mac_vlan_add_resp_code {
HCLGE_ADD_UC_OVERFLOW = 2, /* ADD failed for UC overflow */
HCLGE_ADD_MC_OVERFLOW, /* ADD failed for MC overflow */
};
#define HCLGE_MAC_VLAN_BIT0_EN_B 0
#define HCLGE_MAC_VLAN_BIT1_EN_B 1
#define HCLGE_MAC_EPORT_SW_EN_B 12
#define HCLGE_MAC_EPORT_TYPE_B 11
#define HCLGE_MAC_EPORT_VFID_S 3
#define HCLGE_MAC_EPORT_VFID_M GENMASK(10, 3)
#define HCLGE_MAC_EPORT_PFID_S 0
#define HCLGE_MAC_EPORT_PFID_M GENMASK(2, 0)
struct hclge_mac_vlan_tbl_entry_cmd {
u8 flags;
u8 resp_code;
__le16 vlan_tag;
__le32 mac_addr_hi32;
__le16 mac_addr_lo16;
__le16 rsv1;
u8 entry_type;
u8 mc_mac_en;
__le16 egress_port;
__le16 egress_queue;
u8 rsv2[6];
};
#define HCLGE_UMV_SPC_ALC_B 0
struct hclge_umv_spc_alc_cmd {
u8 allocate;
u8 rsv1[3];
__le32 space_size;
u8 rsv2[16];
};
#define HCLGE_MAC_MGR_MASK_VLAN_B BIT(0)
#define HCLGE_MAC_MGR_MASK_MAC_B BIT(1)
#define HCLGE_MAC_MGR_MASK_ETHERTYPE_B BIT(2)
struct hclge_mac_mgr_tbl_entry_cmd {
u8 flags;
u8 resp_code;
__le16 vlan_tag;
u8 mac_addr[ETH_ALEN];
__le16 rsv1;
__le16 ethter_type;
__le16 egress_port;
__le16 egress_queue;
u8 sw_port_id_aware;
u8 rsv2;
u8 i_port_bitmap;
u8 i_port_direction;
u8 rsv3[2];
};
struct hclge_vlan_filter_ctrl_cmd {
u8 vlan_type;
u8 vlan_fe;
u8 rsv1[2];
u8 vf_id;
u8 rsv2[19];
};
#define HCLGE_VLAN_ID_OFFSET_STEP 160
#define HCLGE_VLAN_BYTE_SIZE 8
#define HCLGE_VLAN_OFFSET_BITMAP \
(HCLGE_VLAN_ID_OFFSET_STEP / HCLGE_VLAN_BYTE_SIZE)
struct hclge_vlan_filter_pf_cfg_cmd {
u8 vlan_offset;
u8 vlan_cfg;
u8 rsv[2];
u8 vlan_offset_bitmap[HCLGE_VLAN_OFFSET_BITMAP];
};
#define HCLGE_MAX_VF_BYTES 16
struct hclge_vlan_filter_vf_cfg_cmd {
__le16 vlan_id;
u8 resp_code;
u8 rsv;
u8 vlan_cfg;
u8 rsv1[3];
u8 vf_bitmap[HCLGE_MAX_VF_BYTES];
};
#define HCLGE_INGRESS_BYPASS_B 0
struct hclge_port_vlan_filter_bypass_cmd {
u8 bypass_state;
u8 rsv1[3];
u8 vf_id;
u8 rsv2[19];
};
#define HCLGE_SWITCH_ANTI_SPOOF_B 0U
#define HCLGE_SWITCH_ALW_LPBK_B 1U
#define HCLGE_SWITCH_ALW_LCL_LPBK_B 2U
#define HCLGE_SWITCH_ALW_DST_OVRD_B 3U
#define HCLGE_SWITCH_NO_MASK 0x0
#define HCLGE_SWITCH_ANTI_SPOOF_MASK 0xFE
#define HCLGE_SWITCH_ALW_LPBK_MASK 0xFD
#define HCLGE_SWITCH_ALW_LCL_LPBK_MASK 0xFB
#define HCLGE_SWITCH_LW_DST_OVRD_MASK 0xF7
struct hclge_mac_vlan_switch_cmd {
u8 roce_sel;
u8 rsv1[3];
__le32 func_id;
u8 switch_param;
u8 rsv2[3];
u8 param_mask;
u8 rsv3[11];
};
enum hclge_mac_vlan_cfg_sel {
HCLGE_MAC_VLAN_NIC_SEL = 0,
HCLGE_MAC_VLAN_ROCE_SEL,
};
#define HCLGE_ACCEPT_TAG1_B 0
#define HCLGE_ACCEPT_UNTAG1_B 1
#define HCLGE_PORT_INS_TAG1_EN_B 2
#define HCLGE_PORT_INS_TAG2_EN_B 3
#define HCLGE_CFG_NIC_ROCE_SEL_B 4
#define HCLGE_ACCEPT_TAG2_B 5
#define HCLGE_ACCEPT_UNTAG2_B 6
#define HCLGE_TAG_SHIFT_MODE_EN_B 7
#define HCLGE_VF_NUM_PER_BYTE 8
struct hclge_vport_vtag_tx_cfg_cmd {
u8 vport_vlan_cfg;
u8 vf_offset;
u8 rsv1[2];
__le16 def_vlan_tag1;
__le16 def_vlan_tag2;
u8 vf_bitmap[HCLGE_VF_NUM_PER_BYTE];
u8 rsv2[8];
};
#define HCLGE_REM_TAG1_EN_B 0
#define HCLGE_REM_TAG2_EN_B 1
#define HCLGE_SHOW_TAG1_EN_B 2
#define HCLGE_SHOW_TAG2_EN_B 3
#define HCLGE_DISCARD_TAG1_EN_B 5
#define HCLGE_DISCARD_TAG2_EN_B 6
struct hclge_vport_vtag_rx_cfg_cmd {
u8 vport_vlan_cfg;
u8 vf_offset;
u8 rsv1[6];
u8 vf_bitmap[HCLGE_VF_NUM_PER_BYTE];
u8 rsv2[8];
};
struct hclge_tx_vlan_type_cfg_cmd {
__le16 ot_vlan_type;
__le16 in_vlan_type;
u8 rsv[20];
};
struct hclge_rx_vlan_type_cfg_cmd {
__le16 ot_fst_vlan_type;
__le16 ot_sec_vlan_type;
__le16 in_fst_vlan_type;
__le16 in_sec_vlan_type;
u8 rsv[16];
};
struct hclge_cfg_com_tqp_queue_cmd {
__le16 tqp_id;
__le16 stream_id;
u8 enable;
u8 rsv[19];
};
struct hclge_cfg_tx_queue_pointer_cmd {
__le16 tqp_id;
__le16 tx_tail;
__le16 tx_head;
__le16 fbd_num;
__le16 ring_offset;
u8 rsv[14];
};
#pragma pack(1)
struct hclge_mac_ethertype_idx_rd_cmd {
u8 flags;
u8 resp_code;
__le16 vlan_tag;
u8 mac_addr[ETH_ALEN];
__le16 index;
__le16 ethter_type;
__le16 egress_port;
__le16 egress_queue;
__le16 rev0;
u8 i_port_bitmap;
u8 i_port_direction;
u8 rev1[2];
};
#pragma pack()
#define HCLGE_TSO_MSS_MIN_S 0
#define HCLGE_TSO_MSS_MIN_M GENMASK(13, 0)
#define HCLGE_TSO_MSS_MAX_S 16
#define HCLGE_TSO_MSS_MAX_M GENMASK(29, 16)
struct hclge_cfg_tso_status_cmd {
__le16 tso_mss_min;
__le16 tso_mss_max;
u8 rsv[20];
};
#define HCLGE_GRO_EN_B 0
struct hclge_cfg_gro_status_cmd {
u8 gro_en;
u8 rsv[23];
};
#define HCLGE_TSO_MSS_MIN 256
#define HCLGE_TSO_MSS_MAX 9668
#define HCLGE_TQP_RESET_B 0
struct hclge_reset_tqp_queue_cmd {
__le16 tqp_id;
u8 reset_req;
u8 ready_to_reset;
u8 rsv[20];
};
#define HCLGE_CFG_RESET_MAC_B 3
#define HCLGE_CFG_RESET_FUNC_B 7
#define HCLGE_CFG_RESET_RCB_B 1
struct hclge_reset_cmd {
u8 mac_func_reset;
u8 fun_reset_vfid;
u8 fun_reset_rcb;
u8 rsv;
__le16 fun_reset_rcb_vqid_start;
__le16 fun_reset_rcb_vqid_num;
u8 fun_reset_rcb_return_status;
u8 rsv1[15];
};
#define HCLGE_PF_RESET_DONE_BIT BIT(0)
struct hclge_pf_rst_done_cmd {
u8 pf_rst_done;
u8 rsv[23];
};
#define HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B BIT(0)
#define HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B BIT(2)
#define HCLGE_CMD_GE_PHY_INNER_LOOP_B BIT(3)
#define HCLGE_CMD_COMMON_LB_DONE_B BIT(0)
#define HCLGE_CMD_COMMON_LB_SUCCESS_B BIT(1)
struct hclge_common_lb_cmd {
u8 mask;
u8 enable;
u8 result;
u8 rsv[21];
};
#define HCLGE_DEFAULT_TX_BUF 0x4000 /* 16k bytes */
#define HCLGE_TOTAL_PKT_BUF 0x108000 /* 1.03125M bytes */
#define HCLGE_DEFAULT_DV 0xA000 /* 40k byte */
#define HCLGE_DEFAULT_NON_DCB_DV 0x7800 /* 30K byte */
#define HCLGE_NON_DCB_ADDITIONAL_BUF 0x1400 /* 5120 byte */
#define HCLGE_LED_LOCATE_STATE_S 0
#define HCLGE_LED_LOCATE_STATE_M GENMASK(1, 0)
struct hclge_set_led_state_cmd {
u8 rsv1[3];
u8 locate_led_config;
u8 rsv2[20];
};
struct hclge_get_fd_mode_cmd {
u8 mode;
u8 enable;
u8 rsv[22];
};
struct hclge_get_fd_allocation_cmd {
__le32 stage1_entry_num;
__le32 stage2_entry_num;
__le16 stage1_counter_num;
__le16 stage2_counter_num;
u8 rsv[12];
};
struct hclge_set_fd_key_config_cmd {
u8 stage;
u8 key_select;
u8 inner_sipv6_word_en;
u8 inner_dipv6_word_en;
u8 outer_sipv6_word_en;
u8 outer_dipv6_word_en;
u8 rsv1[2];
__le32 tuple_mask;
__le32 meta_data_mask;
u8 rsv2[8];
};
#define HCLGE_FD_EPORT_SW_EN_B 0
struct hclge_fd_tcam_config_1_cmd {
u8 stage;
u8 xy_sel;
u8 port_info;
u8 rsv1[1];
__le32 index;
u8 entry_vld;
u8 rsv2[7];
u8 tcam_data[8];
};
struct hclge_fd_tcam_config_2_cmd {
u8 tcam_data[24];
};
struct hclge_fd_tcam_config_3_cmd {
u8 tcam_data[20];
u8 rsv[4];
};
#define HCLGE_FD_AD_DROP_B 0
#define HCLGE_FD_AD_DIRECT_QID_B 1
#define HCLGE_FD_AD_QID_L_S 2
#define HCLGE_FD_AD_QID_L_M GENMASK(11, 2)
#define HCLGE_FD_AD_USE_COUNTER_B 12
#define HCLGE_FD_AD_COUNTER_NUM_L_S 13
#define HCLGE_FD_AD_COUNTER_NUM_L_M GENMASK(19, 13)
#define HCLGE_FD_AD_NXT_STEP_B 20
#define HCLGE_FD_AD_NXT_KEY_S 21
#define HCLGE_FD_AD_NXT_KEY_M GENMASK(25, 21)
#define HCLGE_FD_AD_WR_RULE_ID_B 0
#define HCLGE_FD_AD_RULE_ID_S 1
#define HCLGE_FD_AD_RULE_ID_M GENMASK(12, 1)
#define HCLGE_FD_AD_TC_OVRD_B 16
#define HCLGE_FD_AD_TC_SIZE_S 17
#define HCLGE_FD_AD_TC_SIZE_M GENMASK(20, 17)
#define HCLGE_FD_AD_QID_H_B 21
#define HCLGE_FD_AD_COUNTER_NUM_H_B 26
struct hclge_fd_ad_config_cmd {
u8 stage;
u8 rsv1[3];
__le32 index;
__le64 ad_data;
u8 rsv2[8];
};
struct hclge_fd_ad_cnt_read_cmd {
u8 rsv0[4];
__le16 index;
u8 rsv1[2];
__le64 cnt;
u8 rsv2[8];
};
#define HCLGE_FD_USER_DEF_OFT_S 0
#define HCLGE_FD_USER_DEF_OFT_M GENMASK(14, 0)
#define HCLGE_FD_USER_DEF_EN_B 15
struct hclge_fd_user_def_cfg_cmd {
__le16 ol2_cfg;
__le16 l2_cfg;
__le16 ol3_cfg;
__le16 l3_cfg;
__le16 ol4_cfg;
__le16 l4_cfg;
u8 rsv[12];
};
struct hclge_get_imp_bd_cmd {
__le32 bd_num;
u8 rsv[20];
};
struct hclge_query_ppu_pf_other_int_dfx_cmd {
__le16 over_8bd_no_fe_qid;
__le16 over_8bd_no_fe_vf_id;
__le16 tso_mss_cmp_min_err_qid;
__le16 tso_mss_cmp_min_err_vf_id;
__le16 tso_mss_cmp_max_err_qid;
__le16 tso_mss_cmp_max_err_vf_id;
__le16 tx_rd_fbd_poison_qid;
__le16 tx_rd_fbd_poison_vf_id;
__le16 rx_rd_fbd_poison_qid;
__le16 rx_rd_fbd_poison_vf_id;
u8 rsv[4];
};
#define HCLGE_SFP_INFO_CMD_NUM 6
#define HCLGE_SFP_INFO_BD0_LEN 20
#define HCLGE_SFP_INFO_BDX_LEN 24
#define HCLGE_SFP_INFO_MAX_LEN \
(HCLGE_SFP_INFO_BD0_LEN + \
(HCLGE_SFP_INFO_CMD_NUM - 1) * HCLGE_SFP_INFO_BDX_LEN)
struct hclge_sfp_info_bd0_cmd {
__le16 offset;
__le16 read_len;
u8 data[HCLGE_SFP_INFO_BD0_LEN];
};
#define HCLGE_QUERY_DEV_SPECS_BD_NUM 4
struct hclge_dev_specs_0_cmd {
__le32 rsv0;
__le32 mac_entry_num;
__le32 mng_entry_num;
__le16 rss_ind_tbl_size;
__le16 rss_key_size;
__le16 int_ql_max;
u8 max_non_tso_bd_num;
u8 rsv1;
__le32 max_tm_rate;
};
#define HCLGE_DEF_MAX_INT_GL 0x1FE0U
struct hclge_dev_specs_1_cmd {
__le16 max_frm_size;
__le16 max_qset_num;
__le16 max_int_gl;
u8 rsv0[2];
__le16 umv_size;
__le16 mc_mac_size;
u8 rsv1[6];
u8 tnl_num;
u8 hilink_version;
u8 rsv2[4];
};
/* mac speed type defined in firmware command */
enum HCLGE_FIRMWARE_MAC_SPEED {
HCLGE_FW_MAC_SPEED_1G,
HCLGE_FW_MAC_SPEED_10G,
HCLGE_FW_MAC_SPEED_25G,
HCLGE_FW_MAC_SPEED_40G,
HCLGE_FW_MAC_SPEED_50G,
HCLGE_FW_MAC_SPEED_100G,
HCLGE_FW_MAC_SPEED_10M,
HCLGE_FW_MAC_SPEED_100M,
HCLGE_FW_MAC_SPEED_200G,
};
#define HCLGE_PHY_LINK_SETTING_BD_NUM 2
struct hclge_phy_link_ksetting_0_cmd {
__le32 speed;
u8 duplex;
u8 autoneg;
u8 eth_tp_mdix;
u8 eth_tp_mdix_ctrl;
u8 port;
u8 transceiver;
u8 phy_address;
u8 rsv;
__le32 supported;
__le32 advertising;
__le32 lp_advertising;
};
struct hclge_phy_link_ksetting_1_cmd {
u8 master_slave_cfg;
u8 master_slave_state;
u8 rsv[22];
};
struct hclge_phy_reg_cmd {
__le16 reg_addr;
u8 rsv0[2];
__le16 reg_val;
u8 rsv1[18];
};
struct hclge_wol_cfg_cmd {
__le32 wake_on_lan_mode;
u8 sopass[SOPASS_MAX];
u8 sopass_size;
u8 rsv[13];
};
struct hclge_query_wol_supported_cmd {
__le32 supported_wake_mode;
u8 rsv[20];
};
struct hclge_hw;
int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num);
#endif
@@ -0,0 +1,682 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hclge_main.h"
#include "hclge_dcb.h"
#include "hclge_tm.h"
#include "hnae3.h"
#define BW_PERCENT 100
static int hclge_ieee_ets_to_tm_info(struct hclge_dev *hdev,
struct ieee_ets *ets)
{
u8 i;
for (i = 0; i < HNAE3_MAX_TC; i++) {
switch (ets->tc_tsa[i]) {
case IEEE_8021QAZ_TSA_STRICT:
hdev->tm_info.tc_info[i].tc_sch_mode =
HCLGE_SCH_MODE_SP;
hdev->tm_info.pg_info[0].tc_dwrr[i] = 0;
break;
case IEEE_8021QAZ_TSA_ETS:
hdev->tm_info.tc_info[i].tc_sch_mode =
HCLGE_SCH_MODE_DWRR;
hdev->tm_info.pg_info[0].tc_dwrr[i] =
ets->tc_tx_bw[i];
break;
default:
/* Hardware only supports SP (strict priority)
* or ETS (enhanced transmission selection)
* algorithms, if we receive some other value
* from dcbnl, then throw an error.
*/
return -EINVAL;
}
}
hclge_tm_prio_tc_info_update(hdev, ets->prio_tc);
return 0;
}
static void hclge_tm_info_to_ieee_ets(struct hclge_dev *hdev,
struct ieee_ets *ets)
{
u32 i;
memset(ets, 0, sizeof(*ets));
ets->willing = 1;
ets->ets_cap = hdev->tc_max;
for (i = 0; i < HNAE3_MAX_TC; i++) {
ets->prio_tc[i] = hdev->tm_info.prio_tc[i];
if (i < hdev->tm_info.num_tc)
ets->tc_tx_bw[i] = hdev->tm_info.pg_info[0].tc_dwrr[i];
else
ets->tc_tx_bw[i] = 0;
if (hdev->tm_info.tc_info[i].tc_sch_mode ==
HCLGE_SCH_MODE_SP)
ets->tc_tsa[i] = IEEE_8021QAZ_TSA_STRICT;
else
ets->tc_tsa[i] = IEEE_8021QAZ_TSA_ETS;
}
}
/* IEEE std */
static int hclge_ieee_getets(struct hnae3_handle *h, struct ieee_ets *ets)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
hclge_tm_info_to_ieee_ets(hdev, ets);
return 0;
}
static int hclge_dcb_common_validate(struct hclge_dev *hdev, u8 num_tc,
u8 *prio_tc)
{
int i;
if (num_tc > hdev->tc_max) {
dev_err(&hdev->pdev->dev,
"tc num checking failed, %u > tc_max(%u)\n",
num_tc, hdev->tc_max);
return -EINVAL;
}
for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) {
if (prio_tc[i] >= num_tc) {
dev_err(&hdev->pdev->dev,
"prio_tc[%d] checking failed, %u >= num_tc(%u)\n",
i, prio_tc[i], num_tc);
return -EINVAL;
}
}
if (num_tc > hdev->vport[0].alloc_tqps) {
dev_err(&hdev->pdev->dev,
"allocated tqp checking failed, %u > tqp(%u)\n",
num_tc, hdev->vport[0].alloc_tqps);
return -EINVAL;
}
return 0;
}
static u8 hclge_ets_tc_changed(struct hclge_dev *hdev, struct ieee_ets *ets,
bool *changed)
{
u8 max_tc_id = 0;
u8 i;
for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) {
if (ets->prio_tc[i] != hdev->tm_info.prio_tc[i])
*changed = true;
if (ets->prio_tc[i] > max_tc_id)
max_tc_id = ets->prio_tc[i];
}
/* return max tc number, max tc id need to plus 1 */
return max_tc_id + 1;
}
static int hclge_ets_sch_mode_validate(struct hclge_dev *hdev,
struct ieee_ets *ets, bool *changed,
u8 tc_num)
{
bool has_ets_tc = false;
u32 total_ets_bw = 0;
u8 i;
for (i = 0; i < HNAE3_MAX_TC; i++) {
switch (ets->tc_tsa[i]) {
case IEEE_8021QAZ_TSA_STRICT:
if (hdev->tm_info.tc_info[i].tc_sch_mode !=
HCLGE_SCH_MODE_SP)
*changed = true;
break;
case IEEE_8021QAZ_TSA_ETS:
if (i >= tc_num) {
dev_err(&hdev->pdev->dev,
"tc%u is disabled, cannot set ets bw\n",
i);
return -EINVAL;
}
/* The hardware will switch to sp mode if bandwidth is
* 0, so limit ets bandwidth must be greater than 0.
*/
if (!ets->tc_tx_bw[i]) {
dev_err(&hdev->pdev->dev,
"tc%u ets bw cannot be 0\n", i);
return -EINVAL;
}
if (hdev->tm_info.tc_info[i].tc_sch_mode !=
HCLGE_SCH_MODE_DWRR)
*changed = true;
total_ets_bw += ets->tc_tx_bw[i];
has_ets_tc = true;
break;
default:
return -EINVAL;
}
}
if (has_ets_tc && total_ets_bw != BW_PERCENT)
return -EINVAL;
return 0;
}
static int hclge_ets_validate(struct hclge_dev *hdev, struct ieee_ets *ets,
u8 *tc, bool *changed)
{
u8 tc_num;
int ret;
tc_num = hclge_ets_tc_changed(hdev, ets, changed);
ret = hclge_dcb_common_validate(hdev, tc_num, ets->prio_tc);
if (ret)
return ret;
ret = hclge_ets_sch_mode_validate(hdev, ets, changed, tc_num);
if (ret)
return ret;
*tc = tc_num;
if (*tc != hdev->tm_info.num_tc)
*changed = true;
return 0;
}
static int hclge_map_update(struct hclge_dev *hdev)
{
int ret;
ret = hclge_tm_schd_setup_hw(hdev);
if (ret)
return ret;
ret = hclge_pause_setup_hw(hdev, false);
if (ret)
return ret;
ret = hclge_buffer_alloc(hdev);
if (ret)
return ret;
hclge_comm_rss_indir_init_cfg(hdev->ae_dev, &hdev->rss_cfg);
return hclge_rss_init_hw(hdev);
}
static int hclge_notify_down_uinit(struct hclge_dev *hdev)
{
int ret;
ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
if (ret)
return ret;
ret = hclge_tm_flush_cfg(hdev, true);
if (ret)
return ret;
return hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT);
}
static int hclge_notify_init_up(struct hclge_dev *hdev)
{
int ret;
ret = hclge_notify_client(hdev, HNAE3_INIT_CLIENT);
if (ret)
return ret;
ret = hclge_tm_flush_cfg(hdev, false);
if (ret)
return ret;
return hclge_notify_client(hdev, HNAE3_UP_CLIENT);
}
static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct net_device *netdev = h->kinfo.netdev;
struct hclge_dev *hdev = vport->back;
bool map_changed = false;
u8 num_tc = 0;
int ret;
if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
h->kinfo.tc_info.mqprio_active)
return -EINVAL;
ret = hclge_ets_validate(hdev, ets, &num_tc, &map_changed);
if (ret)
return ret;
if (map_changed) {
netif_dbg(h, drv, netdev, "set ets\n");
ret = hclge_notify_down_uinit(hdev);
if (ret)
return ret;
}
hclge_tm_schd_info_update(hdev, num_tc);
h->kinfo.tc_info.dcb_ets_active = num_tc > 1;
ret = hclge_ieee_ets_to_tm_info(hdev, ets);
if (ret)
goto err_out;
if (map_changed) {
ret = hclge_map_update(hdev);
if (ret)
goto err_out;
return hclge_notify_init_up(hdev);
}
return hclge_tm_dwrr_cfg(hdev);
err_out:
if (!map_changed)
return ret;
hclge_notify_init_up(hdev);
return ret;
}
static int hclge_ieee_getpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
int ret;
memset(pfc, 0, sizeof(*pfc));
pfc->pfc_cap = hdev->pfc_max;
pfc->pfc_en = hdev->tm_info.pfc_en;
ret = hclge_mac_update_stats(hdev);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to update MAC stats, ret = %d.\n", ret);
return ret;
}
hclge_pfc_tx_stats_get(hdev, pfc->requests);
hclge_pfc_rx_stats_get(hdev, pfc->indications);
return 0;
}
static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct net_device *netdev = h->kinfo.netdev;
struct hclge_dev *hdev = vport->back;
u8 i, j, pfc_map, *prio_tc;
int last_bad_ret = 0;
int ret;
if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
if (pfc->pfc_en == hdev->tm_info.pfc_en)
return 0;
prio_tc = hdev->tm_info.prio_tc;
pfc_map = 0;
for (i = 0; i < hdev->tm_info.num_tc; i++) {
for (j = 0; j < HNAE3_MAX_USER_PRIO; j++) {
if ((prio_tc[j] == i) && (pfc->pfc_en & BIT(j))) {
pfc_map |= BIT(i);
break;
}
}
}
hdev->tm_info.hw_pfc_map = pfc_map;
hdev->tm_info.pfc_en = pfc->pfc_en;
netif_dbg(h, drv, netdev,
"set pfc: pfc_en=%x, pfc_map=%x, num_tc=%u\n",
pfc->pfc_en, pfc_map, hdev->tm_info.num_tc);
hclge_tm_pfc_info_update(hdev);
ret = hclge_pause_setup_hw(hdev, false);
if (ret)
return ret;
ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
if (ret)
return ret;
ret = hclge_tm_flush_cfg(hdev, true);
if (ret)
return ret;
/* No matter whether the following operations are performed
* successfully or not, disabling the tm flush and notify
* the network status to up are necessary.
* Do not return immediately.
*/
ret = hclge_buffer_alloc(hdev);
if (ret)
last_bad_ret = ret;
ret = hclge_tm_flush_cfg(hdev, false);
if (ret)
last_bad_ret = ret;
ret = hclge_notify_client(hdev, HNAE3_UP_CLIENT);
if (ret)
last_bad_ret = ret;
return last_bad_ret;
}
static int hclge_ieee_setapp(struct hnae3_handle *h, struct dcb_app *app)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct net_device *netdev = h->kinfo.netdev;
struct hclge_dev *hdev = vport->back;
struct dcb_app old_app;
int ret;
if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP ||
app->protocol >= HNAE3_MAX_DSCP ||
app->priority >= HNAE3_MAX_USER_PRIO)
return -EINVAL;
dev_info(&hdev->pdev->dev, "setapp dscp=%u priority=%u\n",
app->protocol, app->priority);
if (app->priority == h->kinfo.dscp_prio[app->protocol])
return 0;
ret = dcb_ieee_setapp(netdev, app);
if (ret)
return ret;
old_app.selector = IEEE_8021QAZ_APP_SEL_DSCP;
old_app.protocol = app->protocol;
old_app.priority = h->kinfo.dscp_prio[app->protocol];
h->kinfo.dscp_prio[app->protocol] = app->priority;
ret = hclge_dscp_to_tc_map(hdev);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to set dscp to tc map, ret = %d\n", ret);
h->kinfo.dscp_prio[app->protocol] = old_app.priority;
(void)dcb_ieee_delapp(netdev, app);
return ret;
}
vport->nic.kinfo.tc_map_mode = HNAE3_TC_MAP_MODE_DSCP;
if (old_app.priority == HNAE3_PRIO_ID_INVALID)
h->kinfo.dscp_app_cnt++;
else
ret = dcb_ieee_delapp(netdev, &old_app);
return ret;
}
static int hclge_ieee_delapp(struct hnae3_handle *h, struct dcb_app *app)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct net_device *netdev = h->kinfo.netdev;
struct hclge_dev *hdev = vport->back;
int ret;
if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP ||
app->protocol >= HNAE3_MAX_DSCP ||
app->priority >= HNAE3_MAX_USER_PRIO ||
app->priority != h->kinfo.dscp_prio[app->protocol])
return -EINVAL;
dev_info(&hdev->pdev->dev, "delapp dscp=%u priority=%u\n",
app->protocol, app->priority);
ret = dcb_ieee_delapp(netdev, app);
if (ret)
return ret;
h->kinfo.dscp_prio[app->protocol] = HNAE3_PRIO_ID_INVALID;
ret = hclge_dscp_to_tc_map(hdev);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to del dscp to tc map, ret = %d\n", ret);
h->kinfo.dscp_prio[app->protocol] = app->priority;
(void)dcb_ieee_setapp(netdev, app);
return ret;
}
if (h->kinfo.dscp_app_cnt)
h->kinfo.dscp_app_cnt--;
if (!h->kinfo.dscp_app_cnt) {
vport->nic.kinfo.tc_map_mode = HNAE3_TC_MAP_MODE_PRIO;
ret = hclge_up_to_tc_map(hdev);
}
return ret;
}
/* DCBX configuration */
static u8 hclge_getdcbx(struct hnae3_handle *h)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
if (h->kinfo.tc_info.mqprio_active)
return 0;
return hdev->dcbx_cap;
}
static u8 hclge_setdcbx(struct hnae3_handle *h, u8 mode)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct net_device *netdev = h->kinfo.netdev;
struct hclge_dev *hdev = vport->back;
netif_dbg(h, drv, netdev, "set dcbx: mode=%u\n", mode);
/* No support for LLD_MANAGED modes or CEE */
if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
(mode & DCB_CAP_DCBX_VER_CEE) ||
!(mode & DCB_CAP_DCBX_HOST))
return 1;
hdev->dcbx_cap = mode;
return 0;
}
static int hclge_mqprio_qopt_check(struct hclge_dev *hdev,
struct tc_mqprio_qopt_offload *mqprio_qopt)
{
u16 queue_sum = 0;
int ret;
int i;
if (!mqprio_qopt->qopt.num_tc) {
mqprio_qopt->qopt.num_tc = 1;
return 0;
}
ret = hclge_dcb_common_validate(hdev, mqprio_qopt->qopt.num_tc,
mqprio_qopt->qopt.prio_tc_map);
if (ret)
return ret;
for (i = 0; i < mqprio_qopt->qopt.num_tc; i++) {
if (!is_power_of_2(mqprio_qopt->qopt.count[i])) {
dev_err(&hdev->pdev->dev,
"qopt queue count must be power of 2\n");
return -EINVAL;
}
if (mqprio_qopt->qopt.count[i] > hdev->pf_rss_size_max) {
dev_err(&hdev->pdev->dev,
"qopt queue count should be no more than %u\n",
hdev->pf_rss_size_max);
return -EINVAL;
}
if (mqprio_qopt->qopt.offset[i] != queue_sum) {
dev_err(&hdev->pdev->dev,
"qopt queue offset must start from 0, and being continuous\n");
return -EINVAL;
}
if (mqprio_qopt->min_rate[i] || mqprio_qopt->max_rate[i]) {
dev_err(&hdev->pdev->dev,
"qopt tx_rate is not supported\n");
return -EOPNOTSUPP;
}
queue_sum = mqprio_qopt->qopt.offset[i];
queue_sum += mqprio_qopt->qopt.count[i];
}
if (hdev->vport[0].alloc_tqps < queue_sum) {
dev_err(&hdev->pdev->dev,
"qopt queue count sum should be less than %u\n",
hdev->vport[0].alloc_tqps);
return -EINVAL;
}
return 0;
}
static void hclge_sync_mqprio_qopt(struct hnae3_tc_info *tc_info,
struct tc_mqprio_qopt_offload *mqprio_qopt)
{
memset(tc_info, 0, sizeof(*tc_info));
tc_info->num_tc = mqprio_qopt->qopt.num_tc;
memcpy(tc_info->prio_tc, mqprio_qopt->qopt.prio_tc_map,
sizeof_field(struct hnae3_tc_info, prio_tc));
memcpy(tc_info->tqp_count, mqprio_qopt->qopt.count,
sizeof_field(struct hnae3_tc_info, tqp_count));
memcpy(tc_info->tqp_offset, mqprio_qopt->qopt.offset,
sizeof_field(struct hnae3_tc_info, tqp_offset));
}
static int hclge_config_tc(struct hclge_dev *hdev,
struct hnae3_tc_info *tc_info)
{
int i;
hclge_tm_schd_info_update(hdev, tc_info->num_tc);
for (i = 0; i < HNAE3_MAX_USER_PRIO; i++)
hdev->tm_info.prio_tc[i] = tc_info->prio_tc[i];
return hclge_map_update(hdev);
}
/* Set up TC for hardware offloaded mqprio in channel mode */
static int hclge_setup_tc(struct hnae3_handle *h,
struct tc_mqprio_qopt_offload *mqprio_qopt)
{
struct hclge_vport *vport = hclge_get_vport(h);
struct hnae3_knic_private_info *kinfo;
struct hclge_dev *hdev = vport->back;
struct hnae3_tc_info old_tc_info;
u8 tc = mqprio_qopt->qopt.num_tc;
int ret;
/* if client unregistered, it's not allowed to change
* mqprio configuration, which may cause uninit ring
* fail.
*/
if (!test_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state))
return -EBUSY;
kinfo = &vport->nic.kinfo;
if (kinfo->tc_info.dcb_ets_active)
return -EINVAL;
ret = hclge_mqprio_qopt_check(hdev, mqprio_qopt);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to check mqprio qopt params, ret = %d\n", ret);
return ret;
}
kinfo->tc_info.mqprio_destroy = !tc;
ret = hclge_notify_down_uinit(hdev);
if (ret)
return ret;
memcpy(&old_tc_info, &kinfo->tc_info, sizeof(old_tc_info));
hclge_sync_mqprio_qopt(&kinfo->tc_info, mqprio_qopt);
kinfo->tc_info.mqprio_active = tc > 0;
ret = hclge_config_tc(hdev, &kinfo->tc_info);
if (ret)
goto err_out;
return hclge_notify_init_up(hdev);
err_out:
if (!tc) {
dev_warn(&hdev->pdev->dev,
"failed to destroy mqprio, will active after reset, ret = %d\n",
ret);
} else {
/* roll-back */
memcpy(&kinfo->tc_info, &old_tc_info, sizeof(old_tc_info));
if (hclge_config_tc(hdev, &kinfo->tc_info))
dev_err(&hdev->pdev->dev,
"failed to roll back tc configuration\n");
}
hclge_notify_init_up(hdev);
return ret;
}
static const struct hnae3_dcb_ops hns3_dcb_ops = {
.ieee_getets = hclge_ieee_getets,
.ieee_setets = hclge_ieee_setets,
.ieee_getpfc = hclge_ieee_getpfc,
.ieee_setpfc = hclge_ieee_setpfc,
.ieee_setapp = hclge_ieee_setapp,
.ieee_delapp = hclge_ieee_delapp,
.getdcbx = hclge_getdcbx,
.setdcbx = hclge_setdcbx,
.setup_tc = hclge_setup_tc,
};
void hclge_dcb_ops_set(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
struct hnae3_knic_private_info *kinfo;
/* Hdev does not support DCB or vport is
* not a pf, then dcb_ops is not set.
*/
if (!hnae3_dev_dcb_supported(hdev) ||
vport->vport_id != 0)
return;
kinfo = &vport->nic.kinfo;
kinfo->dcb_ops = &hns3_dcb_ops;
hdev->dcbx_cap = DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_HOST;
}
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2016-2017 Hisilicon Limited.
#ifndef __HCLGE_DCB_H__
#define __HCLGE_DCB_H__
#include "hclge_main.h"
#ifdef CONFIG_HNS3_DCB
void hclge_dcb_ops_set(struct hclge_dev *hdev);
#else
static inline void hclge_dcb_ops_set(struct hclge_dev *hdev) {}
#endif
#endif /* __HCLGE_DCB_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,138 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2019 Hisilicon Limited. */
#ifndef __HCLGE_DEBUGFS_H
#define __HCLGE_DEBUGFS_H
#include <linux/etherdevice.h>
#include "hclge_cmd.h"
#define HCLGE_DBG_MNG_TBL_MAX 64
#define HCLGE_DBG_MNG_VLAN_MASK_B BIT(0)
#define HCLGE_DBG_MNG_MAC_MASK_B BIT(1)
#define HCLGE_DBG_MNG_ETHER_MASK_B BIT(2)
#define HCLGE_DBG_MNG_E_TYPE_B BIT(11)
#define HCLGE_DBG_MNG_DROP_B BIT(13)
#define HCLGE_DBG_MNG_VLAN_TAG 0x0FFF
#define HCLGE_DBG_MNG_PF_ID 0x0007
#define HCLGE_DBG_MNG_VF_ID 0x00FF
/* Get DFX BD number offset */
#define HCLGE_DBG_DFX_BIOS_OFFSET 1
#define HCLGE_DBG_DFX_SSU_0_OFFSET 2
#define HCLGE_DBG_DFX_SSU_1_OFFSET 3
#define HCLGE_DBG_DFX_IGU_OFFSET 4
#define HCLGE_DBG_DFX_RPU_0_OFFSET 5
#define HCLGE_DBG_DFX_RPU_1_OFFSET 6
#define HCLGE_DBG_DFX_NCSI_OFFSET 7
#define HCLGE_DBG_DFX_RTC_OFFSET 8
#define HCLGE_DBG_DFX_PPP_OFFSET 9
#define HCLGE_DBG_DFX_RCB_OFFSET 10
#define HCLGE_DBG_DFX_TQP_OFFSET 11
#define HCLGE_DBG_DFX_SSU_2_OFFSET 12
struct hclge_qos_pri_map_cmd {
u8 pri0_tc : 4,
pri1_tc : 4;
u8 pri2_tc : 4,
pri3_tc : 4;
u8 pri4_tc : 4,
pri5_tc : 4;
u8 pri6_tc : 4,
pri7_tc : 4;
u8 vlan_pri : 4,
rev : 4;
};
struct hclge_dbg_bitmap_cmd {
union {
u8 bitmap;
struct {
u8 bit0 : 1,
bit1 : 1,
bit2 : 1,
bit3 : 1,
bit4 : 1,
bit5 : 1,
bit6 : 1,
bit7 : 1;
};
};
};
struct hclge_dbg_reg_common_msg {
int msg_num;
int offset;
enum hclge_opcode_type cmd;
};
struct hclge_dbg_tcam_msg {
u8 stage;
u32 loc;
};
#define HCLGE_DBG_MAX_DFX_MSG_LEN 60
struct hclge_dbg_dfx_message {
int flag;
char message[HCLGE_DBG_MAX_DFX_MSG_LEN];
};
#define HCLGE_DBG_MAC_REG_TYPE_LEN 32
struct hclge_dbg_reg_type_info {
enum hnae3_dbg_cmd cmd;
const struct hclge_dbg_dfx_message *dfx_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);
int (*dbg_dump_reg)(struct hclge_dev *hdev, enum hnae3_dbg_cmd cmd,
char *buf, int len);
read_func dbg_read_func;
};
struct hclge_dbg_status_dfx_info {
u32 offset;
char message[HCLGE_DBG_MAX_DFX_MSG_LEN];
};
#define HCLGE_DBG_INFO_LEN 256
#define HCLGE_DBG_VLAN_FLTR_INFO_LEN 256
#define HCLGE_DBG_VLAN_OFFLOAD_INFO_LEN 512
#define HCLGE_DBG_ID_LEN 16
#define HCLGE_DBG_ITEM_NAME_LEN 32
#define HCLGE_DBG_DATA_STR_LEN 32
#define HCLGE_DBG_TM_INFO_LEN 256
#define HCLGE_BILLION_NANO_SECONDS 1000000000
struct hclge_dbg_item {
char name[HCLGE_DBG_ITEM_NAME_LEN];
u16 interval; /* blank numbers after the item */
};
struct hclge_dbg_vlan_cfg {
u16 pvid;
u8 accept_tag1;
u8 accept_tag2;
u8 accept_untag1;
u8 accept_untag2;
u8 insert_tag1;
u8 insert_tag2;
u8 shift_tag;
u8 strip_tag1;
u8 strip_tag2;
u8 drop_tag1;
u8 drop_tag2;
u8 pri_only1;
u8 pri_only2;
};
int hclge_dbg_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc_src,
int index, int bd_num, enum hclge_opcode_type cmd);
#endif
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Hisilicon Limited. */
#include <net/devlink.h>
#include "hclge_devlink.h"
static int hclge_devlink_scc_info_get(struct devlink *devlink,
struct devlink_info_req *req)
{
struct hclge_devlink_priv *priv = devlink_priv(devlink);
char scc_version[HCLGE_DEVLINK_FW_SCC_LEN];
struct hclge_dev *hdev = priv->hdev;
u32 scc_version_tmp;
int ret;
ret = hclge_query_scc_version(hdev, &scc_version_tmp);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to get scc version, ret = %d\n", ret);
return ret;
}
snprintf(scc_version, sizeof(scc_version), "%lu.%lu.%lu.%lu",
hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE3_MASK,
HNAE3_FW_VERSION_BYTE3_SHIFT),
hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE2_MASK,
HNAE3_FW_VERSION_BYTE2_SHIFT),
hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE1_MASK,
HNAE3_FW_VERSION_BYTE1_SHIFT),
hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE0_MASK,
HNAE3_FW_VERSION_BYTE0_SHIFT));
return devlink_info_version_running_put(req, "fw.scc", scc_version);
}
static int hclge_devlink_info_get(struct devlink *devlink,
struct devlink_info_req *req,
struct netlink_ext_ack *extack)
{
#define HCLGE_DEVLINK_FW_STRING_LEN 32
struct hclge_devlink_priv *priv = devlink_priv(devlink);
char version_str[HCLGE_DEVLINK_FW_STRING_LEN];
struct hclge_dev *hdev = priv->hdev;
int ret;
snprintf(version_str, sizeof(version_str), "%lu.%lu.%lu.%lu",
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE3_MASK,
HNAE3_FW_VERSION_BYTE3_SHIFT),
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE2_MASK,
HNAE3_FW_VERSION_BYTE2_SHIFT),
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE1_MASK,
HNAE3_FW_VERSION_BYTE1_SHIFT),
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE0_MASK,
HNAE3_FW_VERSION_BYTE0_SHIFT));
ret = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
version_str);
if (ret) {
dev_err(&hdev->pdev->dev, "failed to set running version of fw\n");
return ret;
}
if (hdev->pdev->revision > HNAE3_DEVICE_VERSION_V2)
ret = hclge_devlink_scc_info_get(devlink, req);
return ret;
}
static int hclge_devlink_reload_down(struct devlink *devlink, bool netns_change,
enum devlink_reload_action action,
enum devlink_reload_limit limit,
struct netlink_ext_ack *extack)
{
struct hclge_devlink_priv *priv = devlink_priv(devlink);
struct hclge_dev *hdev = priv->hdev;
struct hnae3_handle *h = &hdev->vport->nic;
struct pci_dev *pdev = hdev->pdev;
int ret;
if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) {
dev_err(&pdev->dev, "reset is handling\n");
return -EBUSY;
}
switch (action) {
case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
rtnl_lock();
ret = hdev->nic_client->ops->reset_notify(h, HNAE3_DOWN_CLIENT);
if (ret) {
rtnl_unlock();
return ret;
}
ret = hdev->nic_client->ops->reset_notify(h,
HNAE3_UNINIT_CLIENT);
rtnl_unlock();
return ret;
default:
return -EOPNOTSUPP;
}
}
static int hclge_devlink_reload_up(struct devlink *devlink,
enum devlink_reload_action action,
enum devlink_reload_limit limit,
u32 *actions_performed,
struct netlink_ext_ack *extack)
{
struct hclge_devlink_priv *priv = devlink_priv(devlink);
struct hclge_dev *hdev = priv->hdev;
struct hnae3_handle *h = &hdev->vport->nic;
int ret;
*actions_performed = BIT(action);
switch (action) {
case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
rtnl_lock();
ret = hdev->nic_client->ops->reset_notify(h, HNAE3_INIT_CLIENT);
if (ret) {
rtnl_unlock();
return ret;
}
ret = hdev->nic_client->ops->reset_notify(h, HNAE3_UP_CLIENT);
rtnl_unlock();
return ret;
default:
return -EOPNOTSUPP;
}
}
static const struct devlink_ops hclge_devlink_ops = {
.info_get = hclge_devlink_info_get,
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
.reload_down = hclge_devlink_reload_down,
.reload_up = hclge_devlink_reload_up,
};
int hclge_devlink_init(struct hclge_dev *hdev)
{
struct pci_dev *pdev = hdev->pdev;
struct hclge_devlink_priv *priv;
struct devlink *devlink;
devlink = devlink_alloc(&hclge_devlink_ops,
sizeof(struct hclge_devlink_priv), &pdev->dev);
if (!devlink)
return -ENOMEM;
priv = devlink_priv(devlink);
priv->hdev = hdev;
hdev->devlink = devlink;
devlink_register(devlink);
return 0;
}
void hclge_devlink_uninit(struct hclge_dev *hdev)
{
struct devlink *devlink = hdev->devlink;
devlink_unregister(devlink);
devlink_free(devlink);
}
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Hisilicon Limited. */
#ifndef __HCLGE_DEVLINK_H
#define __HCLGE_DEVLINK_H
#include "hclge_main.h"
#define HCLGE_DEVLINK_FW_SCC_LEN 32
struct hclge_devlink_priv {
struct hclge_dev *hdev;
};
int hclge_devlink_init(struct hclge_dev *hdev);
void hclge_devlink_uninit(struct hclge_dev *hdev);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,269 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2017 Hisilicon Limited. */
#ifndef __HCLGE_ERR_H
#define __HCLGE_ERR_H
#include "hclge_main.h"
#include "hclge_debugfs.h"
#include "hnae3.h"
#define HCLGE_MPF_RAS_INT_MIN_BD_NUM 10
#define HCLGE_PF_RAS_INT_MIN_BD_NUM 4
#define HCLGE_MPF_MSIX_INT_MIN_BD_NUM 10
#define HCLGE_PF_MSIX_INT_MIN_BD_NUM 4
#define HCLGE_RAS_PF_OTHER_INT_STS_REG 0x20B00
#define HCLGE_RAS_REG_NFE_MASK 0xFF00
#define HCLGE_RAS_REG_ROCEE_ERR_MASK 0x3000000
#define HCLGE_RAS_REG_ERR_MASK \
(HCLGE_RAS_REG_NFE_MASK | HCLGE_RAS_REG_ROCEE_ERR_MASK)
#define HCLGE_VECTOR0_REG_MSIX_MASK 0x1FF00
#define HCLGE_IMP_TCM_ECC_ERR_INT_EN 0xFFFF0000
#define HCLGE_IMP_TCM_ECC_ERR_INT_EN_MASK 0xFFFF0000
#define HCLGE_IMP_ITCM4_ECC_ERR_INT_EN 0x300
#define HCLGE_IMP_ITCM4_ECC_ERR_INT_EN_MASK 0x300
#define HCLGE_CMDQ_NIC_ECC_ERR_INT_EN 0xFFFF
#define HCLGE_CMDQ_NIC_ECC_ERR_INT_EN_MASK 0xFFFF
#define HCLGE_CMDQ_ROCEE_ECC_ERR_INT_EN 0xFFFF0000
#define HCLGE_CMDQ_ROCEE_ECC_ERR_INT_EN_MASK 0xFFFF0000
#define HCLGE_IMP_RD_POISON_ERR_INT_EN 0x0100
#define HCLGE_IMP_RD_POISON_ERR_INT_EN_MASK 0x0100
#define HCLGE_TQP_ECC_ERR_INT_EN 0x0FFF
#define HCLGE_TQP_ECC_ERR_INT_EN_MASK 0x0FFF
#define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN_MASK 0x0F000000
#define HCLGE_MSIX_SRAM_ECC_ERR_INT_EN 0x0F000000
#define HCLGE_IGU_ERR_INT_EN 0x0000000F
#define HCLGE_IGU_ERR_INT_TYPE 0x00000660
#define HCLGE_IGU_ERR_INT_EN_MASK 0x000F
#define HCLGE_IGU_TNL_ERR_INT_EN 0x0002AABF
#define HCLGE_IGU_TNL_ERR_INT_EN_MASK 0x003F
#define HCLGE_PPP_MPF_ECC_ERR_INT0_EN 0xFFFFFFFF
#define HCLGE_PPP_MPF_ECC_ERR_INT0_EN_MASK 0xFFFFFFFF
#define HCLGE_PPP_MPF_ECC_ERR_INT1_EN 0xFFFFFFFF
#define HCLGE_PPP_MPF_ECC_ERR_INT1_EN_MASK 0xFFFFFFFF
#define HCLGE_PPP_PF_ERR_INT_EN 0x0003
#define HCLGE_PPP_PF_ERR_INT_EN_MASK 0x0003
#define HCLGE_PPP_MPF_ECC_ERR_INT2_EN 0x003F
#define HCLGE_PPP_MPF_ECC_ERR_INT2_EN_MASK 0x003F
#define HCLGE_PPP_MPF_ECC_ERR_INT3_EN 0x003F
#define HCLGE_PPP_MPF_ECC_ERR_INT3_EN_MASK 0x003F
#define HCLGE_TM_SCH_ECC_ERR_INT_EN 0x3
#define HCLGE_TM_QCN_ERR_INT_TYPE 0x29
#define HCLGE_TM_QCN_FIFO_INT_EN 0xFFFF00
#define HCLGE_TM_QCN_MEM_ERR_INT_EN 0xFFFFFF
#define HCLGE_NCSI_ERR_INT_EN 0x3
#define HCLGE_NCSI_ERR_INT_TYPE 0x9
#define HCLGE_MAC_COMMON_ERR_INT_EN 0x107FF
#define HCLGE_MAC_COMMON_ERR_INT_EN_MASK 0x107FF
#define HCLGE_MAC_TNL_INT_EN GENMASK(9, 0)
#define HCLGE_MAC_TNL_INT_EN_MASK GENMASK(9, 0)
#define HCLGE_MAC_TNL_INT_CLR GENMASK(9, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT0_EN GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT0_EN_MASK GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT1_EN GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT1_EN_MASK GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT2_EN 0x3FFF3FFF
#define HCLGE_PPU_MPF_ABNORMAL_INT2_EN_MASK 0x3FFF3FFF
#define HCLGE_PPU_MPF_ABNORMAL_INT2_EN2 0xB
#define HCLGE_PPU_MPF_ABNORMAL_INT2_EN2_MASK 0xB
#define HCLGE_PPU_MPF_ABNORMAL_INT3_EN GENMASK(7, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT3_EN_MASK GENMASK(23, 16)
#define HCLGE_PPU_PF_ABNORMAL_INT_EN GENMASK(5, 0)
#define HCLGE_PPU_PF_ABNORMAL_INT_EN_MASK GENMASK(5, 0)
#define HCLGE_SSU_1BIT_ECC_ERR_INT_EN GENMASK(31, 0)
#define HCLGE_SSU_1BIT_ECC_ERR_INT_EN_MASK GENMASK(31, 0)
#define HCLGE_SSU_MULTI_BIT_ECC_ERR_INT_EN GENMASK(31, 0)
#define HCLGE_SSU_MULTI_BIT_ECC_ERR_INT_EN_MASK GENMASK(31, 0)
#define HCLGE_SSU_BIT32_ECC_ERR_INT_EN 0x0101
#define HCLGE_SSU_BIT32_ECC_ERR_INT_EN_MASK 0x0101
#define HCLGE_SSU_COMMON_INT_EN GENMASK(9, 0)
#define HCLGE_SSU_COMMON_INT_EN_MASK GENMASK(9, 0)
#define HCLGE_SSU_PORT_BASED_ERR_INT_EN 0x0BFF
#define HCLGE_SSU_PORT_BASED_ERR_INT_EN_MASK 0x0BFF0000
#define HCLGE_SSU_FIFO_OVERFLOW_ERR_INT_EN GENMASK(23, 0)
#define HCLGE_SSU_FIFO_OVERFLOW_ERR_INT_EN_MASK GENMASK(23, 0)
#define HCLGE_SSU_COMMON_ERR_INT_MASK GENMASK(9, 0)
#define HCLGE_SSU_PORT_INT_MSIX_MASK 0x7BFF
#define HCLGE_IGU_INT_MASK GENMASK(3, 0)
#define HCLGE_IGU_EGU_TNL_INT_MASK GENMASK(5, 0)
#define HCLGE_PPP_MPF_INT_ST3_MASK GENMASK(5, 0)
#define HCLGE_PPU_MPF_INT_ST3_MASK GENMASK(7, 0)
#define HCLGE_PPU_MPF_INT_ST2_MSIX_MASK BIT(29)
#define HCLGE_PPU_PF_INT_RAS_MASK 0x18
#define HCLGE_PPU_PF_INT_MSIX_MASK 0x26
#define HCLGE_PPU_PF_OVER_8BD_ERR_MASK 0x01
#define HCLGE_QCN_FIFO_INT_MASK GENMASK(17, 0)
#define HCLGE_QCN_ECC_INT_MASK GENMASK(21, 0)
#define HCLGE_NCSI_ECC_INT_MASK GENMASK(1, 0)
#define HCLGE_ROCEE_RAS_NFE_INT_EN 0xF
#define HCLGE_ROCEE_RAS_CE_INT_EN 0x1
#define HCLGE_ROCEE_RAS_NFE_INT_EN_MASK 0xF
#define HCLGE_ROCEE_RAS_CE_INT_EN_MASK 0x1
#define HCLGE_ROCEE_RERR_INT_MASK BIT(0)
#define HCLGE_ROCEE_BERR_INT_MASK BIT(1)
#define HCLGE_ROCEE_AXI_ERR_INT_MASK GENMASK(1, 0)
#define HCLGE_ROCEE_ECC_INT_MASK BIT(2)
#define HCLGE_ROCEE_OVF_INT_MASK BIT(3)
#define HCLGE_ROCEE_OVF_ERR_INT_MASK 0x10000
#define HCLGE_ROCEE_OVF_ERR_TYPE_MASK 0x3F
#define HCLGE_DESC_DATA_MAX 8
#define HCLGE_REG_NUM_MAX 256
#define HCLGE_DESC_NO_DATA_LEN 8
#define HCLGE_BD_NUM_SSU_REG_0 10
#define HCLGE_BD_NUM_SSU_REG_1 15
#define HCLGE_BD_NUM_RPU_REG_0 1
#define HCLGE_BD_NUM_RPU_REG_1 2
#define HCLGE_BD_NUM_IGU_EGU_REG 9
#define HCLGE_BD_NUM_GEN_REG 8
#define HCLGE_MOD_REG_INFO_LEN_MAX 256
#define HCLGE_MOD_REG_EXTRA_LEN 11
#define HCLGE_MOD_REG_VALUE_LEN 9
#define HCLGE_MOD_REG_GROUP_MAX_SIZE 6
#define HCLGE_MOD_MSG_PARA_ARRAY_MAX_SIZE 8
enum hclge_err_int_type {
HCLGE_ERR_INT_MSIX = 0,
HCLGE_ERR_INT_RAS_CE = 1,
HCLGE_ERR_INT_RAS_NFE = 2,
HCLGE_ERR_INT_RAS_FE = 3,
};
enum hclge_mod_name_list {
MODULE_NONE = 0,
MODULE_BIOS_COMMON = 1,
MODULE_GE = 2,
MODULE_IGU_EGU = 3,
MODULE_LGE = 4,
MODULE_NCSI = 5,
MODULE_PPP = 6,
MODULE_QCN = 7,
MODULE_RCB_RX = 8,
MODULE_RTC = 9,
MODULE_SSU = 10,
MODULE_TM = 11,
MODULE_RCB_TX = 12,
MODULE_TXDMA = 13,
MODULE_MASTER = 14,
MODULE_HIMAC = 15,
/* add new MODULE NAME for NIC here in order */
MODULE_ROCEE_TOP = 40,
MODULE_ROCEE_TIMER = 41,
MODULE_ROCEE_MDB = 42,
MODULE_ROCEE_TSP = 43,
MODULE_ROCEE_TRP = 44,
MODULE_ROCEE_SCC = 45,
MODULE_ROCEE_CAEP = 46,
MODULE_ROCEE_GEN_AC = 47,
MODULE_ROCEE_QMM = 48,
MODULE_ROCEE_LSAN = 49,
/* add new MODULE NAME for RoCEE here in order */
};
enum hclge_err_type_list {
NONE_ERROR = 0,
FIFO_ERROR = 1,
MEMORY_ERROR = 2,
POISON_ERROR = 3,
MSIX_ECC_ERROR = 4,
TQP_INT_ECC_ERROR = 5,
PF_ABNORMAL_INT_ERROR = 6,
MPF_ABNORMAL_INT_ERROR = 7,
COMMON_ERROR = 8,
PORT_ERROR = 9,
ETS_ERROR = 10,
NCSI_ERROR = 11,
GLB_ERROR = 12,
LINK_ERROR = 13,
PTP_ERROR = 14,
/* add new ERROR TYPE for NIC here in order */
ROCEE_NORMAL_ERR = 40,
ROCEE_OVF_ERR = 41,
ROCEE_BUS_ERR = 42,
/* add new ERROR TYPE for ROCEE here in order */
};
struct hclge_hw_blk {
u32 msk;
const char *name;
int (*config_err_int)(struct hclge_dev *hdev, bool en);
};
struct hclge_hw_error {
u32 int_msk;
const char *msg;
enum hnae3_reset_type reset_level;
};
struct hclge_hw_module_id {
enum hclge_mod_name_list module_id;
const char *msg;
void (*query_reg_info)(struct hclge_dev *hdev);
};
struct hclge_hw_type_id {
enum hclge_err_type_list type_id;
const char *msg;
bool cause_by_vf; /* indicate the error may from vf exception */
};
struct hclge_sum_err_info {
u8 reset_type;
u8 mod_num;
u8 rsv[2];
};
struct hclge_mod_err_info {
u8 mod_id;
u8 err_num;
u8 rsv[2];
};
struct hclge_type_reg_err_info {
u8 type_id;
u8 reg_num;
u8 rsv[2];
u32 hclge_reg[HCLGE_REG_NUM_MAX];
};
struct hclge_mod_reg_info {
const char *reg_name;
bool has_suffix; /* add suffix for register name */
/* the positions of reg values in hclge_desc.data */
u8 reg_offset_group[HCLGE_MOD_REG_GROUP_MAX_SIZE];
u8 group_size;
};
/* This structure defines cmdq used to query the hardware module debug
* regisgers.
*/
struct hclge_mod_reg_common_msg {
enum hclge_opcode_type cmd;
struct hclge_desc *desc;
u8 bd_num; /* the bd number of hclge_desc used */
bool need_para; /* whether this cmdq needs to add para */
/* the regs need to print */
const struct hclge_mod_reg_info *result_regs;
u16 result_regs_size;
};
int hclge_config_mac_tnl_int(struct hclge_dev *hdev, bool en);
int hclge_config_nic_hw_error(struct hclge_dev *hdev, bool state);
int hclge_config_rocee_ras_interrupt(struct hclge_dev *hdev, bool en);
void hclge_handle_all_hns_hw_errors(struct hnae3_ae_dev *ae_dev);
bool hclge_find_error_source(struct hclge_dev *hdev);
void hclge_handle_occurred_error(struct hclge_dev *hdev);
pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev);
int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
unsigned long *reset_requests);
int hclge_handle_error_info_log(struct hnae3_ae_dev *ae_dev);
int hclge_handle_mac_tnl(struct hclge_dev *hdev);
int hclge_handle_vf_queue_err_ras(struct hclge_dev *hdev);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2026 Hisilicon Limited. */
#ifndef __HCLGE_FD_H
#define __HCLGE_FD_H
struct hnae3_handle;
struct hclge_dev;
int hclge_init_fd_config(struct hclge_dev *hdev);
int hclge_add_fd_entry(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd);
int hclge_del_fd_entry(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd);
void hclge_del_all_fd_entries(struct hclge_dev *hdev);
int hclge_restore_fd_entries(struct hnae3_handle *handle);
int hclge_get_fd_rule_cnt(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int hclge_get_fd_rule_info(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int hclge_get_all_rules(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd, u32 *rule_locs);
void hclge_enable_fd(struct hnae3_handle *handle, bool enable);
int hclge_add_fd_entry_by_arfs(struct hnae3_handle *handle, u16 queue_id,
u16 flow_id, struct flow_keys *fkeys);
int hclge_add_cls_flower(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower);
int hclge_del_cls_flower(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower);
bool hclge_is_cls_flower_active(struct hnae3_handle *handle);
int hclge_clear_arfs_rules(struct hclge_dev *hdev);
void hclge_sync_fd_table(struct hclge_dev *hdev);
void hclge_rfs_filter_expire(struct hclge_dev *hdev);
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,317 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/marvell_phy.h>
#include "hclge_cmd.h"
#include "hclge_main.h"
#include "hclge_mdio.h"
enum hclge_mdio_c22_op_seq {
HCLGE_MDIO_C22_WRITE = 1,
HCLGE_MDIO_C22_READ = 2
};
#define HCLGE_MDIO_CTRL_START_B 0
#define HCLGE_MDIO_CTRL_ST_S 1
#define HCLGE_MDIO_CTRL_ST_M (0x3 << HCLGE_MDIO_CTRL_ST_S)
#define HCLGE_MDIO_CTRL_OP_S 3
#define HCLGE_MDIO_CTRL_OP_M (0x3 << HCLGE_MDIO_CTRL_OP_S)
#define HCLGE_MDIO_PHYID_S 0
#define HCLGE_MDIO_PHYID_M (0x1f << HCLGE_MDIO_PHYID_S)
#define HCLGE_MDIO_PHYREG_S 0
#define HCLGE_MDIO_PHYREG_M (0x1f << HCLGE_MDIO_PHYREG_S)
#define HCLGE_MDIO_STA_B 0
struct hclge_mdio_cfg_cmd {
u8 ctrl_bit;
u8 phyid;
u8 phyad;
u8 rsvd;
__le16 reserve;
__le16 data_wr;
__le16 data_rd;
__le16 sta;
};
static int hclge_mdio_write(struct mii_bus *bus, int phyid, int regnum,
u16 data)
{
struct hclge_mdio_cfg_cmd *mdio_cmd;
struct hclge_dev *hdev = bus->priv;
struct hclge_desc desc;
int ret;
if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state))
return -EBUSY;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, false);
mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
hnae3_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
HCLGE_MDIO_PHYID_S, (u32)phyid);
hnae3_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
HCLGE_MDIO_PHYREG_S, (u32)regnum);
hnae3_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
HCLGE_MDIO_CTRL_ST_S, 1);
hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_OP_M,
HCLGE_MDIO_CTRL_OP_S, HCLGE_MDIO_C22_WRITE);
mdio_cmd->data_wr = cpu_to_le16(data);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"mdio write fail when sending cmd, status is %d.\n",
ret);
return ret;
}
return 0;
}
static int hclge_mdio_read(struct mii_bus *bus, int phyid, int regnum)
{
struct hclge_mdio_cfg_cmd *mdio_cmd;
struct hclge_dev *hdev = bus->priv;
struct hclge_desc desc;
int ret;
if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state))
return -EBUSY;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, true);
mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
hnae3_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
HCLGE_MDIO_PHYID_S, (u32)phyid);
hnae3_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
HCLGE_MDIO_PHYREG_S, (u32)regnum);
hnae3_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
HCLGE_MDIO_CTRL_ST_S, 1);
hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_OP_M,
HCLGE_MDIO_CTRL_OP_S, HCLGE_MDIO_C22_READ);
/* Read out phy data */
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"mdio read fail when get data, status is %d.\n",
ret);
return ret;
}
if (hnae3_get_bit(le16_to_cpu(mdio_cmd->sta), HCLGE_MDIO_STA_B)) {
dev_err(&hdev->pdev->dev, "mdio read data error\n");
return -EIO;
}
return le16_to_cpu(mdio_cmd->data_rd);
}
int hclge_mac_mdio_config(struct hclge_dev *hdev)
{
#define PHY_INEXISTENT 255
struct hclge_mac *mac = &hdev->hw.mac;
struct phy_device *phydev;
struct mii_bus *mdio_bus;
int ret;
if (hdev->hw.mac.phy_addr == PHY_INEXISTENT) {
dev_info(&hdev->pdev->dev,
"no phy device is connected to mdio bus\n");
return 0;
} else if (hdev->hw.mac.phy_addr >= PHY_MAX_ADDR) {
dev_err(&hdev->pdev->dev, "phy_addr(%u) is too large.\n",
hdev->hw.mac.phy_addr);
return -EINVAL;
}
mdio_bus = devm_mdiobus_alloc(&hdev->pdev->dev);
if (!mdio_bus)
return -ENOMEM;
mdio_bus->name = "hisilicon MII bus";
mdio_bus->read = hclge_mdio_read;
mdio_bus->write = hclge_mdio_write;
snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii",
dev_name(&hdev->pdev->dev));
mdio_bus->parent = &hdev->pdev->dev;
mdio_bus->priv = hdev;
mdio_bus->phy_mask = ~(1U << mac->phy_addr);
ret = mdiobus_register(mdio_bus);
if (ret) {
dev_err(mdio_bus->parent,
"failed to register MDIO bus, ret = %d\n", ret);
return ret;
}
phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr);
if (!phydev) {
dev_err(mdio_bus->parent, "Failed to get phy device\n");
mdiobus_unregister(mdio_bus);
return -EIO;
}
mac->phydev = phydev;
mac->mdio_bus = mdio_bus;
return 0;
}
static void hclge_mac_adjust_link(struct net_device *netdev)
{
struct hnae3_handle *h = *((void **)netdev_priv(netdev));
struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back;
int duplex, speed;
int ret;
/* When phy link down, do nothing */
if (netdev->phydev->link == 0)
return;
speed = netdev->phydev->speed;
duplex = netdev->phydev->duplex;
ret = hclge_cfg_mac_speed_dup(hdev, speed, duplex, 0);
if (ret)
netdev_err(netdev, "failed to adjust link.\n");
hdev->hw.mac.req_speed = (u32)speed;
hdev->hw.mac.req_duplex = (u8)duplex;
ret = hclge_cfg_flowctrl(hdev);
if (ret)
netdev_err(netdev, "failed to configure flow control.\n");
}
int hclge_mac_connect_phy(struct hnae3_handle *handle)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct net_device *netdev = hdev->vport[0].nic.netdev;
struct phy_device *phydev = hdev->hw.mac.phydev;
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
int ret;
if (!phydev)
return 0;
linkmode_clear_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
phydev->dev_flags |= MARVELL_PHY_LED0_LINK_LED1_ACTIVE;
ret = phy_connect_direct(netdev, phydev,
hclge_mac_adjust_link,
PHY_INTERFACE_MODE_SGMII);
if (ret) {
netdev_err(netdev, "phy_connect_direct err.\n");
return ret;
}
linkmode_copy(mask, hdev->hw.mac.supported);
linkmode_and(phydev->supported, phydev->supported, mask);
linkmode_copy(phydev->advertising, phydev->supported);
/* supported flag is Pause and Asym Pause, but default advertising
* should be rx on, tx on, so need clear Asym Pause in advertising
* flag
*/
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
phydev->advertising);
phy_attached_info(phydev);
return 0;
}
void hclge_mac_disconnect_phy(struct hnae3_handle *handle)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct phy_device *phydev = hdev->hw.mac.phydev;
if (!phydev)
return;
phy_disconnect(phydev);
}
void hclge_mac_start_phy(struct hclge_dev *hdev)
{
struct phy_device *phydev = hdev->hw.mac.phydev;
if (!phydev)
return;
phy_loopback(phydev, false, 0);
phy_start(phydev);
}
void hclge_mac_stop_phy(struct hclge_dev *hdev)
{
struct net_device *netdev = hdev->vport[0].nic.netdev;
struct phy_device *phydev = netdev->phydev;
if (!phydev)
return;
phy_stop(phydev);
}
int hclge_read_phy_reg(struct hclge_dev *hdev, u16 reg_addr, u16 *val)
{
struct hclge_phy_reg_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PHY_REG, true);
req = (struct hclge_phy_reg_cmd *)desc.data;
req->reg_addr = cpu_to_le16(reg_addr);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to read phy reg, ret = %d.\n", ret);
return ret;
}
*val = le16_to_cpu(req->reg_val);
return 0;
}
int hclge_write_phy_reg(struct hclge_dev *hdev, u16 reg_addr, u16 val)
{
struct hclge_phy_reg_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PHY_REG, false);
req = (struct hclge_phy_reg_cmd *)desc.data;
req->reg_addr = cpu_to_le16(reg_addr);
req->reg_val = cpu_to_le16(val);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to write phy reg, ret = %d.\n", ret);
return ret;
}
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2016-2017 Hisilicon Limited.
#ifndef __HCLGE_MDIO_H
#define __HCLGE_MDIO_H
#include "hnae3.h"
struct hclge_dev;
int hclge_mac_mdio_config(struct hclge_dev *hdev);
int hclge_mac_connect_phy(struct hnae3_handle *handle);
void hclge_mac_disconnect_phy(struct hnae3_handle *handle);
void hclge_mac_start_phy(struct hclge_dev *hdev);
void hclge_mac_stop_phy(struct hclge_dev *hdev);
int hclge_read_phy_reg(struct hclge_dev *hdev, u16 reg_addr, u16 *val);
int hclge_write_phy_reg(struct hclge_dev *hdev, u16 reg_addr, u16 val);
#endif
@@ -0,0 +1,560 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2021 Hisilicon Limited.
#include <linux/skbuff.h>
#include <linux/string_choices.h>
#include "hclge_main.h"
#include "hnae3.h"
static int hclge_ptp_get_cycle(struct hclge_dev *hdev)
{
struct hclge_ptp *ptp = hdev->ptp;
ptp->cycle.quo = readl(hdev->ptp->io_base + HCLGE_PTP_CYCLE_QUO_REG) &
HCLGE_PTP_CYCLE_QUO_MASK;
ptp->cycle.numer = readl(hdev->ptp->io_base + HCLGE_PTP_CYCLE_NUM_REG);
ptp->cycle.den = readl(hdev->ptp->io_base + HCLGE_PTP_CYCLE_DEN_REG);
if (ptp->cycle.den == 0) {
dev_err(&hdev->pdev->dev, "invalid ptp cycle denominator!\n");
return -EINVAL;
}
return 0;
}
static int hclge_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
struct hclge_ptp_cycle *cycle = &hdev->ptp->cycle;
u64 adj_val, adj_base;
unsigned long flags;
u32 quo, numerator;
adj_base = (u64)cycle->quo * (u64)cycle->den + (u64)cycle->numer;
adj_val = adjust_by_scaled_ppm(adj_base, scaled_ppm);
/* This clock cycle is defined by three part: quotient, numerator
* and denominator. For example, 2.5ns, the quotient is 2,
* denominator is fixed to ptp->cycle.den, and numerator
* is 0.5 * ptp->cycle.den.
*/
quo = div_u64_rem(adj_val, cycle->den, &numerator);
spin_lock_irqsave(&hdev->ptp->lock, flags);
writel(quo & HCLGE_PTP_CYCLE_QUO_MASK,
hdev->ptp->io_base + HCLGE_PTP_CYCLE_QUO_REG);
writel(numerator, hdev->ptp->io_base + HCLGE_PTP_CYCLE_NUM_REG);
writel(cycle->den, hdev->ptp->io_base + HCLGE_PTP_CYCLE_DEN_REG);
writel(HCLGE_PTP_CYCLE_ADJ_EN,
hdev->ptp->io_base + HCLGE_PTP_CYCLE_CFG_REG);
spin_unlock_irqrestore(&hdev->ptp->lock, flags);
return 0;
}
bool hclge_ptp_set_tx_info(struct hnae3_handle *handle, struct sk_buff *skb)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_ptp *ptp = hdev->ptp;
if (!ptp)
return false;
if (!test_bit(HCLGE_PTP_FLAG_TX_EN, &ptp->flags) ||
test_and_set_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state)) {
ptp->tx_skipped++;
return false;
}
ptp->tx_start = jiffies;
ptp->tx_skb = skb_get(skb);
ptp->tx_cnt++;
return true;
}
void hclge_ptp_clean_tx_hwts(struct hclge_dev *hdev)
{
struct sk_buff *skb = hdev->ptp->tx_skb;
struct skb_shared_hwtstamps hwts;
u32 hi, lo;
u64 ns;
ns = readl(hdev->ptp->io_base + HCLGE_PTP_TX_TS_NSEC_REG) &
HCLGE_PTP_TX_TS_NSEC_MASK;
lo = readl(hdev->ptp->io_base + HCLGE_PTP_TX_TS_SEC_L_REG);
hi = readl(hdev->ptp->io_base + HCLGE_PTP_TX_TS_SEC_H_REG) &
HCLGE_PTP_TX_TS_SEC_H_MASK;
hdev->ptp->last_tx_seqid = readl(hdev->ptp->io_base +
HCLGE_PTP_TX_TS_SEQID_REG);
if (skb) {
hdev->ptp->tx_skb = NULL;
hdev->ptp->tx_cleaned++;
ns += (((u64)hi) << 32 | lo) * NSEC_PER_SEC;
hwts.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(skb, &hwts);
dev_kfree_skb_any(skb);
}
clear_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state);
}
void hclge_ptp_get_rx_hwts(struct hnae3_handle *handle, struct sk_buff *skb,
u32 nsec, u32 sec)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
unsigned long flags;
u64 ns = nsec;
u32 sec_h;
if (!hdev->ptp || !test_bit(HCLGE_PTP_FLAG_RX_EN, &hdev->ptp->flags))
return;
/* Since the BD does not have enough space for the higher 16 bits of
* second, and this part will not change frequently, so read it
* from register.
*/
spin_lock_irqsave(&hdev->ptp->lock, flags);
sec_h = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_SEC_H_REG);
spin_unlock_irqrestore(&hdev->ptp->lock, flags);
ns += (((u64)sec_h) << HCLGE_PTP_SEC_H_OFFSET | sec) * NSEC_PER_SEC;
skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
hdev->ptp->last_rx = jiffies;
hdev->ptp->rx_cnt++;
}
static int hclge_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
unsigned long flags;
u32 hi, lo;
u64 ns;
spin_lock_irqsave(&hdev->ptp->lock, flags);
ns = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_NSEC_REG);
hi = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_SEC_H_REG);
lo = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_SEC_L_REG);
spin_unlock_irqrestore(&hdev->ptp->lock, flags);
ns += (((u64)hi) << HCLGE_PTP_SEC_H_OFFSET | lo) * NSEC_PER_SEC;
*ts = ns_to_timespec64(ns);
return 0;
}
static int hclge_ptp_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
unsigned long flags;
spin_lock_irqsave(&hdev->ptp->lock, flags);
writel(ts->tv_nsec, hdev->ptp->io_base + HCLGE_PTP_TIME_NSEC_REG);
writel(ts->tv_sec >> HCLGE_PTP_SEC_H_OFFSET,
hdev->ptp->io_base + HCLGE_PTP_TIME_SEC_H_REG);
writel(ts->tv_sec & HCLGE_PTP_SEC_L_MASK,
hdev->ptp->io_base + HCLGE_PTP_TIME_SEC_L_REG);
/* synchronize the time of phc */
writel(HCLGE_PTP_TIME_SYNC_EN,
hdev->ptp->io_base + HCLGE_PTP_TIME_SYNC_REG);
spin_unlock_irqrestore(&hdev->ptp->lock, flags);
return 0;
}
static int hclge_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
unsigned long flags;
bool is_neg = false;
u32 adj_val = 0;
if (delta < 0) {
adj_val |= HCLGE_PTP_TIME_NSEC_NEG;
delta = -delta;
is_neg = true;
}
if (delta > HCLGE_PTP_TIME_NSEC_MASK) {
struct timespec64 ts;
s64 ns;
hclge_ptp_gettimex(ptp, &ts, NULL);
ns = timespec64_to_ns(&ts);
ns = is_neg ? ns - delta : ns + delta;
ts = ns_to_timespec64(ns);
return hclge_ptp_settime(ptp, &ts);
}
adj_val |= delta & HCLGE_PTP_TIME_NSEC_MASK;
spin_lock_irqsave(&hdev->ptp->lock, flags);
writel(adj_val, hdev->ptp->io_base + HCLGE_PTP_TIME_NSEC_REG);
writel(HCLGE_PTP_TIME_ADJ_EN,
hdev->ptp->io_base + HCLGE_PTP_TIME_ADJ_REG);
spin_unlock_irqrestore(&hdev->ptp->lock, flags);
return 0;
}
int hclge_ptp_get_cfg(struct hnae3_handle *handle,
struct kernel_hwtstamp_config *config)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state))
return -EOPNOTSUPP;
*config = hdev->ptp->ts_cfg;
return 0;
}
static int hclge_ptp_int_en(struct hclge_dev *hdev, bool en)
{
struct hclge_ptp_int_cmd *req;
struct hclge_desc desc;
int ret;
req = (struct hclge_ptp_int_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PTP_INT_EN, false);
req->int_en = en ? 1 : 0;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to %s ptp interrupt, ret = %d\n",
str_enable_disable(en), ret);
return ret;
}
int hclge_ptp_cfg_qry(struct hclge_dev *hdev, u32 *cfg)
{
struct hclge_ptp_cfg_cmd *req;
struct hclge_desc desc;
int ret;
req = (struct hclge_ptp_cfg_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PTP_MODE_CFG, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to query ptp config, ret = %d\n", ret);
return ret;
}
*cfg = le32_to_cpu(req->cfg);
return 0;
}
static int hclge_ptp_cfg(struct hclge_dev *hdev, u32 cfg)
{
struct hclge_ptp_cfg_cmd *req;
struct hclge_desc desc;
int ret;
req = (struct hclge_ptp_cfg_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PTP_MODE_CFG, false);
req->cfg = cpu_to_le32(cfg);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to config ptp, ret = %d\n", ret);
return ret;
}
static int hclge_ptp_set_tx_mode(struct kernel_hwtstamp_config *cfg,
unsigned long *flags, u32 *ptp_cfg)
{
switch (cfg->tx_type) {
case HWTSTAMP_TX_OFF:
clear_bit(HCLGE_PTP_FLAG_TX_EN, flags);
break;
case HWTSTAMP_TX_ON:
set_bit(HCLGE_PTP_FLAG_TX_EN, flags);
*ptp_cfg |= HCLGE_PTP_TX_EN_B;
break;
default:
return -ERANGE;
}
return 0;
}
static int hclge_ptp_set_rx_mode(struct kernel_hwtstamp_config *cfg,
unsigned long *flags, u32 *ptp_cfg)
{
int rx_filter = cfg->rx_filter;
switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
clear_bit(HCLGE_PTP_FLAG_RX_EN, flags);
break;
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
set_bit(HCLGE_PTP_FLAG_RX_EN, flags);
*ptp_cfg |= HCLGE_PTP_RX_EN_B;
*ptp_cfg |= HCLGE_PTP_UDP_FULL_TYPE << HCLGE_PTP_UDP_EN_SHIFT;
rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
set_bit(HCLGE_PTP_FLAG_RX_EN, flags);
*ptp_cfg |= HCLGE_PTP_RX_EN_B;
*ptp_cfg |= HCLGE_PTP_UDP_FULL_TYPE << HCLGE_PTP_UDP_EN_SHIFT;
*ptp_cfg |= HCLGE_PTP_MSG1_V2_DEFAULT << HCLGE_PTP_MSG1_SHIFT;
*ptp_cfg |= HCLGE_PTP_MSG0_V2_EVENT << HCLGE_PTP_MSG0_SHIFT;
*ptp_cfg |= HCLGE_PTP_MSG_TYPE_V2 << HCLGE_PTP_MSG_TYPE_SHIFT;
rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
case HWTSTAMP_FILTER_ALL:
default:
return -ERANGE;
}
cfg->rx_filter = rx_filter;
return 0;
}
static int hclge_ptp_set_ts_mode(struct hclge_dev *hdev,
struct kernel_hwtstamp_config *cfg)
{
unsigned long flags = hdev->ptp->flags;
u32 ptp_cfg = 0;
int ret;
if (test_bit(HCLGE_PTP_FLAG_EN, &hdev->ptp->flags))
ptp_cfg |= HCLGE_PTP_EN_B;
ret = hclge_ptp_set_tx_mode(cfg, &flags, &ptp_cfg);
if (ret)
return ret;
ret = hclge_ptp_set_rx_mode(cfg, &flags, &ptp_cfg);
if (ret)
return ret;
ret = hclge_ptp_cfg(hdev, ptp_cfg);
if (ret)
return ret;
hdev->ptp->flags = flags;
hdev->ptp->ptp_cfg = ptp_cfg;
return 0;
}
int hclge_ptp_set_cfg(struct hnae3_handle *handle,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
int ret;
if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state)) {
dev_err(&hdev->pdev->dev, "phc is unsupported\n");
return -EOPNOTSUPP;
}
ret = hclge_ptp_set_ts_mode(hdev, config);
if (ret)
return ret;
hdev->ptp->ts_cfg = *config;
return 0;
}
int hclge_ptp_get_ts_info(struct hnae3_handle *handle,
struct kernel_ethtool_ts_info *info)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state)) {
dev_err(&hdev->pdev->dev, "phc is unsupported\n");
return -EOPNOTSUPP;
}
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
if (hdev->ptp->clock)
info->phc_index = ptp_clock_index(hdev->ptp->clock);
info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ);
info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
BIT(HWTSTAMP_FILTER_PTP_V2_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
return 0;
}
static int hclge_ptp_create_clock(struct hclge_dev *hdev)
{
struct hclge_ptp *ptp;
ptp = devm_kzalloc(&hdev->pdev->dev, sizeof(*ptp), GFP_KERNEL);
if (!ptp)
return -ENOMEM;
ptp->hdev = hdev;
snprintf(ptp->info.name, sizeof(ptp->info.name), "%s",
HCLGE_DRIVER_NAME);
ptp->info.owner = THIS_MODULE;
ptp->info.max_adj = HCLGE_PTP_CYCLE_ADJ_MAX;
ptp->info.n_ext_ts = 0;
ptp->info.pps = 0;
ptp->info.adjfine = hclge_ptp_adjfine;
ptp->info.adjtime = hclge_ptp_adjtime;
ptp->info.gettimex64 = hclge_ptp_gettimex;
ptp->info.settime64 = hclge_ptp_settime;
ptp->info.n_alarm = 0;
spin_lock_init(&ptp->lock);
ptp->io_base = hdev->hw.hw.io_base + HCLGE_PTP_REG_OFFSET;
ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF;
hdev->ptp = ptp;
ptp->clock = ptp_clock_register(&ptp->info, &hdev->pdev->dev);
if (IS_ERR(ptp->clock)) {
dev_err(&hdev->pdev->dev,
"%d failed to register ptp clock, ret = %ld\n",
ptp->info.n_alarm, PTR_ERR(ptp->clock));
return -ENODEV;
} else if (!ptp->clock) {
dev_err(&hdev->pdev->dev, "failed to register ptp clock\n");
return -ENODEV;
}
return 0;
}
static void hclge_ptp_destroy_clock(struct hclge_dev *hdev)
{
ptp_clock_unregister(hdev->ptp->clock);
hdev->ptp->clock = NULL;
devm_kfree(&hdev->pdev->dev, hdev->ptp);
hdev->ptp = NULL;
}
int hclge_ptp_init(struct hclge_dev *hdev)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
struct timespec64 ts;
int ret;
if (!test_bit(HNAE3_DEV_SUPPORT_PTP_B, ae_dev->caps))
return 0;
if (!hdev->ptp) {
ret = hclge_ptp_create_clock(hdev);
if (ret)
return ret;
ret = hclge_ptp_get_cycle(hdev);
if (ret)
goto out;
}
ret = hclge_ptp_int_en(hdev, true);
if (ret)
goto out;
set_bit(HCLGE_PTP_FLAG_EN, &hdev->ptp->flags);
ret = hclge_ptp_adjfine(&hdev->ptp->info, 0);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to init freq, ret = %d\n", ret);
goto out_clear_int;
}
ret = hclge_ptp_set_ts_mode(hdev, &hdev->ptp->ts_cfg);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to init ts mode, ret = %d\n", ret);
goto out_clear_int;
}
ktime_get_real_ts64(&ts);
ret = hclge_ptp_settime(&hdev->ptp->info, &ts);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to init ts time, ret = %d\n", ret);
goto out_clear_int;
}
set_bit(HCLGE_STATE_PTP_EN, &hdev->state);
dev_info(&hdev->pdev->dev, "phc initializes ok!\n");
return 0;
out_clear_int:
clear_bit(HCLGE_PTP_FLAG_EN, &hdev->ptp->flags);
hclge_ptp_int_en(hdev, false);
out:
hclge_ptp_destroy_clock(hdev);
return ret;
}
void hclge_ptp_uninit(struct hclge_dev *hdev)
{
struct hclge_ptp *ptp = hdev->ptp;
if (!ptp)
return;
hclge_ptp_int_en(hdev, false);
clear_bit(HCLGE_STATE_PTP_EN, &hdev->state);
clear_bit(HCLGE_PTP_FLAG_EN, &ptp->flags);
ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF;
if (hclge_ptp_set_ts_mode(hdev, &ptp->ts_cfg))
dev_err(&hdev->pdev->dev, "failed to disable phc\n");
if (ptp->tx_skb) {
struct sk_buff *skb = ptp->tx_skb;
ptp->tx_skb = NULL;
dev_kfree_skb_any(skb);
}
hclge_ptp_destroy_clock(hdev);
}
@@ -0,0 +1,146 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2021 Hisilicon Limited.
#ifndef __HCLGE_PTP_H
#define __HCLGE_PTP_H
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/types.h>
struct hclge_dev;
struct ifreq;
#define HCLGE_PTP_REG_OFFSET 0x29000
#define HCLGE_PTP_TX_TS_SEQID_REG 0x0
#define HCLGE_PTP_TX_TS_NSEC_REG 0x4
#define HCLGE_PTP_TX_TS_NSEC_MASK GENMASK(29, 0)
#define HCLGE_PTP_TX_TS_SEC_L_REG 0x8
#define HCLGE_PTP_TX_TS_SEC_H_REG 0xC
#define HCLGE_PTP_TX_TS_SEC_H_MASK GENMASK(15, 0)
#define HCLGE_PTP_TX_TS_CNT_REG 0x30
#define HCLGE_PTP_TIME_SEC_H_REG 0x50
#define HCLGE_PTP_TIME_SEC_H_MASK GENMASK(15, 0)
#define HCLGE_PTP_TIME_SEC_L_REG 0x54
#define HCLGE_PTP_TIME_NSEC_REG 0x58
#define HCLGE_PTP_TIME_NSEC_MASK 0x3fffffffLL
#define HCLGE_PTP_TIME_NSEC_NEG BIT(31)
#define HCLGE_PTP_TIME_SYNC_REG 0x5C
#define HCLGE_PTP_TIME_SYNC_EN BIT(0)
#define HCLGE_PTP_TIME_ADJ_REG 0x60
#define HCLGE_PTP_TIME_ADJ_EN BIT(0)
#define HCLGE_PTP_CYCLE_QUO_REG 0x64
#define HCLGE_PTP_CYCLE_QUO_MASK GENMASK(7, 0)
#define HCLGE_PTP_CYCLE_DEN_REG 0x68
#define HCLGE_PTP_CYCLE_NUM_REG 0x6C
#define HCLGE_PTP_CYCLE_CFG_REG 0x70
#define HCLGE_PTP_CYCLE_ADJ_EN BIT(0)
#define HCLGE_PTP_CUR_TIME_SEC_H_REG 0x74
#define HCLGE_PTP_CUR_TIME_SEC_L_REG 0x78
#define HCLGE_PTP_CUR_TIME_NSEC_REG 0x7C
#define HCLGE_PTP_CYCLE_ADJ_MAX 500000000
#define HCLGE_PTP_SEC_H_OFFSET 32u
#define HCLGE_PTP_SEC_L_MASK GENMASK(31, 0)
#define HCLGE_PTP_FLAG_EN 0
#define HCLGE_PTP_FLAG_TX_EN 1
#define HCLGE_PTP_FLAG_RX_EN 2
struct hclge_ptp_cycle {
u32 quo;
u32 numer;
u32 den;
};
struct hclge_ptp {
struct hclge_dev *hdev;
struct ptp_clock *clock;
struct sk_buff *tx_skb;
unsigned long flags;
void __iomem *io_base;
struct ptp_clock_info info;
struct kernel_hwtstamp_config ts_cfg;
spinlock_t lock; /* protects ptp registers */
u32 ptp_cfg;
u32 last_tx_seqid;
struct hclge_ptp_cycle cycle;
unsigned long tx_start;
unsigned long tx_cnt;
unsigned long tx_skipped;
unsigned long tx_cleaned;
unsigned long last_rx;
unsigned long rx_cnt;
unsigned long tx_timeout;
};
struct hclge_ptp_int_cmd {
#define HCLGE_PTP_INT_EN_B BIT(0)
u8 int_en;
u8 rsvd[23];
};
enum hclge_ptp_udp_type {
HCLGE_PTP_UDP_NOT_TYPE,
HCLGE_PTP_UDP_P13F_TYPE,
HCLGE_PTP_UDP_P140_TYPE,
HCLGE_PTP_UDP_FULL_TYPE,
};
enum hclge_ptp_msg_type {
HCLGE_PTP_MSG_TYPE_V2_L2,
HCLGE_PTP_MSG_TYPE_V2,
HCLGE_PTP_MSG_TYPE_V2_EVENT,
};
enum hclge_ptp_msg0_type {
HCLGE_PTP_MSG0_V2_DELAY_REQ = 1,
HCLGE_PTP_MSG0_V2_PDELAY_REQ,
HCLGE_PTP_MSG0_V2_DELAY_RESP,
HCLGE_PTP_MSG0_V2_EVENT = 0xF,
};
#define HCLGE_PTP_MSG1_V2_DEFAULT 1
struct hclge_ptp_cfg_cmd {
#define HCLGE_PTP_EN_B BIT(0)
#define HCLGE_PTP_TX_EN_B BIT(1)
#define HCLGE_PTP_RX_EN_B BIT(2)
#define HCLGE_PTP_UDP_EN_SHIFT 3
#define HCLGE_PTP_UDP_EN_MASK GENMASK(4, 3)
#define HCLGE_PTP_MSG_TYPE_SHIFT 8
#define HCLGE_PTP_MSG_TYPE_MASK GENMASK(9, 8)
#define HCLGE_PTP_MSG1_SHIFT 16
#define HCLGE_PTP_MSG1_MASK GENMASK(19, 16)
#define HCLGE_PTP_MSG0_SHIFT 24
#define HCLGE_PTP_MSG0_MASK GENMASK(27, 24)
__le32 cfg;
u8 rsvd[20];
};
static inline struct hclge_dev *hclge_ptp_get_hdev(struct ptp_clock_info *info)
{
struct hclge_ptp *ptp = container_of(info, struct hclge_ptp, info);
return ptp->hdev;
}
bool hclge_ptp_set_tx_info(struct hnae3_handle *handle, struct sk_buff *skb);
void hclge_ptp_clean_tx_hwts(struct hclge_dev *hdev);
void hclge_ptp_get_rx_hwts(struct hnae3_handle *handle, struct sk_buff *skb,
u32 nsec, u32 sec);
int hclge_ptp_get_cfg(struct hnae3_handle *handle,
struct kernel_hwtstamp_config *config);
int hclge_ptp_set_cfg(struct hnae3_handle *handle,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
int hclge_ptp_init(struct hclge_dev *hdev);
void hclge_ptp_uninit(struct hclge_dev *hdev);
int hclge_ptp_get_ts_info(struct hnae3_handle *handle,
struct kernel_ethtool_ts_info *info);
int hclge_ptp_cfg_qry(struct hclge_dev *hdev, u32 *cfg);
#endif
@@ -0,0 +1,669 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2023 Hisilicon Limited.
#include "hclge_cmd.h"
#include "hclge_main.h"
#include "hclge_regs.h"
#include "hnae3.h"
static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG,
HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG,
HCLGE_COMM_NIC_CSQ_DEPTH_REG,
HCLGE_COMM_NIC_CSQ_TAIL_REG,
HCLGE_COMM_NIC_CSQ_HEAD_REG,
HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG,
HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG,
HCLGE_COMM_NIC_CRQ_DEPTH_REG,
HCLGE_COMM_NIC_CRQ_TAIL_REG,
HCLGE_COMM_NIC_CRQ_HEAD_REG,
HCLGE_COMM_VECTOR0_CMDQ_SRC_REG,
HCLGE_COMM_CMDQ_INTR_STS_REG,
HCLGE_COMM_CMDQ_INTR_EN_REG,
HCLGE_COMM_CMDQ_INTR_GEN_REG};
static const u32 common_reg_addr_list[] = {HCLGE_MISC_VECTOR_REG_BASE,
HCLGE_PF_OTHER_INT_REG,
HCLGE_MISC_RESET_STS_REG,
HCLGE_MISC_VECTOR_INT_STS,
HCLGE_GLOBAL_RESET_REG,
HCLGE_FUN_RST_ING,
HCLGE_GRO_EN_REG};
static const u32 ring_reg_addr_list[] = {HCLGE_RING_RX_ADDR_L_REG,
HCLGE_RING_RX_ADDR_H_REG,
HCLGE_RING_RX_BD_NUM_REG,
HCLGE_RING_RX_BD_LENGTH_REG,
HCLGE_RING_RX_MERGE_EN_REG,
HCLGE_RING_RX_TAIL_REG,
HCLGE_RING_RX_HEAD_REG,
HCLGE_RING_RX_FBD_NUM_REG,
HCLGE_RING_RX_OFFSET_REG,
HCLGE_RING_RX_FBD_OFFSET_REG,
HCLGE_RING_RX_STASH_REG,
HCLGE_RING_RX_BD_ERR_REG,
HCLGE_RING_TX_ADDR_L_REG,
HCLGE_RING_TX_ADDR_H_REG,
HCLGE_RING_TX_BD_NUM_REG,
HCLGE_RING_TX_PRIORITY_REG,
HCLGE_RING_TX_TC_REG,
HCLGE_RING_TX_MERGE_EN_REG,
HCLGE_RING_TX_TAIL_REG,
HCLGE_RING_TX_HEAD_REG,
HCLGE_RING_TX_FBD_NUM_REG,
HCLGE_RING_TX_OFFSET_REG,
HCLGE_RING_TX_EBD_NUM_REG,
HCLGE_RING_TX_EBD_OFFSET_REG,
HCLGE_RING_TX_BD_ERR_REG,
HCLGE_RING_EN_REG};
static const u32 tqp_intr_reg_addr_list[] = {HCLGE_TQP_INTR_CTRL_REG,
HCLGE_TQP_INTR_GL0_REG,
HCLGE_TQP_INTR_GL1_REG,
HCLGE_TQP_INTR_GL2_REG,
HCLGE_TQP_INTR_RL_REG};
/* Get DFX BD number offset */
#define HCLGE_DFX_BIOS_BD_OFFSET 1
#define HCLGE_DFX_SSU_0_BD_OFFSET 2
#define HCLGE_DFX_SSU_1_BD_OFFSET 3
#define HCLGE_DFX_IGU_BD_OFFSET 4
#define HCLGE_DFX_RPU_0_BD_OFFSET 5
#define HCLGE_DFX_RPU_1_BD_OFFSET 6
#define HCLGE_DFX_NCSI_BD_OFFSET 7
#define HCLGE_DFX_RTC_BD_OFFSET 8
#define HCLGE_DFX_PPP_BD_OFFSET 9
#define HCLGE_DFX_RCB_BD_OFFSET 10
#define HCLGE_DFX_TQP_BD_OFFSET 11
#define HCLGE_DFX_SSU_2_BD_OFFSET 12
static const u32 hclge_dfx_bd_offset_list[] = {
HCLGE_DFX_BIOS_BD_OFFSET,
HCLGE_DFX_SSU_0_BD_OFFSET,
HCLGE_DFX_SSU_1_BD_OFFSET,
HCLGE_DFX_IGU_BD_OFFSET,
HCLGE_DFX_RPU_0_BD_OFFSET,
HCLGE_DFX_RPU_1_BD_OFFSET,
HCLGE_DFX_NCSI_BD_OFFSET,
HCLGE_DFX_RTC_BD_OFFSET,
HCLGE_DFX_PPP_BD_OFFSET,
HCLGE_DFX_RCB_BD_OFFSET,
HCLGE_DFX_TQP_BD_OFFSET,
HCLGE_DFX_SSU_2_BD_OFFSET
};
static const enum hclge_opcode_type hclge_dfx_reg_opcode_list[] = {
HCLGE_OPC_DFX_BIOS_COMMON_REG,
HCLGE_OPC_DFX_SSU_REG_0,
HCLGE_OPC_DFX_SSU_REG_1,
HCLGE_OPC_DFX_IGU_EGU_REG,
HCLGE_OPC_DFX_RPU_REG_0,
HCLGE_OPC_DFX_RPU_REG_1,
HCLGE_OPC_DFX_NCSI_REG,
HCLGE_OPC_DFX_RTC_REG,
HCLGE_OPC_DFX_PPP_REG,
HCLGE_OPC_DFX_RCB_REG,
HCLGE_OPC_DFX_TQP_REG,
HCLGE_OPC_DFX_SSU_REG_2
};
enum hclge_reg_tag {
HCLGE_REG_TAG_CMDQ = 0,
HCLGE_REG_TAG_COMMON,
HCLGE_REG_TAG_RING,
HCLGE_REG_TAG_TQP_INTR,
HCLGE_REG_TAG_QUERY_32_BIT,
HCLGE_REG_TAG_QUERY_64_BIT,
HCLGE_REG_TAG_DFX_BIOS_COMMON,
HCLGE_REG_TAG_DFX_SSU_0,
HCLGE_REG_TAG_DFX_SSU_1,
HCLGE_REG_TAG_DFX_IGU_EGU,
HCLGE_REG_TAG_DFX_RPU_0,
HCLGE_REG_TAG_DFX_RPU_1,
HCLGE_REG_TAG_DFX_NCSI,
HCLGE_REG_TAG_DFX_RTC,
HCLGE_REG_TAG_DFX_PPP,
HCLGE_REG_TAG_DFX_RCB,
HCLGE_REG_TAG_DFX_TQP,
HCLGE_REG_TAG_DFX_SSU_2,
HCLGE_REG_TAG_RPU_TNL,
};
#pragma pack(4)
struct hclge_reg_tlv {
u16 tag;
u16 len;
};
struct hclge_reg_header {
u64 magic_number;
u8 is_vf;
u8 rsv[7];
};
#pragma pack()
#define HCLGE_REG_TLV_SIZE sizeof(struct hclge_reg_tlv)
#define HCLGE_REG_HEADER_SIZE sizeof(struct hclge_reg_header)
#define HCLGE_REG_TLV_SPACE (sizeof(struct hclge_reg_tlv) / sizeof(u32))
#define HCLGE_REG_HEADER_SPACE (sizeof(struct hclge_reg_header) / sizeof(u32))
#define HCLGE_REG_MAGIC_NUMBER 0x686e733372656773 /* meaning is hns3regs */
#define HCLGE_REG_RPU_TNL_ID_0 1
static u32 hclge_reg_get_header(void *data)
{
struct hclge_reg_header *header = data;
header->magic_number = HCLGE_REG_MAGIC_NUMBER;
header->is_vf = 0x0;
return HCLGE_REG_HEADER_SPACE;
}
static u32 hclge_reg_get_tlv(u32 tag, u32 regs_num, void *data)
{
struct hclge_reg_tlv *tlv = data;
tlv->tag = tag;
tlv->len = regs_num * sizeof(u32) + HCLGE_REG_TLV_SIZE;
return HCLGE_REG_TLV_SPACE;
}
static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num,
void *data)
{
#define HCLGE_32_BIT_REG_RTN_DATANUM 8
#define HCLGE_32_BIT_DESC_NODATA_LEN 2
struct hclge_desc *desc;
u32 *reg_val = data;
__le32 *desc_data;
int nodata_num;
int cmd_num;
int i, k, n;
int ret;
if (regs_num == 0)
return 0;
nodata_num = HCLGE_32_BIT_DESC_NODATA_LEN;
cmd_num = DIV_ROUND_UP(regs_num + nodata_num,
HCLGE_32_BIT_REG_RTN_DATANUM);
desc = kzalloc_objs(struct hclge_desc, cmd_num);
if (!desc)
return -ENOMEM;
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_32_BIT_REG, true);
ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
if (ret) {
dev_err(&hdev->pdev->dev,
"Query 32 bit register cmd failed, ret = %d.\n", ret);
kfree(desc);
return ret;
}
for (i = 0; i < cmd_num; i++) {
if (i == 0) {
desc_data = (__le32 *)(&desc[i].data[0]);
n = HCLGE_32_BIT_REG_RTN_DATANUM - nodata_num;
} else {
desc_data = (__le32 *)(&desc[i]);
n = HCLGE_32_BIT_REG_RTN_DATANUM;
}
for (k = 0; k < n; k++) {
*reg_val++ = le32_to_cpu(*desc_data++);
regs_num--;
if (!regs_num)
break;
}
}
kfree(desc);
return 0;
}
static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num,
void *data)
{
#define HCLGE_64_BIT_REG_RTN_DATANUM 4
#define HCLGE_64_BIT_DESC_NODATA_LEN 1
struct hclge_desc *desc;
u64 *reg_val = data;
__le64 *desc_data;
int nodata_len;
int cmd_num;
int i, k, n;
int ret;
if (regs_num == 0)
return 0;
nodata_len = HCLGE_64_BIT_DESC_NODATA_LEN;
cmd_num = DIV_ROUND_UP(regs_num + nodata_len,
HCLGE_64_BIT_REG_RTN_DATANUM);
desc = kzalloc_objs(struct hclge_desc, cmd_num);
if (!desc)
return -ENOMEM;
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_64_BIT_REG, true);
ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
if (ret) {
dev_err(&hdev->pdev->dev,
"Query 64 bit register cmd failed, ret = %d.\n", ret);
kfree(desc);
return ret;
}
for (i = 0; i < cmd_num; i++) {
if (i == 0) {
desc_data = (__le64 *)(&desc[i].data[0]);
n = HCLGE_64_BIT_REG_RTN_DATANUM - nodata_len;
} else {
desc_data = (__le64 *)(&desc[i]);
n = HCLGE_64_BIT_REG_RTN_DATANUM;
}
for (k = 0; k < n; k++) {
*reg_val++ = le64_to_cpu(*desc_data++);
regs_num--;
if (!regs_num)
break;
}
}
kfree(desc);
return 0;
}
int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc)
{
int i;
/* initialize command BD except the last one */
for (i = 0; i < HCLGE_GET_DFX_REG_TYPE_CNT - 1; i++) {
hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM,
true);
desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
}
/* initialize the last command BD */
hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM, true);
return hclge_cmd_send(&hdev->hw, desc, HCLGE_GET_DFX_REG_TYPE_CNT);
}
static int hclge_get_dfx_reg_bd_num(struct hclge_dev *hdev,
int *bd_num_list,
u32 type_num)
{
u32 entries_per_desc, desc_index, index, offset, i;
struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
int ret;
ret = hclge_query_bd_num_cmd_send(hdev, desc);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get dfx bd num fail, status is %d.\n", ret);
return ret;
}
entries_per_desc = ARRAY_SIZE(desc[0].data);
for (i = 0; i < type_num; i++) {
offset = hclge_dfx_bd_offset_list[i];
index = offset % entries_per_desc;
desc_index = offset / entries_per_desc;
bd_num_list[i] = le32_to_cpu(desc[desc_index].data[index]);
}
return ret;
}
static int hclge_dfx_reg_cmd_send(struct hclge_dev *hdev,
struct hclge_desc *desc_src, int bd_num,
enum hclge_opcode_type cmd)
{
struct hclge_desc *desc = desc_src;
int i, ret;
hclge_cmd_setup_basic_desc(desc, cmd, true);
for (i = 0; i < bd_num - 1; i++) {
desc->flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
desc++;
hclge_cmd_setup_basic_desc(desc, cmd, true);
}
desc = desc_src;
ret = hclge_cmd_send(&hdev->hw, desc, bd_num);
if (ret)
dev_err(&hdev->pdev->dev,
"Query dfx reg cmd(0x%x) send fail, status is %d.\n",
cmd, ret);
return ret;
}
/* tnl_id = 0 means get sum of all tnl reg's value */
static int hclge_dfx_reg_rpu_tnl_cmd_send(struct hclge_dev *hdev, u32 tnl_id,
struct hclge_desc *desc, int bd_num)
{
int i, ret;
for (i = 0; i < bd_num; i++) {
hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_RPU_REG_0,
true);
if (i != bd_num - 1)
desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
}
desc[0].data[0] = cpu_to_le32(tnl_id);
ret = hclge_cmd_send(&hdev->hw, desc, bd_num);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to query dfx rpu tnl reg, ret = %d\n",
ret);
return ret;
}
static int hclge_dfx_reg_fetch_data(struct hclge_desc *desc_src, int bd_num,
void *data)
{
int entries_per_desc, reg_num, desc_index, index, i;
struct hclge_desc *desc = desc_src;
u32 *reg = data;
entries_per_desc = ARRAY_SIZE(desc->data);
reg_num = entries_per_desc * bd_num;
for (i = 0; i < reg_num; i++) {
index = i % entries_per_desc;
desc_index = i / entries_per_desc;
*reg++ = le32_to_cpu(desc[desc_index].data[index]);
}
return reg_num;
}
static int hclge_get_dfx_reg_len(struct hclge_dev *hdev, int *len)
{
u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list);
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
int data_len_per_desc;
int *bd_num_list;
int ret;
u32 i;
bd_num_list = kzalloc_objs(int, dfx_reg_type_num);
if (!bd_num_list)
return -ENOMEM;
ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get dfx reg bd num fail, status is %d.\n", ret);
goto out;
}
data_len_per_desc = sizeof_field(struct hclge_desc, data);
*len = 0;
for (i = 0; i < dfx_reg_type_num; i++)
*len += bd_num_list[i] * data_len_per_desc + HCLGE_REG_TLV_SIZE;
/**
* the num of dfx_rpu_0 is reused by each dfx_rpu_tnl
* HCLGE_DFX_BD_OFFSET is starting at 1, but the array subscript is
* starting at 0, so offset need '- 1'.
*/
*len += (bd_num_list[HCLGE_DFX_RPU_0_BD_OFFSET - 1] * data_len_per_desc +
HCLGE_REG_TLV_SIZE) * ae_dev->dev_specs.tnl_num;
out:
kfree(bd_num_list);
return ret;
}
static int hclge_get_dfx_rpu_tnl_reg(struct hclge_dev *hdev, u32 *reg,
struct hclge_desc *desc_src,
int bd_num)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
int ret = 0;
u8 i;
for (i = HCLGE_REG_RPU_TNL_ID_0; i <= ae_dev->dev_specs.tnl_num; i++) {
ret = hclge_dfx_reg_rpu_tnl_cmd_send(hdev, i, desc_src, bd_num);
if (ret)
break;
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_RPU_TNL,
ARRAY_SIZE(desc_src->data) * bd_num,
reg);
reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg);
}
return ret;
}
static int hclge_get_dfx_reg(struct hclge_dev *hdev, void *data)
{
u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list);
int bd_num, bd_num_max, buf_len;
struct hclge_desc *desc_src;
int *bd_num_list;
u32 *reg = data;
int ret;
u32 i;
bd_num_list = kzalloc_objs(int, dfx_reg_type_num);
if (!bd_num_list)
return -ENOMEM;
ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get dfx reg bd num fail, status is %d.\n", ret);
goto out;
}
bd_num_max = bd_num_list[0];
for (i = 1; i < dfx_reg_type_num; i++)
bd_num_max = max_t(int, bd_num_max, bd_num_list[i]);
buf_len = sizeof(*desc_src) * bd_num_max;
desc_src = kzalloc(buf_len, GFP_KERNEL);
if (!desc_src) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < dfx_reg_type_num; i++) {
bd_num = bd_num_list[i];
ret = hclge_dfx_reg_cmd_send(hdev, desc_src, bd_num,
hclge_dfx_reg_opcode_list[i]);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get dfx reg fail, status is %d.\n", ret);
goto free;
}
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_DFX_BIOS_COMMON + i,
ARRAY_SIZE(desc_src->data) * bd_num,
reg);
reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg);
}
/**
* HCLGE_DFX_BD_OFFSET is starting at 1, but the array subscript is
* starting at 0, so offset need '- 1'.
*/
bd_num = bd_num_list[HCLGE_DFX_RPU_0_BD_OFFSET - 1];
ret = hclge_get_dfx_rpu_tnl_reg(hdev, reg, desc_src, bd_num);
free:
kfree(desc_src);
out:
kfree(bd_num_list);
return ret;
}
static int hclge_fetch_pf_reg(struct hclge_dev *hdev, void *data,
struct hnae3_knic_private_info *kinfo)
{
#define HCLGE_RING_INT_REG_OFFSET 0x4
struct hnae3_queue *tqp;
int i, j, reg_num;
int data_num_sum;
u32 *reg = data;
/* fetching per-PF registers valus from PF PCIe register space */
reg_num = ARRAY_SIZE(cmdq_reg_addr_list);
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_CMDQ, reg_num, reg);
for (i = 0; i < reg_num; i++)
*reg++ = hclge_read_dev(&hdev->hw, cmdq_reg_addr_list[i]);
data_num_sum = reg_num + HCLGE_REG_TLV_SPACE;
reg_num = ARRAY_SIZE(common_reg_addr_list);
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_COMMON, reg_num, reg);
for (i = 0; i < reg_num; i++)
*reg++ = hclge_read_dev(&hdev->hw, common_reg_addr_list[i]);
data_num_sum += reg_num + HCLGE_REG_TLV_SPACE;
reg_num = ARRAY_SIZE(ring_reg_addr_list);
for (j = 0; j < kinfo->num_tqps; j++) {
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_RING, reg_num, reg);
tqp = kinfo->tqp[j];
for (i = 0; i < reg_num; i++)
*reg++ = readl_relaxed(tqp->io_base -
HCLGE_TQP_REG_OFFSET +
ring_reg_addr_list[i]);
}
data_num_sum += (reg_num + HCLGE_REG_TLV_SPACE) * kinfo->num_tqps;
reg_num = ARRAY_SIZE(tqp_intr_reg_addr_list);
for (j = 0; j < hdev->num_msi_used - 1; j++) {
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_TQP_INTR, reg_num, reg);
for (i = 0; i < reg_num; i++)
*reg++ = hclge_read_dev(&hdev->hw,
tqp_intr_reg_addr_list[i] +
HCLGE_RING_INT_REG_OFFSET * j);
}
data_num_sum += (reg_num + HCLGE_REG_TLV_SPACE) *
(hdev->num_msi_used - 1);
return data_num_sum;
}
static int hclge_get_regs_num(struct hclge_dev *hdev, u32 *regs_num_32_bit,
u32 *regs_num_64_bit)
{
struct hclge_desc desc;
u32 total_num;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_REG_NUM, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"Query register number cmd failed, ret = %d.\n", ret);
return ret;
}
*regs_num_32_bit = le32_to_cpu(desc.data[0]);
*regs_num_64_bit = le32_to_cpu(desc.data[1]);
total_num = *regs_num_32_bit + *regs_num_64_bit;
if (!total_num)
return -EINVAL;
return 0;
}
int hclge_get_regs_len(struct hnae3_handle *handle)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclge_vport *vport = hclge_get_vport(handle);
int regs_num_32_bit, regs_num_64_bit, dfx_regs_len;
int cmdq_len, common_len, ring_len, tqp_intr_len;
int regs_len_32_bit, regs_len_64_bit;
struct hclge_dev *hdev = vport->back;
int ret;
ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get register number failed, ret = %d.\n", ret);
return ret;
}
ret = hclge_get_dfx_reg_len(hdev, &dfx_regs_len);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get dfx reg len failed, ret = %d.\n", ret);
return ret;
}
cmdq_len = HCLGE_REG_TLV_SIZE + sizeof(cmdq_reg_addr_list);
common_len = HCLGE_REG_TLV_SIZE + sizeof(common_reg_addr_list);
ring_len = HCLGE_REG_TLV_SIZE + sizeof(ring_reg_addr_list);
tqp_intr_len = HCLGE_REG_TLV_SIZE + sizeof(tqp_intr_reg_addr_list);
regs_len_32_bit = HCLGE_REG_TLV_SIZE + regs_num_32_bit * sizeof(u32);
regs_len_64_bit = HCLGE_REG_TLV_SIZE + regs_num_64_bit * sizeof(u64);
/* return the total length of all register values */
return HCLGE_REG_HEADER_SIZE + cmdq_len + common_len + ring_len *
kinfo->num_tqps + tqp_intr_len * (hdev->num_msi_used - 1) +
regs_len_32_bit + regs_len_64_bit + dfx_regs_len;
}
void hclge_get_regs(struct hnae3_handle *handle, u32 *version,
void *data)
{
#define HCLGE_REG_64_BIT_SPACE_MULTIPLE 2
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
u32 regs_num_32_bit, regs_num_64_bit;
u32 *reg = data;
int ret;
*version = hdev->fw_version;
ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get register number failed, ret = %d.\n", ret);
return;
}
reg += hclge_reg_get_header(reg);
reg += hclge_fetch_pf_reg(hdev, reg, kinfo);
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_QUERY_32_BIT,
regs_num_32_bit, reg);
ret = hclge_get_32_bit_regs(hdev, regs_num_32_bit, reg);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get 32 bit register failed, ret = %d.\n", ret);
return;
}
reg += regs_num_32_bit;
reg += hclge_reg_get_tlv(HCLGE_REG_TAG_QUERY_64_BIT,
regs_num_64_bit *
HCLGE_REG_64_BIT_SPACE_MULTIPLE, reg);
ret = hclge_get_64_bit_regs(hdev, regs_num_64_bit, reg);
if (ret) {
dev_err(&hdev->pdev->dev,
"Get 64 bit register failed, ret = %d.\n", ret);
return;
}
reg += regs_num_64_bit * HCLGE_REG_64_BIT_SPACE_MULTIPLE;
ret = hclge_get_dfx_reg(hdev, reg);
if (ret)
dev_err(&hdev->pdev->dev,
"Get dfx register failed, ret = %d.\n", ret);
}
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2023 Hisilicon Limited.
#ifndef __HCLGE_REGS_H
#define __HCLGE_REGS_H
#include <linux/types.h>
#include "hclge_comm_cmd.h"
struct hnae3_handle;
struct hclge_dev;
int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
struct hclge_desc *desc);
int hclge_get_regs_len(struct hnae3_handle *handle);
void hclge_get_regs(struct hnae3_handle *handle, u32 *version,
void *data);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,281 @@
/* SPDX-License-Identifier: GPL-2.0+ */
// Copyright (c) 2016-2017 Hisilicon Limited.
#ifndef __HCLGE_TM_H
#define __HCLGE_TM_H
#include <linux/types.h>
#include "hnae3.h"
struct hclge_dev;
struct hclge_vport;
enum hclge_opcode_type;
/* MAC Pause */
#define HCLGE_TX_MAC_PAUSE_EN_MSK BIT(0)
#define HCLGE_RX_MAC_PAUSE_EN_MSK BIT(1)
#define HCLGE_TM_PORT_BASE_MODE_MSK BIT(0)
#define HCLGE_DEFAULT_PAUSE_TRANS_GAP 0x7F
#define HCLGE_DEFAULT_PAUSE_TRANS_TIME 0xFFFF
/* SP or DWRR */
#define HCLGE_TM_TX_SCHD_DWRR_MSK BIT(0)
#define HCLGE_TM_TX_SCHD_SP_MSK 0xFE
#define HCLGE_ETHER_MAX_RATE 100000
#define HCLGE_TM_PF_MAX_PRI_NUM 8
#define HCLGE_TM_PF_MAX_QSET_NUM 8
#define HCLGE_DSCP_MAP_TC_BD_NUM 2
#define HCLGE_DSCP_TC_SHIFT(n) (((n) & 1) * 4)
#define HCLGE_TM_FLUSH_TIME_MS 10
#define HCLGE_TM_FLUSH_EN_MSK BIT(0)
struct hclge_pg_to_pri_link_cmd {
u8 pg_id;
u8 rsvd1[3];
u8 pri_bit_map;
};
struct hclge_qs_to_pri_link_cmd {
__le16 qs_id;
__le16 rsvd;
u8 priority;
#define HCLGE_TM_QS_PRI_LINK_VLD_MSK BIT(0)
u8 link_vld;
};
struct hclge_nq_to_qs_link_cmd {
__le16 nq_id;
__le16 rsvd;
#define HCLGE_TM_Q_QS_LINK_VLD_MSK BIT(10)
#define HCLGE_TM_QS_ID_L_MSK GENMASK(9, 0)
#define HCLGE_TM_QS_ID_L_S 0
#define HCLGE_TM_QS_ID_H_MSK GENMASK(14, 10)
#define HCLGE_TM_QS_ID_H_S 10
#define HCLGE_TM_QS_ID_H_EXT_S 11
#define HCLGE_TM_QS_ID_H_EXT_MSK GENMASK(15, 11)
__le16 qset_id;
};
struct hclge_tqp_tx_queue_tc_cmd {
__le16 queue_id;
__le16 rsvd;
u8 tc_id;
u8 rev[3];
};
struct hclge_pg_weight_cmd {
u8 pg_id;
u8 dwrr;
};
struct hclge_priority_weight_cmd {
u8 pri_id;
u8 dwrr;
};
struct hclge_pri_sch_mode_cfg_cmd {
u8 pri_id;
u8 rsvd[3];
u8 sch_mode;
};
struct hclge_qs_sch_mode_cfg_cmd {
__le16 qs_id;
u8 rsvd[2];
u8 sch_mode;
};
struct hclge_qs_weight_cmd {
__le16 qs_id;
u8 dwrr;
};
struct hclge_ets_tc_weight_cmd {
u8 tc_weight[HNAE3_MAX_TC];
u8 weight_offset;
u8 rsvd[15];
};
#define HCLGE_TM_SHAP_IR_B_MSK GENMASK(7, 0)
#define HCLGE_TM_SHAP_IR_B_LSH 0
#define HCLGE_TM_SHAP_IR_U_MSK GENMASK(11, 8)
#define HCLGE_TM_SHAP_IR_U_LSH 8
#define HCLGE_TM_SHAP_IR_S_MSK GENMASK(15, 12)
#define HCLGE_TM_SHAP_IR_S_LSH 12
#define HCLGE_TM_SHAP_BS_B_MSK GENMASK(20, 16)
#define HCLGE_TM_SHAP_BS_B_LSH 16
#define HCLGE_TM_SHAP_BS_S_MSK GENMASK(25, 21)
#define HCLGE_TM_SHAP_BS_S_LSH 21
enum hclge_shap_bucket {
HCLGE_TM_SHAP_C_BUCKET = 0,
HCLGE_TM_SHAP_P_BUCKET,
};
/* set bit HCLGE_TM_RATE_VLD to 1 means use 'rate' to config shaping */
#define HCLGE_TM_RATE_VLD 0
struct hclge_pri_shapping_cmd {
u8 pri_id;
u8 rsvd[3];
__le32 pri_shapping_para;
u8 flag;
u8 rsvd1[3];
__le32 pri_rate;
};
struct hclge_pg_shapping_cmd {
u8 pg_id;
u8 rsvd[3];
__le32 pg_shapping_para;
u8 flag;
u8 rsvd1[3];
__le32 pg_rate;
};
struct hclge_qs_shapping_cmd {
__le16 qs_id;
u8 rsvd[2];
__le32 qs_shapping_para;
u8 flag;
u8 rsvd1[3];
__le32 qs_rate;
};
#define HCLGE_BP_GRP_NUM 32
#define HCLGE_BP_SUB_GRP_ID_S 0
#define HCLGE_BP_SUB_GRP_ID_M GENMASK(4, 0)
#define HCLGE_BP_GRP_ID_S 5
#define HCLGE_BP_GRP_ID_M GENMASK(9, 5)
#define HCLGE_BP_EXT_GRP_NUM 40
#define HCLGE_BP_EXT_GRP_ID_S 5
#define HCLGE_BP_EXT_GRP_ID_M GENMASK(10, 5)
struct hclge_bp_to_qs_map_cmd {
u8 tc_id;
u8 rsvd[2];
u8 qs_group_id;
__le32 qs_bit_map;
u32 rsvd1;
};
#define HCLGE_PFC_DISABLE 0
#define HCLGE_PFC_TX_RX_DISABLE 0
struct hclge_pfc_en_cmd {
u8 tx_rx_en_bitmap;
u8 pri_en_bitmap;
};
struct hclge_cfg_pause_param_cmd {
u8 mac_addr[ETH_ALEN];
u8 pause_trans_gap;
u8 rsvd;
__le16 pause_trans_time;
u8 rsvd1[6];
/* extra mac address to do double check for pause frame */
u8 mac_addr_extra[ETH_ALEN];
u16 rsvd2;
};
struct hclge_pfc_stats_cmd {
__le64 pkt_num[3];
};
struct hclge_port_shapping_cmd {
__le32 port_shapping_para;
u8 flag;
u8 rsvd[3];
__le32 port_rate;
};
struct hclge_shaper_ir_para {
u8 ir_b; /* IR_B parameter of IR shaper */
u8 ir_u; /* IR_U parameter of IR shaper */
u8 ir_s; /* IR_S parameter of IR shaper */
};
struct hclge_tm_nodes_cmd {
u8 pg_base_id;
u8 pri_base_id;
__le16 qset_base_id;
__le16 queue_base_id;
u8 pg_num;
u8 pri_num;
__le16 qset_num;
__le16 queue_num;
};
struct hclge_tm_shaper_para {
u32 rate;
u8 ir_b;
u8 ir_u;
u8 ir_s;
u8 bs_b;
u8 bs_s;
u8 flag;
};
#define hclge_tm_set_field(dest, string, val) \
hnae3_set_field((dest), \
(HCLGE_TM_SHAP_##string##_MSK), \
(HCLGE_TM_SHAP_##string##_LSH), val)
#define hclge_tm_get_field(src, string) \
hnae3_get_field((src), HCLGE_TM_SHAP_##string##_MSK, \
HCLGE_TM_SHAP_##string##_LSH)
int hclge_tm_schd_init(struct hclge_dev *hdev);
int hclge_tm_vport_map_update(struct hclge_dev *hdev);
int hclge_pause_setup_hw(struct hclge_dev *hdev, bool init);
int hclge_tm_schd_setup_hw(struct hclge_dev *hdev);
void hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc);
void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc);
void hclge_tm_pfc_info_update(struct hclge_dev *hdev);
int hclge_tm_dwrr_cfg(struct hclge_dev *hdev);
int hclge_tm_init_hw(struct hclge_dev *hdev, bool init);
int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap,
u8 pfc_bitmap);
int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx);
int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr);
int hclge_mac_pause_setup_hw(struct hclge_dev *hdev);
void hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats);
void hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats);
int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate);
int hclge_tm_port_shaper_cfg(struct hclge_dev *hdev);
int hclge_tm_get_qset_num(struct hclge_dev *hdev, u16 *qset_num);
int hclge_tm_get_pri_num(struct hclge_dev *hdev, u8 *pri_num);
int hclge_tm_get_qset_map_pri(struct hclge_dev *hdev, u16 qset_id, u8 *priority,
u8 *link_vld);
int hclge_tm_get_qset_sch_mode(struct hclge_dev *hdev, u16 qset_id, u8 *mode);
int hclge_tm_get_qset_weight(struct hclge_dev *hdev, u16 qset_id, u8 *weight);
int hclge_tm_get_qset_shaper(struct hclge_dev *hdev, u16 qset_id,
struct hclge_tm_shaper_para *para);
int hclge_tm_get_pri_sch_mode(struct hclge_dev *hdev, u8 pri_id, u8 *mode);
int hclge_tm_get_pri_weight(struct hclge_dev *hdev, u8 pri_id, u8 *weight);
int hclge_tm_get_pri_shaper(struct hclge_dev *hdev, u8 pri_id,
enum hclge_opcode_type cmd,
struct hclge_tm_shaper_para *para);
int hclge_tm_get_q_to_qs_map(struct hclge_dev *hdev, u16 q_id, u16 *qset_id);
int hclge_tm_get_q_to_tc(struct hclge_dev *hdev, u16 q_id, u8 *tc_id);
int hclge_tm_get_pg_to_pri_map(struct hclge_dev *hdev, u8 pg_id,
u8 *pri_bit_map);
int hclge_tm_get_pg_weight(struct hclge_dev *hdev, u8 pg_id, u8 *weight);
int hclge_tm_get_pg_sch_mode(struct hclge_dev *hdev, u8 pg_id, u8 *mode);
int hclge_tm_get_pg_shaper(struct hclge_dev *hdev, u8 pg_id,
enum hclge_opcode_type cmd,
struct hclge_tm_shaper_para *para);
int hclge_tm_get_port_shaper(struct hclge_dev *hdev,
struct hclge_tm_shaper_para *para);
int hclge_up_to_tc_map(struct hclge_dev *hdev);
int hclge_dscp_to_tc_map(struct hclge_dev *hdev);
int hclge_tm_flush_cfg(struct hclge_dev *hdev, bool enable);
void hclge_reset_tc_config(struct hclge_dev *hdev);
#endif
@@ -0,0 +1,181 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2020 Hisilicon Limited. */
/* This must be outside ifdef _HCLGE_TRACE_H */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hns3
#if !defined(_HCLGE_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _HCLGE_TRACE_H_
#include <linux/tracepoint.h>
#define PF_DESC_LEN (sizeof(struct hclge_desc) / sizeof(u32))
#define PF_GET_MBX_LEN (sizeof(struct hclge_mbx_vf_to_pf_cmd) / sizeof(u32))
#define PF_SEND_MBX_LEN (sizeof(struct hclge_mbx_pf_to_vf_cmd) / sizeof(u32))
TRACE_EVENT(hclge_pf_mbx_get,
TP_PROTO(
struct hclge_dev *hdev,
struct hclge_mbx_vf_to_pf_cmd *req),
TP_ARGS(hdev, req),
TP_STRUCT__entry(
__field(u8, vfid)
__field(u8, code)
__field(u8, subcode)
__string(pciname, pci_name(hdev->pdev))
__string(devname, hdev->vport[0].nic.kinfo.netdev->name)
__array(u32, mbx_data, PF_GET_MBX_LEN)
),
TP_fast_assign(
__entry->vfid = req->mbx_src_vfid;
__entry->code = req->msg.code;
__entry->subcode = req->msg.subcode;
__assign_str(pciname);
__assign_str(devname);
memcpy(__entry->mbx_data, req,
sizeof(struct hclge_mbx_vf_to_pf_cmd));
),
TP_printk(
"%s %s vfid:%u code:%u subcode:%u data:%s",
__get_str(pciname), __get_str(devname), __entry->vfid,
__entry->code, __entry->subcode,
__print_array(__entry->mbx_data, PF_GET_MBX_LEN, sizeof(u32))
)
);
TRACE_EVENT(hclge_pf_mbx_send,
TP_PROTO(
struct hclge_dev *hdev,
struct hclge_mbx_pf_to_vf_cmd *req),
TP_ARGS(hdev, req),
TP_STRUCT__entry(
__field(u8, vfid)
__field(u16, code)
__string(pciname, pci_name(hdev->pdev))
__string(devname, hdev->vport[0].nic.kinfo.netdev->name)
__array(u32, mbx_data, PF_SEND_MBX_LEN)
),
TP_fast_assign(
__entry->vfid = req->dest_vfid;
__entry->code = le16_to_cpu(req->msg.code);
__assign_str(pciname);
__assign_str(devname);
memcpy(__entry->mbx_data, req,
sizeof(struct hclge_mbx_pf_to_vf_cmd));
),
TP_printk(
"%s %s vfid:%u code:%u data:%s",
__get_str(pciname), __get_str(devname), __entry->vfid,
__entry->code,
__print_array(__entry->mbx_data, PF_SEND_MBX_LEN, sizeof(u32))
)
);
DECLARE_EVENT_CLASS(hclge_pf_cmd_template,
TP_PROTO(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num),
TP_STRUCT__entry(__field(u16, opcode)
__field(u16, flag)
__field(u16, retval)
__field(u16, rsv)
__field(int, index)
__field(int, num)
__string(pciname, pci_name(hw->cmq.csq.pdev))
__array(u32, data, HCLGE_DESC_DATA_LEN)),
TP_fast_assign(int i;
__entry->opcode = le16_to_cpu(desc->opcode);
__entry->flag = le16_to_cpu(desc->flag);
__entry->retval = le16_to_cpu(desc->retval);
__entry->rsv = le16_to_cpu(desc->rsv);
__entry->index = index;
__entry->num = num;
__assign_str(pciname);
for (i = 0; i < HCLGE_DESC_DATA_LEN; i++)
__entry->data[i] = le32_to_cpu(desc->data[i]);),
TP_printk("%s opcode:0x%04x %d-%d flag:0x%04x retval:0x%04x rsv:0x%04x data:%s",
__get_str(pciname), __entry->opcode,
__entry->index, __entry->num,
__entry->flag, __entry->retval, __entry->rsv,
__print_array(__entry->data,
HCLGE_DESC_DATA_LEN, sizeof(u32)))
);
DEFINE_EVENT(hclge_pf_cmd_template, hclge_pf_cmd_send,
TP_PROTO(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num)
);
DEFINE_EVENT(hclge_pf_cmd_template, hclge_pf_cmd_get,
TP_PROTO(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num)
);
DECLARE_EVENT_CLASS(hclge_pf_special_cmd_template,
TP_PROTO(struct hclge_comm_hw *hw,
__le32 *data,
int index,
int num),
TP_ARGS(hw, data, index, num),
TP_STRUCT__entry(__field(int, index)
__field(int, num)
__string(pciname, pci_name(hw->cmq.csq.pdev))
__array(u32, data, PF_DESC_LEN)),
TP_fast_assign(int i;
__entry->index = index;
__entry->num = num;
__assign_str(pciname);
for (i = 0; i < PF_DESC_LEN; i++)
__entry->data[i] = le32_to_cpu(data[i]);
),
TP_printk("%s %d-%d data:%s",
__get_str(pciname),
__entry->index, __entry->num,
__print_array(__entry->data,
PF_DESC_LEN, sizeof(u32)))
);
DEFINE_EVENT(hclge_pf_special_cmd_template, hclge_pf_special_cmd_send,
TP_PROTO(struct hclge_comm_hw *hw,
__le32 *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num));
DEFINE_EVENT(hclge_pf_special_cmd_template, hclge_pf_special_cmd_get,
TP_PROTO(struct hclge_comm_hw *hw,
__le32 *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num)
);
#endif /* _HCLGE_TRACE_H_ */
/* This must be outside ifdef _HCLGE_TRACE_H */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE hclge_trace
#include <trace/define_trace.h>
@@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2017 Hisilicon Limited. */
#ifndef __HCLGEVF_CMD_H
#define __HCLGEVF_CMD_H
#include <linux/io.h>
#include <linux/types.h>
#include "hnae3.h"
#include "hclge_comm_cmd.h"
#define HCLGEVF_CMDQ_RX_INVLD_B 0
#define HCLGEVF_CMDQ_RX_OUTVLD_B 1
struct hclgevf_hw;
struct hclgevf_dev;
#define HCLGEVF_SYNC_RX_RING_HEAD_EN_B 4
#define HCLGEVF_TQP_REG_OFFSET 0x80000
#define HCLGEVF_TQP_REG_SIZE 0x200
#define HCLGEVF_TQP_MAX_SIZE_DEV_V2 1024
#define HCLGEVF_TQP_EXT_REG_OFFSET 0x100
struct hclgevf_tqp_map {
__le16 tqp_id; /* Absolute tqp id for in this pf */
u8 tqp_vf; /* VF id */
#define HCLGEVF_TQP_MAP_TYPE_PF 0
#define HCLGEVF_TQP_MAP_TYPE_VF 1
#define HCLGEVF_TQP_MAP_TYPE_B 0
#define HCLGEVF_TQP_MAP_EN_B 1
u8 tqp_flag; /* Indicate it's pf or vf tqp */
__le16 tqp_vid; /* Virtual id in this pf/vf */
u8 rsv[18];
};
#define HCLGEVF_VECTOR_ELEMENTS_PER_CMD 10
enum hclgevf_int_type {
HCLGEVF_INT_TX = 0,
HCLGEVF_INT_RX,
HCLGEVF_INT_EVENT,
};
struct hclgevf_ctrl_vector_chain {
u8 int_vector_id;
u8 int_cause_num;
#define HCLGEVF_INT_TYPE_S 0
#define HCLGEVF_INT_TYPE_M 0x3
#define HCLGEVF_TQP_ID_S 2
#define HCLGEVF_TQP_ID_M (0x3fff << HCLGEVF_TQP_ID_S)
__le16 tqp_type_and_id[HCLGEVF_VECTOR_ELEMENTS_PER_CMD];
u8 vfid;
u8 resv;
};
#define HCLGEVF_MSIX_OFT_ROCEE_S 0
#define HCLGEVF_MSIX_OFT_ROCEE_M (0xffff << HCLGEVF_MSIX_OFT_ROCEE_S)
#define HCLGEVF_VEC_NUM_S 0
#define HCLGEVF_VEC_NUM_M (0xff << HCLGEVF_VEC_NUM_S)
struct hclgevf_query_res_cmd {
__le16 tqp_num;
__le16 reserved;
__le16 msixcap_localid_ba_nic;
__le16 msixcap_localid_ba_rocee;
__le16 vf_intr_vector_number;
__le16 rsv[7];
};
#define HCLGEVF_GRO_EN_B 0
struct hclgevf_cfg_gro_status_cmd {
u8 gro_en;
u8 rsv[23];
};
#define HCLGEVF_LINK_STS_B 0
#define HCLGEVF_LINK_STATUS BIT(HCLGEVF_LINK_STS_B)
struct hclgevf_link_status_cmd {
u8 status;
u8 rsv[23];
};
#define HCLGEVF_RING_ID_MASK 0x3ff
#define HCLGEVF_TQP_ENABLE_B 0
struct hclgevf_cfg_com_tqp_queue_cmd {
__le16 tqp_id;
__le16 stream_id;
u8 enable;
u8 rsv[19];
};
struct hclgevf_cfg_tx_queue_pointer_cmd {
__le16 tqp_id;
__le16 tx_tail;
__le16 tx_head;
__le16 fbd_num;
__le16 ring_offset;
u8 rsv[14];
};
/* this bit indicates that the driver is ready for hardware reset */
#define HCLGEVF_NIC_SW_RST_RDY_B 16
#define HCLGEVF_NIC_SW_RST_RDY BIT(HCLGEVF_NIC_SW_RST_RDY_B)
#define HCLGEVF_NIC_CMQ_DESC_NUM 1024
#define HCLGEVF_NIC_CMQ_DESC_NUM_S 3
#define HCLGEVF_QUERY_DEV_SPECS_BD_NUM 4
#define hclgevf_cmd_setup_basic_desc(desc, opcode, is_read) \
hclge_comm_cmd_setup_basic_desc(desc, opcode, is_read)
struct hclgevf_dev_specs_0_cmd {
__le32 rsv0;
__le32 mac_entry_num;
__le32 mng_entry_num;
__le16 rss_ind_tbl_size;
__le16 rss_key_size;
__le16 int_ql_max;
u8 max_non_tso_bd_num;
u8 rsv1[5];
};
#define HCLGEVF_DEF_MAX_INT_GL 0x1FE0U
struct hclgevf_dev_specs_1_cmd {
__le16 max_frm_size;
__le16 rsv0;
__le16 max_int_gl;
u8 rsv1[18];
};
int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclge_desc *desc, int num);
void hclgevf_arq_init(struct hclgevf_dev *hdev);
#endif
@@ -0,0 +1,130 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Hisilicon Limited. */
#include <net/devlink.h>
#include "hclgevf_devlink.h"
static int hclgevf_devlink_info_get(struct devlink *devlink,
struct devlink_info_req *req,
struct netlink_ext_ack *extack)
{
#define HCLGEVF_DEVLINK_FW_STRING_LEN 32
struct hclgevf_devlink_priv *priv = devlink_priv(devlink);
char version_str[HCLGEVF_DEVLINK_FW_STRING_LEN];
struct hclgevf_dev *hdev = priv->hdev;
snprintf(version_str, sizeof(version_str), "%lu.%lu.%lu.%lu",
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE3_MASK,
HNAE3_FW_VERSION_BYTE3_SHIFT),
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE2_MASK,
HNAE3_FW_VERSION_BYTE2_SHIFT),
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE1_MASK,
HNAE3_FW_VERSION_BYTE1_SHIFT),
hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE0_MASK,
HNAE3_FW_VERSION_BYTE0_SHIFT));
return devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
version_str);
}
static int hclgevf_devlink_reload_down(struct devlink *devlink,
bool netns_change,
enum devlink_reload_action action,
enum devlink_reload_limit limit,
struct netlink_ext_ack *extack)
{
struct hclgevf_devlink_priv *priv = devlink_priv(devlink);
struct hclgevf_dev *hdev = priv->hdev;
struct hnae3_handle *h = &hdev->nic;
struct pci_dev *pdev = hdev->pdev;
int ret;
if (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state)) {
dev_err(&pdev->dev, "reset is handling\n");
return -EBUSY;
}
switch (action) {
case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
rtnl_lock();
ret = hdev->nic_client->ops->reset_notify(h, HNAE3_DOWN_CLIENT);
if (ret) {
rtnl_unlock();
return ret;
}
ret = hdev->nic_client->ops->reset_notify(h,
HNAE3_UNINIT_CLIENT);
rtnl_unlock();
return ret;
default:
return -EOPNOTSUPP;
}
}
static int hclgevf_devlink_reload_up(struct devlink *devlink,
enum devlink_reload_action action,
enum devlink_reload_limit limit,
u32 *actions_performed,
struct netlink_ext_ack *extack)
{
struct hclgevf_devlink_priv *priv = devlink_priv(devlink);
struct hclgevf_dev *hdev = priv->hdev;
struct hnae3_handle *h = &hdev->nic;
int ret;
*actions_performed = BIT(action);
switch (action) {
case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
rtnl_lock();
ret = hdev->nic_client->ops->reset_notify(h, HNAE3_INIT_CLIENT);
if (ret) {
rtnl_unlock();
return ret;
}
ret = hdev->nic_client->ops->reset_notify(h, HNAE3_UP_CLIENT);
rtnl_unlock();
return ret;
default:
return -EOPNOTSUPP;
}
}
static const struct devlink_ops hclgevf_devlink_ops = {
.info_get = hclgevf_devlink_info_get,
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
.reload_down = hclgevf_devlink_reload_down,
.reload_up = hclgevf_devlink_reload_up,
};
int hclgevf_devlink_init(struct hclgevf_dev *hdev)
{
struct pci_dev *pdev = hdev->pdev;
struct hclgevf_devlink_priv *priv;
struct devlink *devlink;
devlink =
devlink_alloc(&hclgevf_devlink_ops,
sizeof(struct hclgevf_devlink_priv), &pdev->dev);
if (!devlink)
return -ENOMEM;
priv = devlink_priv(devlink);
priv->hdev = hdev;
hdev->devlink = devlink;
devlink_register(devlink);
return 0;
}
void hclgevf_devlink_uninit(struct hclgevf_dev *hdev)
{
struct devlink *devlink = hdev->devlink;
devlink_unregister(devlink);
devlink_free(devlink);
}
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Hisilicon Limited. */
#ifndef __HCLGEVF_DEVLINK_H
#define __HCLGEVF_DEVLINK_H
#include "hclgevf_main.h"
struct hclgevf_devlink_priv {
struct hclgevf_dev *hdev;
};
int hclgevf_devlink_init(struct hclgevf_dev *hdev);
void hclgevf_devlink_uninit(struct hclgevf_dev *hdev);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2017 Hisilicon Limited. */
#ifndef __HCLGEVF_MAIN_H
#define __HCLGEVF_MAIN_H
#include <linux/fs.h>
#include <linux/if_vlan.h>
#include <linux/types.h>
#include <net/devlink.h>
#include "hclge_mbx.h"
#include "hclgevf_cmd.h"
#include "hnae3.h"
#include "hclge_comm_rss.h"
#include "hclge_comm_tqp_stats.h"
#define HCLGEVF_MOD_VERSION "1.0"
#define HCLGEVF_DRIVER_NAME "hclgevf"
#define HCLGEVF_MAX_VLAN_ID 4095
#define HCLGEVF_MISC_VECTOR_NUM 0
#define HCLGEVF_INVALID_VPORT 0xffff
#define HCLGEVF_GENERAL_TASK_INTERVAL 5
#define HCLGEVF_KEEP_ALIVE_TASK_INTERVAL 2
/* This number in actual depends upon the total number of VFs
* created by physical function. But the maximum number of
* possible vector-per-VF is {VFn(1-32), VECTn(32 + 1)}.
*/
#define HCLGEVF_MAX_VF_VECTOR_NUM (32 + 1)
#define HCLGEVF_VECTOR_REG_BASE 0x20000
#define HCLGEVF_MISC_VECTOR_REG_BASE 0x20400
#define HCLGEVF_VECTOR_REG_OFFSET 0x4
#define HCLGEVF_VECTOR_VF_OFFSET 0x100000
/* bar registers for common func */
#define HCLGEVF_GRO_EN_REG 0x28000
#define HCLGEVF_RXD_ADV_LAYOUT_EN_REG 0x28008
/* bar registers for rcb */
#define HCLGEVF_RING_RX_ADDR_L_REG 0x80000
#define HCLGEVF_RING_RX_ADDR_H_REG 0x80004
#define HCLGEVF_RING_RX_BD_NUM_REG 0x80008
#define HCLGEVF_RING_RX_BD_LENGTH_REG 0x8000C
#define HCLGEVF_RING_RX_MERGE_EN_REG 0x80014
#define HCLGEVF_RING_RX_TAIL_REG 0x80018
#define HCLGEVF_RING_RX_HEAD_REG 0x8001C
#define HCLGEVF_RING_RX_FBD_NUM_REG 0x80020
#define HCLGEVF_RING_RX_OFFSET_REG 0x80024
#define HCLGEVF_RING_RX_FBD_OFFSET_REG 0x80028
#define HCLGEVF_RING_RX_STASH_REG 0x80030
#define HCLGEVF_RING_RX_BD_ERR_REG 0x80034
#define HCLGEVF_RING_TX_ADDR_L_REG 0x80040
#define HCLGEVF_RING_TX_ADDR_H_REG 0x80044
#define HCLGEVF_RING_TX_BD_NUM_REG 0x80048
#define HCLGEVF_RING_TX_PRIORITY_REG 0x8004C
#define HCLGEVF_RING_TX_TC_REG 0x80050
#define HCLGEVF_RING_TX_MERGE_EN_REG 0x80054
#define HCLGEVF_RING_TX_TAIL_REG 0x80058
#define HCLGEVF_RING_TX_HEAD_REG 0x8005C
#define HCLGEVF_RING_TX_FBD_NUM_REG 0x80060
#define HCLGEVF_RING_TX_OFFSET_REG 0x80064
#define HCLGEVF_RING_TX_EBD_NUM_REG 0x80068
#define HCLGEVF_RING_TX_EBD_OFFSET_REG 0x80070
#define HCLGEVF_RING_TX_BD_ERR_REG 0x80074
#define HCLGEVF_RING_EN_REG 0x80090
/* bar registers for tqp interrupt */
#define HCLGEVF_TQP_INTR_CTRL_REG 0x20000
#define HCLGEVF_TQP_INTR_GL0_REG 0x20100
#define HCLGEVF_TQP_INTR_GL1_REG 0x20200
#define HCLGEVF_TQP_INTR_GL2_REG 0x20300
#define HCLGEVF_TQP_INTR_RL_REG 0x20900
/* CMDQ register bits for RX event(=MBX event) */
#define HCLGEVF_VECTOR0_RX_CMDQ_INT_B 1
/* RST register bits for RESET event */
#define HCLGEVF_VECTOR0_RST_INT_B 2
#define HCLGEVF_TQP_RESET_TRY_TIMES 10
/* Reset related Registers */
#define HCLGEVF_RST_ING 0x20C00
#define HCLGEVF_FUN_RST_ING_BIT BIT(0)
#define HCLGEVF_GLOBAL_RST_ING_BIT BIT(5)
#define HCLGEVF_CORE_RST_ING_BIT BIT(6)
#define HCLGEVF_IMP_RST_ING_BIT BIT(7)
#define HCLGEVF_RST_ING_BITS \
(HCLGEVF_FUN_RST_ING_BIT | HCLGEVF_GLOBAL_RST_ING_BIT | \
HCLGEVF_CORE_RST_ING_BIT | HCLGEVF_IMP_RST_ING_BIT)
#define HCLGEVF_VF_RST_ING 0x07008
#define HCLGEVF_VF_RST_ING_BIT BIT(16)
#define HCLGEVF_WAIT_RESET_DONE 100
#define HCLGEVF_RSS_IND_TBL_SIZE 512
#define HCLGEVF_TQP_MEM_SIZE 0x10000
#define HCLGEVF_MEM_BAR 4
/* in the bar4, the first half is for roce, and the second half is for nic */
#define HCLGEVF_NIC_MEM_OFFSET(hdev) \
(pci_resource_len((hdev)->pdev, HCLGEVF_MEM_BAR) >> 1)
#define HCLGEVF_TQP_MEM_OFFSET(hdev, i) \
(HCLGEVF_NIC_MEM_OFFSET(hdev) + HCLGEVF_TQP_MEM_SIZE * (i))
#define HCLGEVF_MAC_MAX_FRAME 9728
#define HCLGEVF_STATS_TIMER_INTERVAL 36U
#define hclgevf_read_dev(a, reg) \
hclge_comm_read_reg((a)->hw.io_base, reg)
#define hclgevf_write_dev(a, reg, value) \
hclge_comm_write_reg((a)->hw.io_base, reg, value)
enum hclgevf_evt_cause {
HCLGEVF_VECTOR0_EVENT_RST,
HCLGEVF_VECTOR0_EVENT_MBX,
HCLGEVF_VECTOR0_EVENT_OTHER,
};
/* states of hclgevf device & tasks */
enum hclgevf_states {
/* device states */
HCLGEVF_STATE_DOWN,
HCLGEVF_STATE_DISABLED,
HCLGEVF_STATE_IRQ_INITED,
HCLGEVF_STATE_REMOVING,
HCLGEVF_STATE_NIC_REGISTERED,
HCLGEVF_STATE_ROCE_REGISTERED,
HCLGEVF_STATE_SERVICE_INITED,
/* task states */
HCLGEVF_STATE_RST_SERVICE_SCHED,
HCLGEVF_STATE_RST_HANDLING,
HCLGEVF_STATE_MBX_SERVICE_SCHED,
HCLGEVF_STATE_MBX_HANDLING,
HCLGEVF_STATE_LINK_UPDATING,
HCLGEVF_STATE_PROMISC_CHANGED,
HCLGEVF_STATE_RST_FAIL,
HCLGEVF_STATE_PF_PUSH_LINK_STATUS,
};
struct hclgevf_mac {
u8 media_type;
u8 module_type;
u8 mac_addr[ETH_ALEN];
int link;
u8 duplex;
u32 speed;
u64 supported;
u64 advertising;
};
struct hclgevf_hw {
struct hclge_comm_hw hw;
int num_vec;
struct hclgevf_mac mac;
};
struct hclgevf_cfg {
u8 tc_num;
u16 tqp_desc_num;
u16 rx_buf_len;
u8 phy_addr;
u8 media_type;
u8 mac_addr[ETH_ALEN];
u32 numa_node_map;
};
struct hclgevf_misc_vector {
u8 __iomem *addr;
int vector_irq;
char name[HNAE3_INT_NAME_LEN];
};
struct hclgevf_rst_stats {
u32 rst_cnt; /* the number of reset */
u32 vf_func_rst_cnt; /* the number of VF function reset */
u32 flr_rst_cnt; /* the number of FLR */
u32 vf_rst_cnt; /* the number of VF reset */
u32 rst_done_cnt; /* the number of reset completed */
u32 hw_rst_done_cnt; /* the number of HW reset completed */
u32 rst_fail_cnt; /* the number of VF reset fail */
};
enum HCLGEVF_MAC_ADDR_TYPE {
HCLGEVF_MAC_ADDR_UC,
HCLGEVF_MAC_ADDR_MC
};
enum HCLGEVF_MAC_NODE_STATE {
HCLGEVF_MAC_TO_ADD,
HCLGEVF_MAC_TO_DEL,
HCLGEVF_MAC_ACTIVE
};
struct hclgevf_mac_addr_node {
struct list_head node;
enum HCLGEVF_MAC_NODE_STATE state;
u8 mac_addr[ETH_ALEN];
};
struct hclgevf_mac_table_cfg {
spinlock_t mac_list_lock; /* protect mac address need to add/detele */
struct list_head uc_mac_list;
struct list_head mc_mac_list;
};
struct hclgevf_dev {
struct pci_dev *pdev;
struct hnae3_ae_dev *ae_dev;
struct hclgevf_hw hw;
struct hclgevf_misc_vector misc_vector;
struct hclge_comm_rss_cfg rss_cfg;
unsigned long state;
unsigned long flr_state;
unsigned long default_reset_request;
unsigned long last_reset_time;
enum hnae3_reset_type reset_level;
unsigned long reset_pending;
enum hnae3_reset_type reset_type;
struct timer_list reset_timer;
#define HCLGEVF_RESET_REQUESTED 0
#define HCLGEVF_RESET_PENDING 1
unsigned long reset_state; /* requested, pending */
struct hclgevf_rst_stats rst_stats;
u32 reset_attempts;
struct semaphore reset_sem; /* protect reset process */
u32 fw_version;
u16 mbx_api_version;
u16 num_tqps; /* num task queue pairs of this VF */
u16 alloc_rss_size; /* allocated RSS task queue */
u16 rss_size_max; /* HW defined max RSS task queue */
u16 num_alloc_vport; /* num vports this driver supports */
nodemask_t numa_node_mask;
u16 rx_buf_len;
u16 num_tx_desc; /* desc num of per tx queue */
u16 num_rx_desc; /* desc num of per rx queue */
u8 hw_tc_map;
u8 has_pf_mac;
u16 num_msi;
u16 num_msi_left;
u16 num_msi_used;
u16 num_nic_msix; /* Num of nic vectors for this VF */
u16 num_roce_msix; /* Num of roce vectors for this VF */
u16 roce_base_msix_offset;
u16 *vector_status;
int *vector_irq;
bool gro_en;
bool rxvtag_strip_en;
unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)];
struct hclgevf_mac_table_cfg mac_table;
struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */
struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */
struct delayed_work service_task;
struct hclge_comm_tqp *htqp;
struct hnae3_handle nic;
struct hnae3_handle roce;
struct hnae3_client *nic_client;
struct hnae3_client *roce_client;
u32 flag;
unsigned long serv_processed_cnt;
unsigned long last_serv_processed;
struct devlink *devlink;
};
static inline bool hclgevf_is_reset_pending(struct hclgevf_dev *hdev)
{
return !!hdev->reset_pending;
}
int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev,
struct hclge_vf_to_pf_msg *send_msg, bool need_resp,
u8 *resp_data, u16 resp_len);
void hclgevf_mbx_handler(struct hclgevf_dev *hdev);
void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev);
void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state);
void hclgevf_update_speed_duplex(struct hclgevf_dev *hdev, u32 speed,
u8 duplex);
void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev);
void hclgevf_mbx_task_schedule(struct hclgevf_dev *hdev);
void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state,
struct hclge_mbx_port_base_vlan *port_base_vlan);
struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle);
#endif
@@ -0,0 +1,388 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hclge_mbx.h"
#include "hclgevf_main.h"
#include "hnae3.h"
#define CREATE_TRACE_POINTS
#include "hclgevf_trace.h"
static int hclgevf_resp_to_errno(u16 resp_code)
{
return resp_code ? -resp_code : 0;
}
#define HCLGEVF_MBX_MATCH_ID_START 1
static void hclgevf_reset_mbx_resp_status(struct hclgevf_dev *hdev)
{
/* this function should be called with mbx_resp.mbx_mutex held
* to protect the received_response from race condition
*/
hdev->mbx_resp.received_resp = false;
hdev->mbx_resp.origin_mbx_msg = 0;
hdev->mbx_resp.resp_status = 0;
hdev->mbx_resp.match_id++;
/* Update match_id and ensure the value of match_id is not zero */
if (hdev->mbx_resp.match_id == 0)
hdev->mbx_resp.match_id = HCLGEVF_MBX_MATCH_ID_START;
memset(hdev->mbx_resp.additional_info, 0, HCLGE_MBX_MAX_RESP_DATA_SIZE);
}
/* hclgevf_get_mbx_resp: used to get a response from PF after VF sends a mailbox
* message to PF.
* @hdev: pointer to struct hclgevf_dev
* @code0: the message opcode VF send to PF.
* @code1: the message sub-opcode VF send to PF.
* @resp_data: pointer to store response data from PF to VF.
* @resp_len: the length of resp_data from PF to VF.
*/
static int hclgevf_get_mbx_resp(struct hclgevf_dev *hdev, u16 code0, u16 code1,
u8 *resp_data, u16 resp_len)
{
#define HCLGEVF_MAX_TRY_TIMES 500
#define HCLGEVF_SLEEP_USECOND 1000
struct hclgevf_mbx_resp_status *mbx_resp;
u16 r_code0, r_code1;
int i = 0;
if (resp_len > HCLGE_MBX_MAX_RESP_DATA_SIZE) {
dev_err(&hdev->pdev->dev,
"VF mbx response len(=%u) exceeds maximum(=%u)\n",
resp_len,
HCLGE_MBX_MAX_RESP_DATA_SIZE);
return -EINVAL;
}
while ((!hdev->mbx_resp.received_resp) && (i < HCLGEVF_MAX_TRY_TIMES)) {
if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE,
&hdev->hw.hw.comm_state))
return -EIO;
usleep_range(HCLGEVF_SLEEP_USECOND, HCLGEVF_SLEEP_USECOND * 2);
i++;
}
/* ensure additional_info will be seen after received_resp */
smp_rmb();
if (i >= HCLGEVF_MAX_TRY_TIMES) {
dev_err(&hdev->pdev->dev,
"VF could not get mbx(%u,%u) resp(=%d) from PF in %d tries\n",
code0, code1, hdev->mbx_resp.received_resp, i);
return -EIO;
}
mbx_resp = &hdev->mbx_resp;
r_code0 = (u16)(mbx_resp->origin_mbx_msg >> 16);
r_code1 = (u16)(mbx_resp->origin_mbx_msg & 0xff);
if (mbx_resp->resp_status)
return mbx_resp->resp_status;
if (resp_data)
memcpy(resp_data, &mbx_resp->additional_info[0], resp_len);
hclgevf_reset_mbx_resp_status(hdev);
if (!(r_code0 == code0 && r_code1 == code1 && !mbx_resp->resp_status)) {
dev_err(&hdev->pdev->dev,
"VF could not match resp code(code0=%u,code1=%u), %d\n",
code0, code1, mbx_resp->resp_status);
dev_err(&hdev->pdev->dev,
"VF could not match resp r_code(r_code0=%u,r_code1=%u)\n",
r_code0, r_code1);
return -EIO;
}
return 0;
}
int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev,
struct hclge_vf_to_pf_msg *send_msg, bool need_resp,
u8 *resp_data, u16 resp_len)
{
struct hclge_mbx_vf_to_pf_cmd *req;
struct hclge_desc desc;
int status;
req = (struct hclge_mbx_vf_to_pf_cmd *)desc.data;
if (!send_msg) {
dev_err(&hdev->pdev->dev,
"failed to send mbx, msg is NULL\n");
return -EINVAL;
}
hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_MBX_VF_TO_PF, false);
if (need_resp)
hnae3_set_bit(req->mbx_need_resp, HCLGE_MBX_NEED_RESP_B, 1);
memcpy(&req->msg, send_msg, sizeof(struct hclge_vf_to_pf_msg));
if (test_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state))
trace_hclge_vf_mbx_send(hdev, req);
/* synchronous send */
if (need_resp) {
mutex_lock(&hdev->mbx_resp.mbx_mutex);
hclgevf_reset_mbx_resp_status(hdev);
req->match_id = cpu_to_le16(hdev->mbx_resp.match_id);
status = hclgevf_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev,
"VF failed(=%d) to send mbx message to PF\n",
status);
mutex_unlock(&hdev->mbx_resp.mbx_mutex);
return status;
}
status = hclgevf_get_mbx_resp(hdev, send_msg->code,
send_msg->subcode, resp_data,
resp_len);
mutex_unlock(&hdev->mbx_resp.mbx_mutex);
} else {
/* asynchronous send */
status = hclgevf_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev,
"VF failed(=%d) to send mbx message to PF\n",
status);
return status;
}
}
return status;
}
static bool hclgevf_cmd_crq_empty(struct hclgevf_hw *hw)
{
u32 tail = hclgevf_read_dev(hw, HCLGE_COMM_NIC_CRQ_TAIL_REG);
return tail == (u32)hw->hw.cmq.crq.next_to_use;
}
static void hclgevf_handle_mbx_response(struct hclgevf_dev *hdev,
struct hclge_mbx_pf_to_vf_cmd *req)
{
u16 vf_mbx_msg_subcode = le16_to_cpu(req->msg.vf_mbx_msg_subcode);
u16 vf_mbx_msg_code = le16_to_cpu(req->msg.vf_mbx_msg_code);
struct hclgevf_mbx_resp_status *resp = &hdev->mbx_resp;
u16 resp_status = le16_to_cpu(req->msg.resp_status);
u16 match_id = le16_to_cpu(req->match_id);
if (resp->received_resp)
dev_warn(&hdev->pdev->dev,
"VF mbx resp flag not clear(%u)\n",
vf_mbx_msg_code);
resp->origin_mbx_msg = (vf_mbx_msg_code << 16);
resp->origin_mbx_msg |= vf_mbx_msg_subcode;
resp->resp_status = hclgevf_resp_to_errno(resp_status);
memcpy(resp->additional_info, req->msg.resp_data,
HCLGE_MBX_MAX_RESP_DATA_SIZE * sizeof(u8));
/* ensure additional_info will be seen before setting received_resp */
smp_wmb();
if (match_id) {
/* If match_id is not zero, it means PF support match_id.
* if the match_id is right, VF get the right response, or
* ignore the response. and driver will clear hdev->mbx_resp
* when send next message which need response.
*/
if (match_id == resp->match_id)
resp->received_resp = true;
} else {
resp->received_resp = true;
}
}
static void hclgevf_handle_mbx_msg(struct hclgevf_dev *hdev,
struct hclge_mbx_pf_to_vf_cmd *req)
{
/* we will drop the async msg if we find ARQ as full
* and continue with next message
*/
if (atomic_read(&hdev->arq.count) >=
HCLGE_MBX_MAX_ARQ_MSG_NUM) {
dev_warn(&hdev->pdev->dev,
"Async Q full, dropping msg(%u)\n",
le16_to_cpu(req->msg.code));
return;
}
/* tail the async message in arq */
memcpy(hdev->arq.msg_q[hdev->arq.tail], &req->msg,
HCLGE_MBX_MAX_ARQ_MSG_SIZE * sizeof(u16));
hclge_mbx_tail_ptr_move_arq(hdev->arq);
atomic_inc(&hdev->arq.count);
hclgevf_mbx_task_schedule(hdev);
}
void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
{
struct hclge_mbx_pf_to_vf_cmd *req;
struct hclge_comm_cmq_ring *crq;
struct hclge_desc *desc;
u16 flag;
u16 code;
crq = &hdev->hw.hw.cmq.crq;
while (!hclgevf_cmd_crq_empty(&hdev->hw)) {
if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE,
&hdev->hw.hw.comm_state)) {
dev_info(&hdev->pdev->dev, "vf crq need init\n");
return;
}
desc = &crq->desc[crq->next_to_use];
req = (struct hclge_mbx_pf_to_vf_cmd *)desc->data;
flag = le16_to_cpu(crq->desc[crq->next_to_use].flag);
code = le16_to_cpu(req->msg.code);
if (unlikely(!hnae3_get_bit(flag, HCLGEVF_CMDQ_RX_OUTVLD_B))) {
dev_warn(&hdev->pdev->dev,
"dropped invalid mailbox message, code = %u\n",
code);
/* dropping/not processing this invalid message */
crq->desc[crq->next_to_use].flag = 0;
hclge_mbx_ring_ptr_move_crq(crq);
continue;
}
trace_hclge_vf_mbx_get(hdev, req);
/* synchronous messages are time critical and need preferential
* treatment. Therefore, we need to acknowledge all the sync
* responses as quickly as possible so that waiting tasks do not
* timeout and simultaneously queue the async messages for later
* prcessing in context of mailbox task i.e. the slow path.
*/
switch (code) {
case HCLGE_MBX_PF_VF_RESP:
hclgevf_handle_mbx_response(hdev, req);
break;
case HCLGE_MBX_LINK_STAT_CHANGE:
case HCLGE_MBX_ASSERTING_RESET:
case HCLGE_MBX_LINK_STAT_MODE:
case HCLGE_MBX_PUSH_VLAN_INFO:
case HCLGE_MBX_PUSH_PROMISC_INFO:
hclgevf_handle_mbx_msg(hdev, req);
break;
default:
dev_err(&hdev->pdev->dev,
"VF received unsupported(%u) mbx msg from PF\n",
code);
break;
}
crq->desc[crq->next_to_use].flag = 0;
hclge_mbx_ring_ptr_move_crq(crq);
}
/* Write back CMDQ_RQ header pointer, M7 need this pointer */
hclgevf_write_dev(&hdev->hw, HCLGE_COMM_NIC_CRQ_HEAD_REG,
crq->next_to_use);
}
static void hclgevf_parse_promisc_info(struct hclgevf_dev *hdev,
u16 promisc_info)
{
if (!promisc_info)
dev_info(&hdev->pdev->dev,
"Promisc mode is closed by host for being untrusted.\n");
}
void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
{
struct hclge_mbx_port_base_vlan *vlan_info;
struct hclge_mbx_link_status *link_info;
struct hclge_mbx_link_mode *link_mode;
enum hnae3_reset_type reset_type;
u16 link_status, state;
__le16 *msg_q;
u16 opcode;
u8 duplex;
u32 speed;
u32 tail;
u8 flag;
u16 idx;
tail = hdev->arq.tail;
/* process all the async queue messages */
while (tail != hdev->arq.head) {
if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE,
&hdev->hw.hw.comm_state)) {
dev_info(&hdev->pdev->dev,
"vf crq need init in async\n");
return;
}
msg_q = hdev->arq.msg_q[hdev->arq.head];
opcode = le16_to_cpu(msg_q[0]);
switch (opcode) {
case HCLGE_MBX_LINK_STAT_CHANGE:
link_info = (struct hclge_mbx_link_status *)(msg_q + 1);
link_status = le16_to_cpu(link_info->link_status);
speed = le32_to_cpu(link_info->speed);
duplex = (u8)le16_to_cpu(link_info->duplex);
flag = link_info->flag;
/* update upper layer with new link link status */
hclgevf_update_speed_duplex(hdev, speed, duplex);
hclgevf_update_link_status(hdev, link_status);
if (flag & HCLGE_MBX_PUSH_LINK_STATUS_EN)
set_bit(HCLGEVF_STATE_PF_PUSH_LINK_STATUS,
&hdev->state);
break;
case HCLGE_MBX_LINK_STAT_MODE:
link_mode = (struct hclge_mbx_link_mode *)(msg_q + 1);
idx = le16_to_cpu(link_mode->idx);
if (idx)
hdev->hw.mac.supported =
le64_to_cpu(link_mode->link_mode);
else
hdev->hw.mac.advertising =
le64_to_cpu(link_mode->link_mode);
break;
case HCLGE_MBX_ASSERTING_RESET:
/* PF has asserted reset hence VF should go in pending
* state and poll for the hardware reset status till it
* has been completely reset. After this stack should
* eventually be re-initialized.
*/
reset_type =
(enum hnae3_reset_type)le16_to_cpu(msg_q[1]);
set_bit(reset_type, &hdev->reset_pending);
set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state);
hclgevf_reset_task_schedule(hdev);
break;
case HCLGE_MBX_PUSH_VLAN_INFO:
vlan_info =
(struct hclge_mbx_port_base_vlan *)(msg_q + 1);
state = le16_to_cpu(vlan_info->state);
hclgevf_update_port_base_vlan_info(hdev, state,
vlan_info);
break;
case HCLGE_MBX_PUSH_PROMISC_INFO:
hclgevf_parse_promisc_info(hdev, le16_to_cpu(msg_q[1]));
break;
default:
dev_err(&hdev->pdev->dev,
"fetched unsupported(%u) message from arq\n",
opcode);
break;
}
hclge_mbx_head_ptr_move_arq(hdev->arq);
atomic_dec(&hdev->arq.count);
msg_q = hdev->arq.msg_q[hdev->arq.head];
}
}
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2023 Hisilicon Limited.
#include "hclgevf_main.h"
#include "hclgevf_regs.h"
#include "hnae3.h"
static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG,
HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG,
HCLGE_COMM_NIC_CSQ_DEPTH_REG,
HCLGE_COMM_NIC_CSQ_TAIL_REG,
HCLGE_COMM_NIC_CSQ_HEAD_REG,
HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG,
HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG,
HCLGE_COMM_NIC_CRQ_DEPTH_REG,
HCLGE_COMM_NIC_CRQ_TAIL_REG,
HCLGE_COMM_NIC_CRQ_HEAD_REG,
HCLGE_COMM_VECTOR0_CMDQ_SRC_REG,
HCLGE_COMM_VECTOR0_CMDQ_STATE_REG,
HCLGE_COMM_CMDQ_INTR_EN_REG,
HCLGE_COMM_CMDQ_INTR_GEN_REG};
static const u32 common_reg_addr_list[] = {HCLGEVF_MISC_VECTOR_REG_BASE,
HCLGEVF_RST_ING,
HCLGEVF_GRO_EN_REG};
static const u32 ring_reg_addr_list[] = {HCLGEVF_RING_RX_ADDR_L_REG,
HCLGEVF_RING_RX_ADDR_H_REG,
HCLGEVF_RING_RX_BD_NUM_REG,
HCLGEVF_RING_RX_BD_LENGTH_REG,
HCLGEVF_RING_RX_MERGE_EN_REG,
HCLGEVF_RING_RX_TAIL_REG,
HCLGEVF_RING_RX_HEAD_REG,
HCLGEVF_RING_RX_FBD_NUM_REG,
HCLGEVF_RING_RX_OFFSET_REG,
HCLGEVF_RING_RX_FBD_OFFSET_REG,
HCLGEVF_RING_RX_STASH_REG,
HCLGEVF_RING_RX_BD_ERR_REG,
HCLGEVF_RING_TX_ADDR_L_REG,
HCLGEVF_RING_TX_ADDR_H_REG,
HCLGEVF_RING_TX_BD_NUM_REG,
HCLGEVF_RING_TX_PRIORITY_REG,
HCLGEVF_RING_TX_TC_REG,
HCLGEVF_RING_TX_MERGE_EN_REG,
HCLGEVF_RING_TX_TAIL_REG,
HCLGEVF_RING_TX_HEAD_REG,
HCLGEVF_RING_TX_FBD_NUM_REG,
HCLGEVF_RING_TX_OFFSET_REG,
HCLGEVF_RING_TX_EBD_NUM_REG,
HCLGEVF_RING_TX_EBD_OFFSET_REG,
HCLGEVF_RING_TX_BD_ERR_REG,
HCLGEVF_RING_EN_REG};
static const u32 tqp_intr_reg_addr_list[] = {HCLGEVF_TQP_INTR_CTRL_REG,
HCLGEVF_TQP_INTR_GL0_REG,
HCLGEVF_TQP_INTR_GL1_REG,
HCLGEVF_TQP_INTR_GL2_REG,
HCLGEVF_TQP_INTR_RL_REG};
enum hclgevf_reg_tag {
HCLGEVF_REG_TAG_CMDQ = 0,
HCLGEVF_REG_TAG_COMMON,
HCLGEVF_REG_TAG_RING,
HCLGEVF_REG_TAG_TQP_INTR,
};
#pragma pack(4)
struct hclgevf_reg_tlv {
u16 tag;
u16 len;
};
struct hclgevf_reg_header {
u64 magic_number;
u8 is_vf;
u8 rsv[7];
};
#pragma pack()
#define HCLGEVF_REG_TLV_SIZE sizeof(struct hclgevf_reg_tlv)
#define HCLGEVF_REG_HEADER_SIZE sizeof(struct hclgevf_reg_header)
#define HCLGEVF_REG_TLV_SPACE (sizeof(struct hclgevf_reg_tlv) / sizeof(u32))
#define HCLGEVF_REG_HEADER_SPACE (sizeof(struct hclgevf_reg_header) / sizeof(u32))
#define HCLGEVF_REG_MAGIC_NUMBER 0x686e733372656773 /* meaning is hns3regs */
static u32 hclgevf_reg_get_header(void *data)
{
struct hclgevf_reg_header *header = data;
header->magic_number = HCLGEVF_REG_MAGIC_NUMBER;
header->is_vf = 0x1;
return HCLGEVF_REG_HEADER_SPACE;
}
static u32 hclgevf_reg_get_tlv(u32 tag, u32 regs_num, void *data)
{
struct hclgevf_reg_tlv *tlv = data;
tlv->tag = tag;
tlv->len = regs_num * sizeof(u32) + HCLGEVF_REG_TLV_SIZE;
return HCLGEVF_REG_TLV_SPACE;
}
int hclgevf_get_regs_len(struct hnae3_handle *handle)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
int cmdq_len, common_len, ring_len, tqp_intr_len;
cmdq_len = HCLGEVF_REG_TLV_SIZE + sizeof(cmdq_reg_addr_list);
common_len = HCLGEVF_REG_TLV_SIZE + sizeof(common_reg_addr_list);
ring_len = HCLGEVF_REG_TLV_SIZE + sizeof(ring_reg_addr_list);
tqp_intr_len = HCLGEVF_REG_TLV_SIZE + sizeof(tqp_intr_reg_addr_list);
/* return the total length of all register values */
return HCLGEVF_REG_HEADER_SIZE + cmdq_len + common_len +
tqp_intr_len * (hdev->num_msi_used - 1) +
ring_len * hdev->num_tqps;
}
void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version,
void *data)
{
#define HCLGEVF_RING_INT_REG_OFFSET 0x4
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
struct hnae3_queue *tqp;
int i, j, reg_num;
u32 *reg = data;
*version = hdev->fw_version;
reg += hclgevf_reg_get_header(reg);
/* fetching per-VF registers values from VF PCIe register space */
reg_num = ARRAY_SIZE(cmdq_reg_addr_list);
reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_CMDQ, reg_num, reg);
for (i = 0; i < reg_num; i++)
*reg++ = hclgevf_read_dev(&hdev->hw, cmdq_reg_addr_list[i]);
reg_num = ARRAY_SIZE(common_reg_addr_list);
reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_COMMON, reg_num, reg);
for (i = 0; i < reg_num; i++)
*reg++ = hclgevf_read_dev(&hdev->hw, common_reg_addr_list[i]);
reg_num = ARRAY_SIZE(ring_reg_addr_list);
for (j = 0; j < hdev->num_tqps; j++) {
reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_RING, reg_num, reg);
tqp = &hdev->htqp[j].q;
for (i = 0; i < reg_num; i++)
*reg++ = readl_relaxed(tqp->io_base -
HCLGEVF_TQP_REG_OFFSET +
ring_reg_addr_list[i]);
}
reg_num = ARRAY_SIZE(tqp_intr_reg_addr_list);
for (j = 0; j < hdev->num_msi_used - 1; j++) {
reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_TQP_INTR,
reg_num, reg);
for (i = 0; i < reg_num; i++)
*reg++ = hclgevf_read_dev(&hdev->hw,
tqp_intr_reg_addr_list[i] +
HCLGEVF_RING_INT_REG_OFFSET * j);
}
}
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2023 Hisilicon Limited. */
#ifndef __HCLGEVF_REGS_H
#define __HCLGEVF_REGS_H
#include <linux/types.h>
struct hnae3_handle;
int hclgevf_get_regs_len(struct hnae3_handle *handle);
void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version,
void *data);
#endif
@@ -0,0 +1,137 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2019 Hisilicon Limited. */
/* This must be outside ifdef _HCLGEVF_TRACE_H */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hns3
#if !defined(_HCLGEVF_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _HCLGEVF_TRACE_H_
#include <linux/tracepoint.h>
#define VF_GET_MBX_LEN (sizeof(struct hclge_mbx_pf_to_vf_cmd) / sizeof(u32))
#define VF_SEND_MBX_LEN (sizeof(struct hclge_mbx_vf_to_pf_cmd) / sizeof(u32))
TRACE_EVENT(hclge_vf_mbx_get,
TP_PROTO(
struct hclgevf_dev *hdev,
struct hclge_mbx_pf_to_vf_cmd *req),
TP_ARGS(hdev, req),
TP_STRUCT__entry(
__field(u8, vfid)
__field(u16, code)
__string(pciname, pci_name(hdev->pdev))
__string(devname, hdev->nic.kinfo.netdev->name)
__array(u32, mbx_data, VF_GET_MBX_LEN)
),
TP_fast_assign(
__entry->vfid = req->dest_vfid;
__entry->code = le16_to_cpu(req->msg.code);
__assign_str(pciname);
__assign_str(devname);
memcpy(__entry->mbx_data, req,
sizeof(struct hclge_mbx_pf_to_vf_cmd));
),
TP_printk(
"%s %s vfid:%u code:%u data:%s",
__get_str(pciname), __get_str(devname), __entry->vfid,
__entry->code,
__print_array(__entry->mbx_data, VF_GET_MBX_LEN, sizeof(u32))
)
);
TRACE_EVENT(hclge_vf_mbx_send,
TP_PROTO(
struct hclgevf_dev *hdev,
struct hclge_mbx_vf_to_pf_cmd *req),
TP_ARGS(hdev, req),
TP_STRUCT__entry(
__field(u8, vfid)
__field(u8, code)
__field(u8, subcode)
__string(pciname, pci_name(hdev->pdev))
__string(devname, hdev->nic.kinfo.netdev->name)
__array(u32, mbx_data, VF_SEND_MBX_LEN)
),
TP_fast_assign(
__entry->vfid = req->mbx_src_vfid;
__entry->code = req->msg.code;
__entry->subcode = req->msg.subcode;
__assign_str(pciname);
__assign_str(devname);
memcpy(__entry->mbx_data, req,
sizeof(struct hclge_mbx_vf_to_pf_cmd));
),
TP_printk(
"%s %s vfid:%u code:%u subcode:%u data:%s",
__get_str(pciname), __get_str(devname), __entry->vfid,
__entry->code, __entry->subcode,
__print_array(__entry->mbx_data, VF_SEND_MBX_LEN, sizeof(u32))
)
);
DECLARE_EVENT_CLASS(hclge_vf_cmd_template,
TP_PROTO(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num),
TP_STRUCT__entry(__field(u16, opcode)
__field(u16, flag)
__field(u16, retval)
__field(u16, rsv)
__field(int, index)
__field(int, num)
__string(pciname, pci_name(hw->cmq.csq.pdev))
__array(u32, data, HCLGE_DESC_DATA_LEN)),
TP_fast_assign(int i;
__entry->opcode = le16_to_cpu(desc->opcode);
__entry->flag = le16_to_cpu(desc->flag);
__entry->retval = le16_to_cpu(desc->retval);
__entry->rsv = le16_to_cpu(desc->rsv);
__entry->index = index;
__entry->num = num;
__assign_str(pciname);
for (i = 0; i < HCLGE_DESC_DATA_LEN; i++)
__entry->data[i] = le32_to_cpu(desc->data[i]);),
TP_printk("%s opcode:0x%04x %d-%d flag:0x%04x retval:0x%04x rsv:0x%04x data:%s",
__get_str(pciname), __entry->opcode,
__entry->index, __entry->num,
__entry->flag, __entry->retval, __entry->rsv,
__print_array(__entry->data,
HCLGE_DESC_DATA_LEN, sizeof(u32)))
);
DEFINE_EVENT(hclge_vf_cmd_template, hclge_vf_cmd_send,
TP_PROTO(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num));
DEFINE_EVENT(hclge_vf_cmd_template, hclge_vf_cmd_get,
TP_PROTO(struct hclge_comm_hw *hw,
struct hclge_desc *desc,
int index,
int num),
TP_ARGS(hw, desc, index, num));
#endif /* _HCLGEVF_TRACE_H_ */
/* This must be outside ifdef _HCLGEVF_TRACE_H */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE hclgevf_trace
#include <trace/define_trace.h>