From: Yufeng Mo moyufeng@huawei.com
mainline inclusion from mainline-v5.12-rc1-dontuse commit eb0faf32b86e208049b6432197bfeeeac8580fe1 category: feature bugzilla: 173966 CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------------------------------------
hclgevf_cmd_send() is bloated, so split it into separate functions for readability and maintainability.
Signed-off-by: Yufeng Mo moyufeng@huawei.com Signed-off-by: Huazhong Tan tanhuazhong@huawei.com Signed-off-by: David S. Miller davem@davemloft.net Reviewed-by: Yongxin Li liyongxin1@huawei.com Signed-off-by: Junxin Chen chenjunxin1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../hisilicon/hns3/hns3vf/hclgevf_cmd.c | 141 ++++++++++-------- 1 file changed, 81 insertions(+), 60 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index 603665e5bf39..46700c427849 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -181,6 +181,22 @@ struct vf_errcode { int common_errno; };
+static void hclgevf_cmd_copy_desc(struct hclgevf_hw *hw, + struct hclgevf_desc *desc, int num) +{ + struct hclgevf_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 hclgevf_cmd_convert_err_code(u16 desc_ret) { struct vf_errcode hclgevf_cmd_errcode[] = { @@ -207,6 +223,66 @@ static int hclgevf_cmd_convert_err_code(u16 desc_ret) return -EIO; }
+static int hclgevf_cmd_check_retval(struct hclgevf_hw *hw, + struct hclgevf_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++) { + /* Get the result of hardware write back */ + desc[handle] = hw->cmq.csq.desc[ntc]; + ntc++; + if (ntc == hw->cmq.csq.desc_num) + ntc = 0; + } + if (likely(!hclgevf_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 hclgevf_cmd_convert_err_code(desc_ret); +} + +static int hclgevf_cmd_check_result(struct hclgevf_hw *hw, + struct hclgevf_desc *desc, int num, int ntc) +{ + struct hclgevf_dev *hdev = (struct hclgevf_dev *)hw->hdev; + 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 (HCLGEVF_SEND_SYNC(le16_to_cpu(desc->flag))) { + do { + if (hclgevf_cmd_csq_done(hw)) { + is_completed = true; + break; + } + udelay(1); + timeout++; + } while (timeout < hw->cmq.tx_timeout); + } + + if (!is_completed) + ret = -EBADE; + else + ret = hclgevf_cmd_check_retval(hw, desc, num, ntc); + + /* Clean the command send queue */ + handle = hclgevf_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; +} + /* hclgevf_cmd_send - send command to command queue * @hw: pointer to the hw struct * @desc: prefilled descriptor for describing the command @@ -219,13 +295,7 @@ int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclgevf_desc *desc, int num) { struct hclgevf_dev *hdev = (struct hclgevf_dev *)hw->hdev; struct hclgevf_cmq_ring *csq = &hw->cmq.csq; - struct hclgevf_desc *desc_to_use; - bool complete = false; - u32 timeout = 0; - int handle = 0; - int status = 0; - u16 retval; - u16 opcode; + int ret; int ntc;
spin_lock_bh(&hw->cmq.csq.lock); @@ -249,67 +319,18 @@ int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclgevf_desc *desc, int num) * which will be use for hardware to write back */ ntc = hw->cmq.csq.next_to_use; - opcode = le16_to_cpu(desc[0].opcode); - 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++; - } + + hclgevf_cmd_copy_desc(hw, desc, num);
/* Write to hardware */ hclgevf_write_dev(hw, HCLGEVF_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 (HCLGEVF_SEND_SYNC(le16_to_cpu(desc->flag))) { - do { - if (hclgevf_cmd_csq_done(hw)) - break; - udelay(1); - timeout++; - } while (timeout < hw->cmq.tx_timeout); - } - - if (hclgevf_cmd_csq_done(hw)) { - complete = true; - handle = 0; - - while (handle < num) { - /* Get the result of hardware write back */ - desc_to_use = &hw->cmq.csq.desc[ntc]; - desc[handle] = *desc_to_use; - - if (likely(!hclgevf_is_special_opcode(opcode))) - retval = le16_to_cpu(desc[handle].retval); - else - retval = le16_to_cpu(desc[0].retval); - - status = hclgevf_cmd_convert_err_code(retval); - hw->cmq.last_status = (enum hclgevf_cmd_status)retval; - ntc++; - handle++; - if (ntc == hw->cmq.csq.desc_num) - ntc = 0; - } - } - - if (!complete) - status = -EBADE; - - /* Clean the command send queue */ - handle = hclgevf_cmd_csq_clean(hw); - if (handle != num) - dev_warn(&hdev->pdev->dev, - "cleaned %d, need to clean %d\n", handle, num); + ret = hclgevf_cmd_check_result(hw, desc, num, ntc);
spin_unlock_bh(&hw->cmq.csq.lock);
- return status; + return ret; }
static void hclgevf_set_default_capability(struct hclgevf_dev *hdev)