diff options
Diffstat (limited to 'drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c')
-rw-r--r-- | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 165 |
1 files changed, 96 insertions, 69 deletions
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index b728be4737f8..1bd0ddfaec4d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -189,38 +189,53 @@ static bool hclge_is_special_opcode(u16 opcode) return false; } -static int hclge_cmd_convert_err_code(u16 desc_ret) +struct errcode { + u32 imp_errcode; + int common_errno; +}; + +static void hclge_cmd_copy_desc(struct hclge_hw *hw, struct hclge_desc *desc, + int num) { - switch (desc_ret) { - case HCLGE_CMD_EXEC_SUCCESS: - return 0; - case HCLGE_CMD_NO_AUTH: - return -EPERM; - case HCLGE_CMD_NOT_SUPPORTED: - return -EOPNOTSUPP; - case HCLGE_CMD_QUEUE_FULL: - return -EXFULL; - case HCLGE_CMD_NEXT_ERR: - return -ENOSR; - case HCLGE_CMD_UNEXE_ERR: - return -ENOTBLK; - case HCLGE_CMD_PARA_ERR: - return -EINVAL; - case HCLGE_CMD_RESULT_ERR: - return -ERANGE; - case HCLGE_CMD_TIMEOUT: - return -ETIME; - case HCLGE_CMD_HILINK_ERR: - return -ENOLINK; - case HCLGE_CMD_QUEUE_ILLEGAL: - return -ENXIO; - case HCLGE_CMD_INVALID: - return -EBADR; - default: - return -EIO; + 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_cmd_convert_err_code(u16 desc_ret) +{ + struct errcode hclge_cmd_errcode[] = { + {HCLGE_CMD_EXEC_SUCCESS, 0}, + {HCLGE_CMD_NO_AUTH, -EPERM}, + {HCLGE_CMD_NOT_SUPPORTED, -EOPNOTSUPP}, + {HCLGE_CMD_QUEUE_FULL, -EXFULL}, + {HCLGE_CMD_NEXT_ERR, -ENOSR}, + {HCLGE_CMD_UNEXE_ERR, -ENOTBLK}, + {HCLGE_CMD_PARA_ERR, -EINVAL}, + {HCLGE_CMD_RESULT_ERR, -ERANGE}, + {HCLGE_CMD_TIMEOUT, -ETIME}, + {HCLGE_CMD_HILINK_ERR, -ENOLINK}, + {HCLGE_CMD_QUEUE_ILLEGAL, -ENXIO}, + {HCLGE_CMD_INVALID, -EBADR}, + }; + u32 errcode_count = ARRAY_SIZE(hclge_cmd_errcode); + u32 i; + + for (i = 0; i < errcode_count; i++) + if (hclge_cmd_errcode[i].imp_errcode == desc_ret) + return hclge_cmd_errcode[i].common_errno; + + return -EIO; +} + static int hclge_cmd_check_retval(struct hclge_hw *hw, struct hclge_desc *desc, int num, int ntc) { @@ -244,6 +259,44 @@ static int hclge_cmd_check_retval(struct hclge_hw *hw, struct hclge_desc *desc, return hclge_cmd_convert_err_code(desc_ret); } +static int hclge_cmd_check_result(struct hclge_hw *hw, struct hclge_desc *desc, + int num, int ntc) +{ + struct hclge_dev *hdev = container_of(hw, struct hclge_dev, hw); + bool is_completed = false; + u32 timeout = 0; + 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_SEND_SYNC(le16_to_cpu(desc->flag))) { + do { + if (hclge_cmd_csq_done(hw)) { + is_completed = true; + break; + } + udelay(1); + timeout++; + } while (timeout < hw->cmq.tx_timeout); + } + + if (!is_completed) + ret = -EBADE; + else + ret = hclge_cmd_check_retval(hw, desc, num, ntc); + + /* Clean the command send queue */ + handle = hclge_cmd_csq_clean(hw); + if (handle < 0) + ret = handle; + else if (handle != num) + dev_warn(&hdev->pdev->dev, + "cleaned %d, need to clean %d\n", handle, num); + return ret; +} + /** * hclge_cmd_send - send command to command queue * @hw: pointer to the hw struct @@ -257,11 +310,7 @@ int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num) { struct hclge_dev *hdev = container_of(hw, struct hclge_dev, hw); struct hclge_cmq_ring *csq = &hw->cmq.csq; - struct hclge_desc *desc_to_use; - bool complete = false; - u32 timeout = 0; - int handle = 0; - int retval; + int ret; int ntc; spin_lock_bh(&hw->cmq.csq.lock); @@ -285,49 +334,17 @@ int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num) * which will be use for hardware to write back */ ntc = hw->cmq.csq.next_to_use; - 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++; - } + + hclge_cmd_copy_desc(hw, desc, num); /* Write to hardware */ hclge_write_dev(hw, HCLGE_NIC_CSQ_TAIL_REG, hw->cmq.csq.next_to_use); - /** - * 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_SEND_SYNC(le16_to_cpu(desc->flag))) { - do { - if (hclge_cmd_csq_done(hw)) { - complete = true; - break; - } - udelay(1); - timeout++; - } while (timeout < hw->cmq.tx_timeout); - } - - if (!complete) - retval = -EBADE; - else - retval = hclge_cmd_check_retval(hw, desc, num, ntc); - - /* Clean the command send queue */ - handle = hclge_cmd_csq_clean(hw); - if (handle < 0) - retval = handle; - else if (handle != num) - dev_warn(&hdev->pdev->dev, - "cleaned %d, need to clean %d\n", handle, num); + ret = hclge_cmd_check_result(hw, desc, num, ntc); spin_unlock_bh(&hw->cmq.csq.lock); - return retval; + return ret; } static void hclge_set_default_capability(struct hclge_dev *hdev) @@ -363,6 +380,15 @@ static void hclge_parse_capability(struct hclge_dev *hdev, set_bit(HNAE3_DEV_SUPPORT_FD_FORWARD_TC_B, ae_dev->caps); } +static __le32 hclge_build_api_caps(void) +{ + u32 api_caps = 0; + + hnae3_set_bit(api_caps, HCLGE_API_CAP_FLEX_RSS_TBL_B, 1); + + return cpu_to_le32(api_caps); +} + static enum hclge_cmd_status hclge_cmd_query_version_and_capability(struct hclge_dev *hdev) { @@ -373,6 +399,7 @@ hclge_cmd_query_version_and_capability(struct hclge_dev *hdev) hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_FW_VER, 1); resp = (struct hclge_query_version_cmd *)desc.data; + resp->api_caps = hclge_build_api_caps(); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) |