net: hns3: implement .process_hw_error for hns3 client
authorWeihang Li <liweihang@hisilicon.com>
Wed, 28 Aug 2019 14:23:13 +0000 (22:23 +0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 29 Aug 2019 23:57:43 +0000 (16:57 -0700)
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>
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h

index 3e21533..c4b7bf8 100644 (file)
@@ -146,6 +146,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,
@@ -210,7 +216,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);
-       enum hnae3_reset_type (*process_hw_error)(struct hnae3_handle *handle);
+       void (*process_hw_error)(struct hnae3_handle *handle,
+                                enum hnae3_hw_error_type);
 };
 
 #define HNAE3_CLIENT_NAME_LENGTH 16
index a11d514..9f3f8e3 100644 (file)
@@ -4470,12 +4470,36 @@ int hns3_set_channels(struct net_device *netdev,
        return hns3_reset_notify(h, HNAE3_UP_CLIENT);
 }
 
+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)
+{
+       int 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;
+               }
+       }
+}
+
 static 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,
 };
 
 /* hns3_init_module - Driver registration routine
index e37e64e..2110fa3 100644 (file)
@@ -552,6 +552,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
index d986c36..58c6231 100644 (file)
@@ -1325,10 +1325,12 @@ static int hclge_handle_pf_ras_error(struct hclge_dev *hdev,
        /* log PPU(RCB) errors */
        desc_data = (__le32 *)&desc[3];
        status = le32_to_cpu(*desc_data) & HCLGE_PPU_PF_INT_RAS_MASK;
-       if (status)
+       if (status) {
                hclge_log_error(dev, "PPU_PF_ABNORMAL_INT_ST0",
                                &hclge_ppu_pf_abnormal_int[0], status,
                                &ae_dev->hw_err_reset_req);
+               hclge_report_hw_error(hdev, HNAE3_PPU_POISON_ERROR);
+       }
 
        /* clear all PF RAS errors */
        hclge_cmd_reuse_desc(&desc[0], false);
index 7ea8bb2..876fd81 100644 (file)
@@ -5,6 +5,7 @@
 #define __HCLGE_ERR_H
 
 #include "hclge_main.h"
+#include "hnae3.h"
 
 #define HCLGE_MPF_RAS_INT_MIN_BD_NUM   10
 #define HCLGE_PF_RAS_INT_MIN_BD_NUM    4
index f43c298..9ef1f46 100644 (file)
@@ -3265,6 +3265,38 @@ static int hclge_func_reset_sync_vf(struct hclge_dev *hdev)
        return -ETIME;
 }
 
+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;
@@ -3471,6 +3503,7 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
                hdev->rst_stats.flr_rst_cnt++;
                break;
        case HNAE3_IMP_RESET:
+               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);
index 00c07f8..a3bc382 100644 (file)
@@ -178,6 +178,8 @@ enum HLCGE_PORT_TYPE {
 #define HCLGE_VECTOR0_RX_CMDQ_INT_B    1
 
 #define HCLGE_VECTOR0_IMP_RESET_INT_B  1
+#define HCLGE_VECTOR0_IMP_CMDQ_ERR_B   4U
+#define HCLGE_VECTOR0_IMP_RD_POISON_B  5U
 
 #define HCLGE_MAC_DEFAULT_FRAME \
        (ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN + ETH_DATA_LEN)
@@ -986,4 +988,6 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
 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);
 #endif