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,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