[PATCH AUTOSEL for 4.9 047/190] iwlwifi: split the handler and the wake parts of the notification infra

2018-03-07 Thread Sasha Levin
From: Emmanuel Grumbach 

[ Upstream commit 2220fb2960b72915e7fd9da640a4695dceff238c ]

The notification infrastructure (iwl_notification_wait_*
functions) allows to wait until a list of notifications
will come up from the firmware and to run a special handler
(notif_wait handler) when those are received.

The operation mode notifies the notification infrastructure
about any Rx being received by the mean of
iwl_notification_wait_notify() which will do two things:
1) call the notif_wait handler
2) wakeup the thread that was waiting for the notification

Typically, only after those two steps happened, the
operation mode will run its own handler for the notification
that was received from the firmware. This means that the
thread that was waiting for that notification can be
running before the operation mode's handler was called.

When the operation mode's handler is ASYNC, things get even
worse since the thread that was waiting for the
notification isn't even guaranteed that the ASYNC callback
was added to async_handlers_list before it starts to run.
This means that even calling
iwl_mvm_wait_for_async_handlers() can't guarantee that
absolutely everything related to that notification has run.
The following can happen:

Thread sending the commandOperation mode's Rx path
--
iwl_init_notification_wait()
iwl_mvm_send_cmd()
  iwl_mvm_rx_common()
  iwl_notification_wait_notify()
iwl_mvm_wait_for_async_handlers()
// Possibly free some data
// structure
  list_add_tail(async_handlers_list);
  schedule_work(async_handlers_wk);
  // Access the freed structure

Split the 'run notif_wait's handler' and the 'wake up the
thread' parts to fix this. This allows the operation mode
to do the following:

Thread sending the commandOperation mode's Rx path
--
iwl_init_notification_wait()
iwl_mvm_send_cmd()
  iwl_mvm_rx_common()
  iwl_notification_wait()
  // Will run the notif_wait's handler
  list_add_tail(async_handlers_list);
  schedule_work(async_handlers_wk);
  iwl_notification_notify()
iwl_mvm_wait_for_async_handlers()

This way, the waiter is guaranteed that all the handlers
have been run (if SYNC), or at least enqueued (if ASYNC)
by the time it wakes up.

Signed-off-by: Emmanuel Grumbach 
Signed-off-by: Luca Coelho 

Signed-off-by: Sasha Levin 
---
 .../net/wireless/intel/iwlwifi/iwl-notif-wait.c| 10 -
 .../net/wireless/intel/iwlwifi/iwl-notif-wait.h| 25 +-
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c 
b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c
index 88f260db3744..68412ff2112e 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c
@@ -76,8 +76,8 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data 
*notif_wait)
 }
 IWL_EXPORT_SYMBOL(iwl_notification_wait_init);
 
-void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
- struct iwl_rx_packet *pkt)
+bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait,
+  struct iwl_rx_packet *pkt)
 {
bool triggered = false;
 
@@ -118,13 +118,11 @@ void iwl_notification_wait_notify(struct 
iwl_notif_wait_data *notif_wait,
}
}
spin_unlock(_wait->notif_wait_lock);
-
}
 
-   if (triggered)
-   wake_up_all(_wait->notif_waitq);
+   return triggered;
 }
-IWL_EXPORT_SYMBOL(iwl_notification_wait_notify);
+IWL_EXPORT_SYMBOL(iwl_notification_wait);
 
 void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
 {
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h 
b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h
index 0f9995ed71cd..368884be4e7c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights 

[PATCH AUTOSEL for 4.9 047/190] iwlwifi: split the handler and the wake parts of the notification infra

2018-03-07 Thread Sasha Levin
From: Emmanuel Grumbach 

[ Upstream commit 2220fb2960b72915e7fd9da640a4695dceff238c ]

The notification infrastructure (iwl_notification_wait_*
functions) allows to wait until a list of notifications
will come up from the firmware and to run a special handler
(notif_wait handler) when those are received.

The operation mode notifies the notification infrastructure
about any Rx being received by the mean of
iwl_notification_wait_notify() which will do two things:
1) call the notif_wait handler
2) wakeup the thread that was waiting for the notification

Typically, only after those two steps happened, the
operation mode will run its own handler for the notification
that was received from the firmware. This means that the
thread that was waiting for that notification can be
running before the operation mode's handler was called.

When the operation mode's handler is ASYNC, things get even
worse since the thread that was waiting for the
notification isn't even guaranteed that the ASYNC callback
was added to async_handlers_list before it starts to run.
This means that even calling
iwl_mvm_wait_for_async_handlers() can't guarantee that
absolutely everything related to that notification has run.
The following can happen:

Thread sending the commandOperation mode's Rx path
--
iwl_init_notification_wait()
iwl_mvm_send_cmd()
  iwl_mvm_rx_common()
  iwl_notification_wait_notify()
iwl_mvm_wait_for_async_handlers()
// Possibly free some data
// structure
  list_add_tail(async_handlers_list);
  schedule_work(async_handlers_wk);
  // Access the freed structure

Split the 'run notif_wait's handler' and the 'wake up the
thread' parts to fix this. This allows the operation mode
to do the following:

Thread sending the commandOperation mode's Rx path
--
iwl_init_notification_wait()
iwl_mvm_send_cmd()
  iwl_mvm_rx_common()
  iwl_notification_wait()
  // Will run the notif_wait's handler
  list_add_tail(async_handlers_list);
  schedule_work(async_handlers_wk);
  iwl_notification_notify()
iwl_mvm_wait_for_async_handlers()

This way, the waiter is guaranteed that all the handlers
have been run (if SYNC), or at least enqueued (if ASYNC)
by the time it wakes up.

Signed-off-by: Emmanuel Grumbach 
Signed-off-by: Luca Coelho 

Signed-off-by: Sasha Levin 
---
 .../net/wireless/intel/iwlwifi/iwl-notif-wait.c| 10 -
 .../net/wireless/intel/iwlwifi/iwl-notif-wait.h| 25 +-
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c 
b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c
index 88f260db3744..68412ff2112e 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c
@@ -76,8 +76,8 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data 
*notif_wait)
 }
 IWL_EXPORT_SYMBOL(iwl_notification_wait_init);
 
-void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
- struct iwl_rx_packet *pkt)
+bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait,
+  struct iwl_rx_packet *pkt)
 {
bool triggered = false;
 
@@ -118,13 +118,11 @@ void iwl_notification_wait_notify(struct 
iwl_notif_wait_data *notif_wait,
}
}
spin_unlock(_wait->notif_wait_lock);
-
}
 
-   if (triggered)
-   wake_up_all(_wait->notif_waitq);
+   return triggered;
 }
-IWL_EXPORT_SYMBOL(iwl_notification_wait_notify);
+IWL_EXPORT_SYMBOL(iwl_notification_wait);
 
 void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
 {
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h 
b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h
index 0f9995ed71cd..368884be4e7c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and