diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
commit | ace9429bb58fd418f0c81d4c2835699bddf6bde6 (patch) | |
tree | b2d64bc10158fdd5497876388cd68142ca374ed3 /drivers/net/ethernet/hisilicon/hns3/hns3_common | |
parent | Initial commit. (diff) | |
download | linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.tar.xz linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.zip |
Adding upstream version 6.6.15.upstream/6.6.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/net/ethernet/hisilicon/hns3/hns3_common')
6 files changed, 1921 insertions, 0 deletions
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c new file mode 100644 index 0000000000..dcecb23daa --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c @@ -0,0 +1,654 @@ +// 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); +} + +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); +} + +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}, +}; + +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 == 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_TX_TIMEOUT_500MS}, + }; + 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) +{ + struct hclge_comm_cmq_ring *csq = &hw->cmq.csq; + int ret; + int ntc; + + 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); + + return ret; +} + +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); +} + +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; +} + +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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h new file mode 100644 index 0000000000..2b7197ce0a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h @@ -0,0 +1,476 @@ +/* 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_TX_TIMEOUT_500MS 500000 + +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_QUERY_DEV_SPECS = 0x0050, + + /* 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, + + /* 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_LANE_NUM_B = 27, + HCLGE_COMM_CAP_WOL_B = 28, + HCLGE_COMM_CAP_TM_FLUSH_B = 31, +}; + +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 */ +}; + +#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_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_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); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c new file mode 100644 index 0000000000..b4ae2160af --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c @@ -0,0 +1,504 @@ +// 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; +} + +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; + } +} + +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; +} + +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; +} + +int hclge_comm_set_rss_tuple(struct hnae3_ae_dev *ae_dev, + struct hclge_comm_hw *hw, + struct hclge_comm_rss_cfg *rss_cfg, + struct ethtool_rxnfc *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; +} + +u32 hclge_comm_get_rss_key_size(struct hnae3_handle *handle) +{ + return HCLGE_COMM_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; +} + +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; +} + +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; +} + +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; +} + +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); +} + +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]; +} + +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; +} + +static u8 hclge_comm_get_rss_hash_bits(struct ethtool_rxnfc *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, + struct ethtool_rxnfc *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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h new file mode 100644 index 0000000000..cdafa63fe3 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h @@ -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, + struct ethtool_rxnfc *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, + struct ethtool_rxnfc *nfc); +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c new file mode 100644 index 0000000000..f3c9395d83 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c @@ -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; +} + +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; +} + +u8 *hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 *data) +{ + struct hnae3_knic_private_info *kinfo = &handle->kinfo; + u8 *buff = data; + 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); + snprintf(buff, ETH_GSTRING_LEN, "txq%u_pktnum_rcd", tqp->index); + buff += ETH_GSTRING_LEN; + } + + for (i = 0; i < kinfo->num_tqps; i++) { + struct hclge_comm_tqp *tqp = + container_of(kinfo->tqp[i], struct hclge_comm_tqp, q); + snprintf(buff, ETH_GSTRING_LEN, "rxq%u_pktnum_rcd", tqp->index); + buff += ETH_GSTRING_LEN; + } + + return buff; +} + +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 & 0x1ff); + 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; +} + +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)); + } +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h new file mode 100644 index 0000000000..a46350162e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h @@ -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); +u8 *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 |