wifi: iwlwifi: mei: wait for the mac to stop on suspend
authorAvraham Stern <avraham.stern@intel.com>
Wed, 2 Nov 2022 14:59:58 +0000 (16:59 +0200)
committerGregory Greenman <gregory.greenman@intel.com>
Thu, 10 Nov 2022 11:27:11 +0000 (13:27 +0200)
When iwlmei driver is removed, it removes all the interfaces
since CSME will take over the NIC while there is no SAP connection.
When the iwlmei driver is removed due to the host being suspended,
this results in the interface being down after resume since the
interface was removed on suspend so mac80211 will not try to bring it
up on resume.
Since on suspend the mac is stopped anyway by mac80211, there is
no need to remove the interface in this case. Wait for the mac
to stop instead. Once the mac is stopped, the driver will not
access the NIC anymore so it is safe for CSME to take over.

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20221102165239.371102f04586.I813a964607b3e92ea275a0cf56df57227c11ae88@changeid
drivers/net/wireless/intel/iwlwifi/mei/main.c

index 9a49361cd059af122ac777b037fe9e8da9e92053..b89989b6399a82899d63aca8cb71c087840bd270 100644 (file)
@@ -1990,6 +1990,7 @@ free:
 }
 
 #define SEND_SAP_MAX_WAIT_ITERATION 10
+#define IWLMEI_DEVICE_DOWN_WAIT_ITERATION 50
 
 static void iwl_mei_remove(struct mei_cl_device *cldev)
 {
@@ -2000,8 +2001,26 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
         * We are being removed while the bus is active, it means we are
         * going to suspend/ shutdown, so the NIC will disappear.
         */
-       if (mei_cldev_enabled(cldev) && iwl_mei_cache.ops)
-               iwl_mei_cache.ops->nic_stolen(iwl_mei_cache.priv);
+       if (mei_cldev_enabled(cldev) && iwl_mei_cache.ops) {
+               unsigned int iter = IWLMEI_DEVICE_DOWN_WAIT_ITERATION;
+               bool down = false;
+
+               /*
+                * In case of suspend, wait for the mac to stop and don't remove
+                * the interface. This will allow the interface to come back
+                * on resume.
+                */
+               while (!down && iter--) {
+                       mdelay(1);
+
+                       mutex_lock(&iwl_mei_mutex);
+                       down = mei->device_down;
+                       mutex_unlock(&iwl_mei_mutex);
+               }
+
+               if (!down)
+                       iwl_mei_cache.ops->nic_stolen(iwl_mei_cache.priv);
+       }
 
        if (rcu_access_pointer(iwl_mei_cache.netdev)) {
                struct net_device *dev;