net: hns3: fix VF reset fail issue
authorJijie Shao <shaojijie@huawei.com>
Fri, 10 Nov 2023 09:37:12 +0000 (17:37 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 13 Nov 2023 09:06:58 +0000 (09:06 +0000)
Currently the reset process in hns3 and firmware watchdog init process is
asynchronous. We think firmware watchdog initialization is completed
before VF clear the interrupt source. However, firmware initialization
may not complete early. So VF will receive multiple reset interrupts
and fail to reset.

So we add delay before VF interrupt source and 5 ms delay
is enough to avoid second reset interrupt.

Fixes: 427900d27d86 ("net: hns3: fix the timing issue of VF clearing interrupt sources")
Signed-off-by: Jijie Shao <shaojijie@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h

index 1c62e58ff6d8971971044c7b4d47c8b60503476c..0aa9beefd1c7ee6c53d9f2623069bae00848e77f 100644 (file)
@@ -1981,8 +1981,18 @@ static enum hclgevf_evt_cause hclgevf_check_evt_cause(struct hclgevf_dev *hdev,
        return HCLGEVF_VECTOR0_EVENT_OTHER;
 }
 
+static void hclgevf_reset_timer(struct timer_list *t)
+{
+       struct hclgevf_dev *hdev = from_timer(hdev, t, reset_timer);
+
+       hclgevf_clear_event_cause(hdev, HCLGEVF_VECTOR0_EVENT_RST);
+       hclgevf_reset_task_schedule(hdev);
+}
+
 static irqreturn_t hclgevf_misc_irq_handle(int irq, void *data)
 {
+#define HCLGEVF_RESET_DELAY    5
+
        enum hclgevf_evt_cause event_cause;
        struct hclgevf_dev *hdev = data;
        u32 clearval;
@@ -1994,7 +2004,8 @@ static irqreturn_t hclgevf_misc_irq_handle(int irq, void *data)
 
        switch (event_cause) {
        case HCLGEVF_VECTOR0_EVENT_RST:
-               hclgevf_reset_task_schedule(hdev);
+               mod_timer(&hdev->reset_timer,
+                         jiffies + msecs_to_jiffies(HCLGEVF_RESET_DELAY));
                break;
        case HCLGEVF_VECTOR0_EVENT_MBX:
                hclgevf_mbx_handler(hdev);
@@ -2937,6 +2948,7 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
                 HCLGEVF_DRIVER_NAME);
 
        hclgevf_task_schedule(hdev, round_jiffies_relative(HZ));
+       timer_setup(&hdev->reset_timer, hclgevf_reset_timer, 0);
 
        return 0;
 
index 81c16b8c8da2961c1dcc800cdf164c1dd9ae2ba1..a73f2bf3a56a6426704c64a20e74403c715ac09f 100644 (file)
@@ -219,6 +219,7 @@ struct hclgevf_dev {
        enum hnae3_reset_type reset_level;
        unsigned long reset_pending;
        enum hnae3_reset_type reset_type;
+       struct timer_list reset_timer;
 
 #define HCLGEVF_RESET_REQUESTED                0
 #define HCLGEVF_RESET_PENDING          1