wifi: iwlwifi: mei: re-ask for ownership after it was taken by CSME
authorAvraham Stern <avraham.stern@intel.com>
Tue, 18 Apr 2023 09:28:13 +0000 (12:28 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 20 Apr 2023 09:45:55 +0000 (11:45 +0200)
When the host disconnects from the AP CSME takes ownership right away.
Since the driver never asks for ownership again wifi is left in rfkill
until CSME releases the NIC, although in many cases the host could
re-connect shortly after the disconnection. To allow the host to
recover from occasional disconnection, re-ask for ownership to let
the host connect again.
Allow one minute before re-asking for ownership to avoid too frequent
ownership transitions.

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230418122405.a6c6ebc48f2d.I8a17003b86e71b3567521cc69864b9cbe9553ea9@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/mei/main.c

index 67dfb77..f1e0fe8 100644 (file)
@@ -31,6 +31,11 @@ MODULE_LICENSE("GPL");
 #define MEI_WLAN_UUID UUID_LE(0x13280904, 0x7792, 0x4fcb, \
                              0xa1, 0xaa, 0x5e, 0x70, 0xcb, 0xb1, 0xe8, 0x65)
 
+/* After CSME takes ownership, it won't release it for 60 seconds to avoid
+ * frequent ownership transitions.
+ */
+#define MEI_OWNERSHIP_RETAKE_TIMEOUT_MS        msecs_to_jiffies(60000)
+
 /*
  * Since iwlwifi calls iwlmei without any context, hold a pointer to the
  * mei_cl_device structure here.
@@ -156,6 +161,8 @@ struct iwl_mei_filters {
  *     accessed without the mutex.
  * @netdev_work: used to defer registering and unregistering of the netdev to
  *     avoid taking the rtnl lock in the SAP messages handlers.
+ * @ownership_dwork: used to re-ask for NIC ownership after ownership was taken
+ *     by CSME or when a previous ownership request failed.
  * @sap_seq_no: the sequence number for the SAP messages
  * @seq_no: the sequence number for the SAP messages
  * @dbgfs_dir: the debugfs dir entry
@@ -179,6 +186,7 @@ struct iwl_mei {
        bool pldr_active;
        spinlock_t data_q_lock;
        struct work_struct netdev_work;
+       struct delayed_work ownership_dwork;
 
        atomic_t sap_seq_no;
        atomic_t seq_no;
@@ -833,6 +841,8 @@ static void iwl_mei_handle_csme_taking_ownership(struct mei_cl_device *cldev,
        } else {
                iwl_mei_send_sap_msg(cldev,
                                     SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED);
+               schedule_delayed_work(&mei->ownership_dwork,
+                                     MEI_OWNERSHIP_RETAKE_TIMEOUT_MS);
        }
 }
 
@@ -1447,7 +1457,13 @@ int iwl_mei_get_ownership(void)
 
        ret = wait_event_timeout(mei->get_ownership_wq,
                                 mei->got_ownership, HZ / 2);
-       return (!ret) ? -ETIMEDOUT : 0;
+       if (!ret) {
+               schedule_delayed_work(&mei->ownership_dwork,
+                                     MEI_OWNERSHIP_RETAKE_TIMEOUT_MS);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
 out:
        mutex_unlock(&iwl_mei_mutex);
        return ret;
@@ -1738,6 +1754,8 @@ void iwl_mei_device_state(bool up)
        iwl_mei_send_sap_msg(mei->cldev,
                             SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED);
        mei->csme_taking_ownership = false;
+       schedule_delayed_work(&mei->ownership_dwork,
+                             MEI_OWNERSHIP_RETAKE_TIMEOUT_MS);
 out:
        mutex_unlock(&iwl_mei_mutex);
 }
@@ -1894,6 +1912,11 @@ static void iwl_mei_dbgfs_unregister(struct iwl_mei *mei) {}
 
 #endif /* CONFIG_DEBUG_FS */
 
+static void iwl_mei_ownership_dwork(struct work_struct *wk)
+{
+       iwl_mei_get_ownership();
+}
+
 #define ALLOC_SHARED_MEM_RETRY_MAX_NUM 3
 
 /*
@@ -1923,6 +1946,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
        init_waitqueue_head(&mei->pldr_wq);
        spin_lock_init(&mei->data_q_lock);
        INIT_WORK(&mei->netdev_work, iwl_mei_netdev_work);
+       INIT_DELAYED_WORK(&mei->ownership_dwork, iwl_mei_ownership_dwork);
 
        mei_cldev_set_drvdata(cldev, mei);
        mei->cldev = cldev;
@@ -2105,6 +2129,7 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
        cancel_work_sync(&mei->send_csa_msg_wk);
        cancel_delayed_work_sync(&mei->csa_throttle_end_wk);
        cancel_work_sync(&mei->netdev_work);
+       cancel_delayed_work_sync(&mei->ownership_dwork);
 
        /*
         * If someone waits for the ownership, let him know that we are going