net: hns3: trigger VF reset if a VF has an over_8bd_nfe_err
authorWeihang Li <liweihang@hisilicon.com>
Fri, 7 Jun 2019 02:03:07 +0000 (10:03 +0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 9 Jun 2019 20:20:59 +0000 (13:20 -0700)
We trigger PF reset when a RAS error of NIC named over_8bd_nfe_err
occurred before. But it is possible that a VF causes that error, it's
reasonable to trigger VF reset instead of PF reset in this case.
This patch add detection of vf_id if a over_8bd_nfe_err occurs, if
vf_id is 0, we trigger PF reset. Otherwise, we will trigger VF reset
on the VF with error.

Signed-off-by: Weihang Li <liweihang@hisilicon.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.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_mbx.c

index 29af1b444fa39fb73ac1e7c7d7b241dfe1f6b9f0..76d67ce8513f7fc1ecbe4e84ac8f9b53f1ea79a5 100644 (file)
@@ -180,6 +180,9 @@ enum hclge_opcode_type {
        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,
@@ -979,6 +982,20 @@ struct hclge_get_m7_bd_cmd {
        u8 rsv[20];
 };
 
+struct hclge_query_ppu_pf_other_int_dfx_cmd {
+       __le16 over_8bd_no_fe_qid;
+       __le16 over_8bd_no_fe_vf_id;
+       __le16 tso_mss_cmp_min_err_qid;
+       __le16 tso_mss_cmp_min_err_vf_id;
+       __le16 tso_mss_cmp_max_err_qid;
+       __le16 tso_mss_cmp_max_err_vf_id;
+       __le16 tx_rd_fbd_poison_qid;
+       __le16 tx_rd_fbd_poison_vf_id;
+       __le16 rx_rd_fbd_poison_qid;
+       __le16 rx_rd_fbd_poison_vf_id;
+       u8 rsv[4];
+};
+
 int hclge_cmd_init(struct hclge_dev *hdev);
 static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
 {
index 4f2af3d5279363ed5af8598cda4207ffddec6c9c..cb6ed8c7a9728df37eb4fe867a94234dd29146c5 100644 (file)
@@ -1687,6 +1687,81 @@ pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev)
        return PCI_ERS_RESULT_RECOVERED;
 }
 
+/* hclge_query_8bd_info: query information about over_8bd_nfe_err
+ * @hdev: pointer to struct hclge_dev
+ * @vf_id: Index of the virtual function with error
+ * @q_id: Physical index of the queue with error
+ *
+ * This function get specific index of queue and function which causes
+ * over_8bd_nfe_err by using command. If vf_id is 0, it means error is
+ * caused by PF instead of VF.
+ */
+static int hclge_query_over_8bd_err_info(struct hclge_dev *hdev, u16 *vf_id,
+                                        u16 *q_id)
+{
+       struct hclge_query_ppu_pf_other_int_dfx_cmd *req;
+       struct hclge_desc desc;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PPU_PF_OTHER_INT_DFX, true);
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret)
+               return ret;
+
+       req = (struct hclge_query_ppu_pf_other_int_dfx_cmd *)desc.data;
+       *vf_id = le16_to_cpu(req->over_8bd_no_fe_vf_id);
+       *q_id = le16_to_cpu(req->over_8bd_no_fe_qid);
+
+       return 0;
+}
+
+/* hclge_handle_over_8bd_err: handle MSI-X error named over_8bd_nfe_err
+ * @hdev: pointer to struct hclge_dev
+ * @reset_requests: reset level that we need to trigger later
+ *
+ * over_8bd_nfe_err is a special MSI-X because it may caused by a VF, in
+ * that case, we need to trigger VF reset. Otherwise, a PF reset is needed.
+ */
+static void hclge_handle_over_8bd_err(struct hclge_dev *hdev,
+                                     unsigned long *reset_requests)
+{
+       struct device *dev = &hdev->pdev->dev;
+       u16 vf_id;
+       u16 q_id;
+       int ret;
+
+       ret = hclge_query_over_8bd_err_info(hdev, &vf_id, &q_id);
+       if (ret) {
+               dev_err(dev, "fail(%d) to query over_8bd_no_fe info\n",
+                       ret);
+               return;
+       }
+
+       dev_warn(dev, "PPU_PF_ABNORMAL_INT_ST over_8bd_no_fe found, vf_id(%d), queue_id(%d)\n",
+                vf_id, q_id);
+
+       if (vf_id) {
+               if (vf_id >= hdev->num_alloc_vport) {
+                       dev_err(dev, "invalid vf id(%d)\n", vf_id);
+                       return;
+               }
+
+               /* If we need to trigger other reset whose level is higher
+                * than HNAE3_VF_FUNC_RESET, no need to trigger a VF reset
+                * here.
+                */
+               if (*reset_requests != 0)
+                       return;
+
+               ret = hclge_inform_reset_assert_to_vf(&hdev->vport[vf_id]);
+               if (ret)
+                       dev_warn(dev, "inform reset to vf(%d) failed %d!\n",
+                                hdev->vport->vport_id, ret);
+       } else {
+               set_bit(HNAE3_FUNC_RESET, reset_requests);
+       }
+}
+
 int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
                               unsigned long *reset_requests)
 {
@@ -1799,6 +1874,10 @@ int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
                set_bit(reset_level, reset_requests);
        }
 
+       status = le32_to_cpu(*desc_data) & HCLGE_PPU_PF_OVER_8BD_ERR_MASK;
+       if (status)
+               hclge_handle_over_8bd_err(hdev, reset_requests);
+
        /* clear all PF MSIx errors */
        hclge_cmd_reuse_desc(&desc[0], false);
        ret = hclge_cmd_send(&hdev->hw, &desc[0], pf_bd_num);
index 668473306cb34d4fe1d4d5a82dbad57e51b9fd40..be1186a3c345e4f9192dd4ba2a8e72d730d9eb24 100644 (file)
@@ -83,7 +83,8 @@
 #define HCLGE_PPU_MPF_INT_ST3_MASK     GENMASK(7, 0)
 #define HCLGE_PPU_MPF_INT_ST2_MSIX_MASK        GENMASK(29, 28)
 #define HCLGE_PPU_PF_INT_RAS_MASK      0x18
-#define HCLGE_PPU_PF_INT_MSIX_MASK     0x27
+#define HCLGE_PPU_PF_INT_MSIX_MASK     0x26
+#define HCLGE_PPU_PF_OVER_8BD_ERR_MASK 0x01
 #define HCLGE_QCN_FIFO_INT_MASK                GENMASK(17, 0)
 #define HCLGE_QCN_ECC_INT_MASK         GENMASK(21, 0)
 #define HCLGE_NCSI_ECC_INT_MASK                GENMASK(1, 0)
index d20f01720719496ed8196d5f747aafa462132c95..2003817cde36f752a0dd57cd0e111ccf7d1c2179 100644 (file)
@@ -93,7 +93,7 @@ int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport)
        else if (hdev->reset_type == HNAE3_FLR_RESET)
                reset_type = HNAE3_VF_FULL_RESET;
        else
-               return -EINVAL;
+               reset_type = HNAE3_VF_FUNC_RESET;
 
        memcpy(&msg_data[0], &reset_type, sizeof(u16));