]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
i40e: lock service task correctly
authorMitch Williams <mitch.a.williams@intel.com>
Mon, 21 Nov 2016 21:03:51 +0000 (13:03 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 7 Dec 2016 05:10:53 +0000 (21:10 -0800)
The service task lock was being set in the scheduling function, not the
actual service task. This would potentially leave the bit set for a long
time before the task actually ran. Furthermore, if the service task
takes too long, it calls the schedule function to reschedule itself -
which would fail to take the lock and do nothing.

Instead, set and clear the lock bit in the service task itself. In the
process, get rid of the i40e_service_event_complete() function, which is
really just two lines of code that can be put right in the service task
itself.

Change-ID: I83155e682b686121e2897f4429eb7d3f7c669168
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e_main.c

index b0486c9cf6bb9aa6b2011c2216ee9f08283d1048..c47e9c59e8dddbf8ff6db7d735c3eadb57aee627 100644 (file)
@@ -288,8 +288,7 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id)
 void i40e_service_event_schedule(struct i40e_pf *pf)
 {
        if (!test_bit(__I40E_DOWN, &pf->state) &&
-           !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) &&
-           !test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state))
+           !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
                queue_work(i40e_wq, &pf->service_task);
 }
 
@@ -5954,19 +5953,6 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
        }
 }
 
-/**
- * i40e_service_event_complete - Finish up the service event
- * @pf: board private structure
- **/
-static void i40e_service_event_complete(struct i40e_pf *pf)
-{
-       WARN_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state));
-
-       /* flush memory to make sure state is correct before next watchog */
-       smp_mb__before_atomic();
-       clear_bit(__I40E_SERVICE_SCHED, &pf->state);
-}
-
 /**
  * i40e_get_cur_guaranteed_fd_count - Get the consumed guaranteed FD filters
  * @pf: board private structure
@@ -7276,10 +7262,12 @@ static void i40e_service_task(struct work_struct *work)
 
        /* don't bother with service tasks if a reset is in progress */
        if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) {
-               i40e_service_event_complete(pf);
                return;
        }
 
+       if (test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state))
+               return;
+
        i40e_detect_recover_hung(pf);
        i40e_sync_filters_subtask(pf);
        i40e_reset_subtask(pf);
@@ -7292,7 +7280,9 @@ static void i40e_service_task(struct work_struct *work)
        i40e_sync_udp_filters_subtask(pf);
        i40e_clean_adminq_subtask(pf);
 
-       i40e_service_event_complete(pf);
+       /* flush memory to make sure state is correct before next watchdog */
+       smp_mb__before_atomic();
+       clear_bit(__I40E_SERVICE_SCHED, &pf->state);
 
        /* If the tasks have taken longer than one timer cycle or there
         * is more work to be done, reschedule the service task now