]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
net: hns3: add PCIe FLR support for PF
authorHuazhong Tan <tanhuazhong@huawei.com>
Fri, 9 Nov 2018 14:07:54 +0000 (22:07 +0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 10 Nov 2018 00:47:35 +0000 (16:47 -0800)
This patch implements the .reset_prepare and .reset_done
ops from pci framework to support the PF FLR.

Signed-off-by: Huazhong Tan <tanhuazhong@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_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c

index f15f5958decfc8441a1745202852a0dae738ed6b..f69d39f17bddf2f0a0c35d20a9b9e777bf7da678 100644 (file)
@@ -127,6 +127,7 @@ enum hnae3_reset_type {
        HNAE3_VF_FUNC_RESET,
        HNAE3_VF_PF_FUNC_RESET,
        HNAE3_VF_FULL_RESET,
+       HNAE3_FLR_RESET,
        HNAE3_FUNC_RESET,
        HNAE3_CORE_RESET,
        HNAE3_GLOBAL_RESET,
@@ -134,6 +135,11 @@ enum hnae3_reset_type {
        HNAE3_NONE_RESET,
 };
 
+enum hnae3_flr_state {
+       HNAE3_FLR_DOWN,
+       HNAE3_FLR_DONE,
+};
+
 struct hnae3_vector_info {
        u8 __iomem *io_addr;
        int vector;
@@ -299,7 +305,8 @@ struct hnae3_ae_dev {
 struct hnae3_ae_ops {
        int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
        void (*uninit_ae_dev)(struct hnae3_ae_dev *ae_dev);
-
+       void (*flr_prepare)(struct hnae3_ae_dev *ae_dev);
+       void (*flr_done)(struct hnae3_ae_dev *ae_dev);
        int (*init_client_instance)(struct hnae3_client *client,
                                    struct hnae3_ae_dev *ae_dev);
        void (*uninit_client_instance)(struct hnae3_client *client,
index 499032bba70584b92b147c8e00f180df7227a5c7..52ebba77f15ec7b54d912d44a9d1543d5bb082a7 100644 (file)
@@ -1851,9 +1851,29 @@ static pci_ers_result_t hns3_slot_reset(struct pci_dev *pdev)
        return PCI_ERS_RESULT_DISCONNECT;
 }
 
+static void hns3_reset_prepare(struct pci_dev *pdev)
+{
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+
+       dev_info(&pdev->dev, "hns3 flr prepare\n");
+       if (ae_dev && ae_dev->ops && ae_dev->ops->flr_prepare)
+               ae_dev->ops->flr_prepare(ae_dev);
+}
+
+static void hns3_reset_done(struct pci_dev *pdev)
+{
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+
+       dev_info(&pdev->dev, "hns3 flr done\n");
+       if (ae_dev && ae_dev->ops && ae_dev->ops->flr_done)
+               ae_dev->ops->flr_done(ae_dev);
+}
+
 static const struct pci_error_handlers hns3_err_handler = {
        .error_detected = hns3_error_detected,
        .slot_reset     = hns3_slot_reset,
+       .reset_prepare  = hns3_reset_prepare,
+       .reset_done     = hns3_reset_done,
 };
 
 static struct pci_driver hns3_driver = {
index bd6ee5c8516b0136e86379a83b4bde25804d51b0..10ff18af3cc7440cca9413db0d5e84dd053bac16 100644 (file)
@@ -594,7 +594,9 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
 static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev)
 {
        return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET ||
+                          ae_dev->reset_type == HNAE3_FLR_RESET ||
                           ae_dev->reset_type == HNAE3_VF_FUNC_RESET ||
+                          ae_dev->reset_type == HNAE3_VF_FULL_RESET ||
                           ae_dev->reset_type == HNAE3_VF_PF_FUNC_RESET));
 }
 
index 7dbab29da212203c3acfa430537682ee19c05f66..ab90108db1c93e232630336c7da2841a480a5dc2 100644 (file)
@@ -2374,6 +2374,8 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
                reg = HCLGE_FUN_RST_ING;
                reg_bit = HCLGE_FUN_RST_ING_B;
                break;
+       case HNAE3_FLR_RESET:
+               break;
        default:
                dev_err(&hdev->pdev->dev,
                        "Wait for unsupported reset type: %d\n",
@@ -2381,6 +2383,20 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
                return -EINVAL;
        }
 
+       if (hdev->reset_type == HNAE3_FLR_RESET) {
+               while (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state) &&
+                      cnt++ < HCLGE_RESET_WAIT_CNT)
+                       msleep(HCLGE_RESET_WATI_MS);
+
+               if (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state)) {
+                       dev_err(&hdev->pdev->dev,
+                               "flr wait timeout: %d\n", cnt);
+                       return -EBUSY;
+               }
+
+               return 0;
+       }
+
        val = hclge_read_dev(&hdev->hw, reg);
        while (hnae3_get_bit(val, reg_bit) && cnt < HCLGE_RESET_WAIT_CNT) {
                msleep(HCLGE_RESET_WATI_MS);
@@ -2488,6 +2504,12 @@ static void hclge_do_reset(struct hclge_dev *hdev)
                set_bit(HNAE3_FUNC_RESET, &hdev->reset_pending);
                hclge_reset_task_schedule(hdev);
                break;
+       case HNAE3_FLR_RESET:
+               dev_info(&pdev->dev, "FLR requested\n");
+               /* schedule again to check later */
+               set_bit(HNAE3_FLR_RESET, &hdev->reset_pending);
+               hclge_reset_task_schedule(hdev);
+               break;
        default:
                dev_warn(&pdev->dev,
                         "Unsupported reset type: %d\n", hdev->reset_type);
@@ -2519,6 +2541,9 @@ static enum hnae3_reset_type hclge_get_reset_level(struct hclge_dev *hdev,
        } else if (test_bit(HNAE3_FUNC_RESET, addr)) {
                rst_level = HNAE3_FUNC_RESET;
                clear_bit(HNAE3_FUNC_RESET, addr);
+       } else if (test_bit(HNAE3_FLR_RESET, addr)) {
+               rst_level = HNAE3_FLR_RESET;
+               clear_bit(HNAE3_FLR_RESET, addr);
        }
 
        return rst_level;
@@ -2555,6 +2580,8 @@ static int hclge_reset_prepare_down(struct hclge_dev *hdev)
 
        switch (hdev->reset_type) {
        case HNAE3_FUNC_RESET:
+               /* fall through */
+       case HNAE3_FLR_RESET:
                ret = hclge_set_all_vf_rst(hdev, true);
                break;
        default:
@@ -2589,6 +2616,14 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
                 */
                set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
                break;
+       case HNAE3_FLR_RESET:
+               /* There is no mechanism for PF to know if VF has stopped IO
+                * for now, just wait 100 ms for VF to stop IO
+                */
+               msleep(100);
+               set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
+               set_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
+               break;
        case HNAE3_IMP_RESET:
                reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG);
                hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG,
@@ -2647,6 +2682,8 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev)
 
        switch (hdev->reset_type) {
        case HNAE3_FUNC_RESET:
+               /* fall through */
+       case HNAE3_FLR_RESET:
                ret = hclge_set_all_vf_rst(hdev, false);
                break;
        default:
@@ -6917,6 +6954,34 @@ static void hclge_state_uninit(struct hclge_dev *hdev)
                cancel_work_sync(&hdev->mbx_service_task);
 }
 
+static void hclge_flr_prepare(struct hnae3_ae_dev *ae_dev)
+{
+#define HCLGE_FLR_WAIT_MS      100
+#define HCLGE_FLR_WAIT_CNT     50
+       struct hclge_dev *hdev = ae_dev->priv;
+       int cnt = 0;
+
+       clear_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
+       clear_bit(HNAE3_FLR_DONE, &hdev->flr_state);
+       set_bit(HNAE3_FLR_RESET, &hdev->default_reset_request);
+       hclge_reset_event(hdev->pdev, NULL);
+
+       while (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state) &&
+              cnt++ < HCLGE_FLR_WAIT_CNT)
+               msleep(HCLGE_FLR_WAIT_MS);
+
+       if (!test_bit(HNAE3_FLR_DOWN, &hdev->flr_state))
+               dev_err(&hdev->pdev->dev,
+                       "flr wait down timeout: %d\n", cnt);
+}
+
+static void hclge_flr_done(struct hnae3_ae_dev *ae_dev)
+{
+       struct hclge_dev *hdev = ae_dev->priv;
+
+       set_bit(HNAE3_FLR_DONE, &hdev->flr_state);
+}
+
 static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
 {
        struct pci_dev *pdev = ae_dev->pdev;
@@ -7575,6 +7640,8 @@ static void hclge_get_link_mode(struct hnae3_handle *handle,
 static const struct hnae3_ae_ops hclge_ops = {
        .init_ae_dev = hclge_init_ae_dev,
        .uninit_ae_dev = hclge_uninit_ae_dev,
+       .flr_prepare = hclge_flr_prepare,
+       .flr_done = hclge_flr_done,
        .init_client_instance = hclge_init_client_instance,
        .uninit_client_instance = hclge_uninit_client_instance,
        .map_ring_to_vector = hclge_map_ring_to_vector,
index b0e683e05a494882b9f469db1ab6c2eec081d6cc..ca90b662e33bebffbe6d850ddf98a35390c6ded8 100644 (file)
@@ -597,6 +597,7 @@ struct hclge_dev {
        struct hclge_misc_vector misc_vector;
        struct hclge_hw_stats hw_stats;
        unsigned long state;
+       unsigned long flr_state;
        unsigned long last_reset_time;
 
        enum hnae3_reset_type reset_type;
index f15b807b977ea647ba524872a2eddeacb9b4f91f..4c7e7bd3c84744f4329ffc784344ffad18515c19 100644 (file)
@@ -90,6 +90,8 @@ int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport)
 
        if (hdev->reset_type == HNAE3_FUNC_RESET)
                reset_type = HNAE3_VF_PF_FUNC_RESET;
+       else if (hdev->reset_type == HNAE3_FLR_RESET)
+               reset_type = HNAE3_VF_FULL_RESET;
        else
                return -EINVAL;