From: Weihang Li liweihang@hisilicon.com
mainline inclusion from mainline-v5.4-rc1 commit a83d29618b1cd9176ad33fc415f5e033fd6a45a2 category: feature bugzilla: NA CVE: NA
----------------------------
When hardware or IMP get specified error it may need the client to take some special operations.
This patch implements the hns3 client's process_hw_errorx.
Signed-off-by: Weihang Li liweihang@hisilicon.com Signed-off-by: Huazhong Tan tanhuazhong@huawei.com Reviewed-by: Peng Li lipeng321@huawei.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Yonglong Liu liuyonglong@huawei.com Reviewed-by: Yongxin Li liyongxin1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 8 +++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 24 ++++++++ .../net/ethernet/hisilicon/hns3/hns3_enet.h | 5 ++ .../hisilicon/hns3/hns3pf/hclge_err.c | 35 +---------- .../hisilicon/hns3/hns3pf/hclge_main.c | 58 +++++++++++-------- .../hisilicon/hns3/hns3pf/hclge_main.h | 2 + 6 files changed, 74 insertions(+), 58 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 89906220e233..8a6e9fefc130 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -152,6 +152,12 @@ enum hnae3_reset_notify_type { HNAE3_RESTORE_CLIENT, };
+enum hnae3_hw_error_type { + HNAE3_PPU_POISON_ERROR, + HNAE3_CMDQ_ECC_ERROR, + HNAE3_IMP_RD_POISON_ERROR, +}; + enum hnae3_reset_type { HNAE3_VF_RESET, HNAE3_VF_FUNC_RESET, @@ -212,6 +218,8 @@ struct hnae3_client_ops { int (*setup_tc)(struct hnae3_handle *handle, u8 tc); int (*reset_notify)(struct hnae3_handle *handle, enum hnae3_reset_notify_type type); + void (*process_hw_error)(struct hnae3_handle *handle, + enum hnae3_hw_error_type); };
#define HNAE3_CLIENT_NAME_LENGTH 16 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 619cbef55d9c..49953ddc22d4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4647,12 +4647,36 @@ int hns3_set_channels(struct net_device *netdev, return 0; }
+static const struct hns3_hw_error_info hns3_hw_err[] = { + { .type = HNAE3_PPU_POISON_ERROR, + .msg = "PPU poison" }, + { .type = HNAE3_CMDQ_ECC_ERROR, + .msg = "IMP CMDQ error" }, + { .type = HNAE3_IMP_RD_POISON_ERROR, + .msg = "IMP RD poison" }, +}; + +static void hns3_process_hw_error(struct hnae3_handle *handle, + enum hnae3_hw_error_type type) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(hns3_hw_err); i++) { + if (hns3_hw_err[i].type == type) { + dev_err(&handle->pdev->dev, "Detected %s!\n", + hns3_hw_err[i].msg); + break; + } + } +} + const struct hnae3_client_ops client_ops = { .init_instance = hns3_client_init, .uninit_instance = hns3_client_uninit, .link_status_change = hns3_link_status_change, .setup_tc = hns3_client_setup_tc, .reset_notify = hns3_reset_notify, + .process_hw_error = hns3_process_hw_error, };
#ifndef CONFIG_IT_VALIDATION diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 4d0cef5a06da..34e045486386 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -544,6 +544,11 @@ union l4_hdr_info { unsigned char *hdr; };
+struct hns3_hw_error_info { + enum hnae3_hw_error_type type; + const char *msg; +}; + static inline int ring_space(struct hns3_enet_ring *ring) { /* This smp_load_acquire() pairs with smp_store_release() in diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index d017d9aed378..3c76eabb93a8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -676,28 +676,6 @@ static int hclge_cmd_query_error(struct hclge_dev *hdev, return ret; }
-static int hclge_check_imp_poison_err(struct hclge_dev *hdev) -{ - struct device *dev = &hdev->pdev->dev; - int ret = false; - u32 ras_status; - - ras_status = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG); - if (ras_status & HCLGE_RAS_IMP_RD_POISON_MASK) { - set_bit(HCLGE_IMP_RD_POISON, &hdev->imp_err_state); - /* This error will be handle by IMP reset */ - dev_info(dev, "IMP RD poison detected!\n"); - ret = true; - } else if (ras_status & HCLGE_RAS_IMP_CMDQ_ERR_MASK) { - set_bit(HCLGE_IMP_CMDQ_ERROR, &hdev->imp_err_state); - /* This error will be handle by IMP reset */ - dev_info(dev, "IMP CMDQ error detected!\n"); - ret = true; - } - - return ret; -} - static int hclge_clear_mac_tnl_int(struct hclge_dev *hdev) { struct hclge_desc desc; @@ -1351,7 +1329,7 @@ static int hclge_handle_pf_ras_error(struct hclge_dev *hdev, hclge_log_error(dev, "PPU_PF_ABNORMAL_INT_ST0", &hclge_ppu_pf_abnormal_int[0], status, &ae_dev->hw_err_reset_req); - hdev->ppu_poison_ras_err = true; + hclge_report_hw_error(hdev, HNAE3_PPU_POISON_ERROR); }
/* clear all PF RAS errors */ @@ -1661,7 +1639,6 @@ pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev) struct hclge_dev *hdev = ae_dev->priv; struct device *dev = &hdev->pdev->dev; u32 status; - int ret;
if (!test_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state)) { dev_err(dev, @@ -1669,9 +1646,6 @@ pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev) return PCI_ERS_RESULT_NONE; }
- if (hclge_check_imp_poison_err(hdev)) - return PCI_ERS_RESULT_RECOVERED; - status = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG);
if (status & HCLGE_RAS_REG_NFE_MASK || @@ -1685,12 +1659,7 @@ pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev) dev_err(dev, "HNS Non-Fatal RAS error(status=0x%x) identified\n", status); - ret = hclge_handle_all_ras_errors(hdev); - if (ret) { - ret = hclge_check_imp_poison_err(hdev); - if (ret) - return PCI_ERS_RESULT_RECOVERED; - } + hclge_handle_all_ras_errors(hdev); }
/* Handling Non-fatal Rocee RAS errors */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2c1c0efad80e..6b98552a6e29 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3420,6 +3420,38 @@ static void hclge_func_reset_sync_vf(struct hclge_dev *hdev) dev_warn(&hdev->pdev->dev, "sync with VF timeout!\n"); }
+void hclge_report_hw_error(struct hclge_dev *hdev, + enum hnae3_hw_error_type type) +{ + struct hnae3_client *client = hdev->nic_client; + u16 i; + + if (!client || !client->ops->process_hw_error || + !test_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state)) + return; + + for (i = 0; i < hdev->num_vmdq_vport + 1; i++) + client->ops->process_hw_error(&hdev->vport[i].nic, type); +} + +static void hclge_handle_imp_error(struct hclge_dev *hdev) +{ + u32 reg_val; + + reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG); + if (reg_val & BIT(HCLGE_VECTOR0_IMP_RD_POISON_B)) { + hclge_report_hw_error(hdev, HNAE3_IMP_RD_POISON_ERROR); + reg_val &= ~BIT(HCLGE_VECTOR0_IMP_RD_POISON_B); + hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); + } + + if (reg_val & BIT(HCLGE_VECTOR0_IMP_CMDQ_ERR_B)) { + hclge_report_hw_error(hdev, HNAE3_CMDQ_ECC_ERROR); + reg_val &= ~BIT(HCLGE_VECTOR0_IMP_CMDQ_ERR_B); + hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); + } +} + int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id) { struct hclge_desc desc; @@ -3559,7 +3591,6 @@ static int hclge_func_reset_notify_vf(struct hclge_dev *hdev)
static int hclge_reset_prepare_wait(struct hclge_dev *hdev) { - struct hnae3_handle *handle = &hdev->vport[0].nic; u32 reg_val; int ret = 0;
@@ -3590,8 +3621,7 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev) return ret; break; case HNAE3_IMP_RESET: - if (handle && handle->ae_algo->ops->handle_imp_error) - handle->ae_algo->ops->handle_imp_error(handle); + hclge_handle_imp_error(hdev); reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG); hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, BIT(HCLGE_VECTOR0_IMP_RESET_INT_B) | reg_val); @@ -3963,27 +3993,6 @@ static bool hclge_reset_done(struct hnae3_handle *handle, bool done) return done; }
-static void hclge_handle_imp_error(struct hnae3_handle *handle) -{ - struct hclge_vport *vport = hclge_get_vport(handle); - struct hclge_dev *hdev = vport->back; - u32 reg_val; - - if (test_and_clear_bit(HCLGE_IMP_RD_POISON, &hdev->imp_err_state)) { - dev_err(&hdev->pdev->dev, "Detected IMP RD poison!\n"); - reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG) & - ~BIT(HCLGE_VECTOR0_IMP_RD_POISON_B); - hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); - } - - if (test_and_clear_bit(HCLGE_IMP_CMDQ_ERROR, &hdev->imp_err_state)) { - dev_err(&hdev->pdev->dev, "Detected IMP CMDQ error!\n"); - reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG) & - ~BIT(HCLGE_VECTOR0_IMP_CMDQ_ERR_B); - hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); - } -} - static void hclge_reset_subtask(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); @@ -11583,7 +11592,6 @@ struct hnae3_ae_ops hclge_ops = { .mac_connect_phy = hclge_mac_connect_phy, .mac_disconnect_phy = hclge_mac_disconnect_phy, .reset_done = hclge_reset_done, - .handle_imp_error = hclge_handle_imp_error, .get_vf_config = hclge_get_vf_config, .set_vf_link_state = hclge_set_vf_link_state, .set_vf_spoofchk = hclge_set_vf_spoofchk, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index a834b5d35226..419b6c4acaf8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -1039,6 +1039,8 @@ enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev, void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time); int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc); +void hclge_report_hw_error(struct hclge_dev *hdev, + enum hnae3_hw_error_type type); void hclge_inform_vf_promisc_info(struct hclge_vport *vport); void hclge_dbg_dump_rst_info(struct hclge_dev *hdev); bool hclge_vf_vlan_need_enable(struct hclge_vport *vport);