net: hns3: stop schedule reset service while unloading driver
authorHuazhong Tan <tanhuazhong@huawei.com>
Tue, 28 May 2019 09:03:00 +0000 (17:03 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 29 May 2019 00:39:01 +0000 (17:39 -0700)
When unloading driver, the reset task should not be scheduled
anymore. If disable IRQ before cancel ongoing reset task,
the IRQ may be re-enabled by the reset task.

This patch uses HCLGE_STATE_REMOVING/HCLGEVF_STATE_REMOVING
flag to indicate that the driver is unloading, and we should
stop new coming reset service to be scheduled, otherwise,
reset service will access some resource which has been freed
by unloading.

Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h

index a563815e5ed17318957433b8e06993e479c97652..0545f3890d1ca592e5d079b76ee5c79aca4f22df 100644 (file)
@@ -2427,7 +2427,8 @@ static void hclge_mbx_task_schedule(struct hclge_dev *hdev)
 
 static void hclge_reset_task_schedule(struct hclge_dev *hdev)
 {
-       if (!test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
+       if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
+           !test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
                schedule_work(&hdev->rst_service_task);
 }
 
@@ -8385,6 +8386,7 @@ static void hclge_state_init(struct hclge_dev *hdev)
 static void hclge_state_uninit(struct hclge_dev *hdev)
 {
        set_bit(HCLGE_STATE_DOWN, &hdev->state);
+       set_bit(HCLGE_STATE_REMOVING, &hdev->state);
 
        if (hdev->service_timer.function)
                del_timer_sync(&hdev->service_timer);
index ee1eecad3b8d7b8aa7b70df653a6420697848048..87a619db2780c25df7ae2d4457dbcd5b856d08c7 100644 (file)
@@ -1621,7 +1621,8 @@ static void hclgevf_get_misc_vector(struct hclgevf_dev *hdev)
 
 void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev)
 {
-       if (!test_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state)) {
+       if (!test_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state) &&
+           !test_bit(HCLGEVF_STATE_REMOVING, &hdev->state)) {
                set_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state);
                schedule_work(&hdev->rst_service_task);
        }
@@ -2132,6 +2133,7 @@ static void hclgevf_state_init(struct hclgevf_dev *hdev)
 static void hclgevf_state_uninit(struct hclgevf_dev *hdev)
 {
        set_bit(HCLGEVF_STATE_DOWN, &hdev->state);
+       set_bit(HCLGEVF_STATE_REMOVING, &hdev->state);
 
        if (hdev->keep_alive_timer.function)
                del_timer_sync(&hdev->keep_alive_timer);
index eab1095bf2217caa2589ca4d375979a4c0b96bbb..a7fbd38c14921df38ed44fbc0c0ee997d94993ff 100644 (file)
@@ -130,6 +130,7 @@ enum hclgevf_states {
        HCLGEVF_STATE_DOWN,
        HCLGEVF_STATE_DISABLED,
        HCLGEVF_STATE_IRQ_INITED,
+       HCLGEVF_STATE_REMOVING,
        HCLGEVF_STATE_NIC_REGISTERED,
        /* task states */
        HCLGEVF_STATE_SERVICE_SCHED,