wifi: iwlwifi: mei: make sure ownership confirmed message is sent
authorAvraham Stern <avraham.stern@intel.com>
Sun, 30 Oct 2022 17:17:41 +0000 (19:17 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 31 Dec 2022 12:32:10 +0000 (13:32 +0100)
[ Upstream commit 5aa7ce31bd84c2f4f059200f06c537c920cbb458 ]

It is possible that CSME will try to take ownership while the driver
is stopping. In this case, if the CSME takes ownership message arrives
after the driver started unregistering, the iwl_mei_cache->ops is
already invalid, so the host will not answer with the ownership
confirmed message.
Similarly, if the take ownership message arrived after the mac was
stopped or when iwl_mvm_up() failed, setting rfkill will not trigger
sending the confirm message. As a result, CSME will not take
ownership, which will result in a disconnection.

Fix it by sending the ownership confirmed message immediately in such
cases.

Fixes: 2da4366f9e2c ("iwlwifi: mei: add the driver to allow cooperation with CSME")
Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20221030191011.b2a4c009e3e6.I7f931b7ee8b168e8ac88b11f23bff98b7ed3cb19@changeid
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
drivers/net/wireless/intel/iwlwifi/mei/main.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c

index 67122cfa22920dd3d45833da33c6742793194d3a..5409699c9a1fdfa167d866fec2c9191b257c6692 100644 (file)
@@ -446,9 +446,10 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
 void iwl_mei_host_disassociated(void);
 
 /**
- * iwl_mei_device_down() - must be called when the device is down
+ * iwl_mei_device_state() - must be called when the device changes up/down state
+ * @up: true if the device is up, false otherwise.
  */
-void iwl_mei_device_down(void);
+void iwl_mei_device_state(bool up);
 
 #else
 
@@ -497,7 +498,7 @@ static inline void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_
 static inline void iwl_mei_host_disassociated(void)
 {}
 
-static inline void iwl_mei_device_down(void)
+static inline void iwl_mei_device_state(bool up)
 {}
 
 #endif /* CONFIG_IWLMEI */
index 357f14626cf43e66b40fef20d1501f6b2a4a07f2..90646c54a3c5edfa70f18bda4290da5d599c42c2 100644 (file)
@@ -147,6 +147,8 @@ struct iwl_mei_filters {
  *     to send CSME_OWNERSHIP_CONFIRMED when the driver completes its down
  *     flow.
  * @link_prot_state: true when we are in link protection PASSIVE
+ * @device_down: true if the device is down. Used to remember to send
+ *     CSME_OWNERSHIP_CONFIRMED when the driver is already down.
  * @csa_throttle_end_wk: used when &csa_throttled is true
  * @data_q_lock: protects the access to the data queues which are
  *     accessed without the mutex.
@@ -167,6 +169,7 @@ struct iwl_mei {
        bool csa_throttled;
        bool csme_taking_ownership;
        bool link_prot_state;
+       bool device_down;
        struct delayed_work csa_throttle_end_wk;
        spinlock_t data_q_lock;
 
@@ -798,14 +801,18 @@ static void iwl_mei_handle_csme_taking_ownership(struct mei_cl_device *cldev,
 
        mei->got_ownership = false;
 
-       /*
-        * Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi driver
-        * is finished taking the device down.
-        */
-       mei->csme_taking_ownership = true;
+       if (iwl_mei_cache.ops && !mei->device_down) {
+               /*
+                * Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi
+                * driver is finished taking the device down.
+                */
+               mei->csme_taking_ownership = true;
 
-       if (iwl_mei_cache.ops)
-               iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true);
+               iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true, true);
+       } else {
+               iwl_mei_send_sap_msg(cldev,
+                                    SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED);
+       }
 }
 
 static void iwl_mei_handle_nvm(struct mei_cl_device *cldev,
@@ -1616,7 +1623,7 @@ out:
 }
 EXPORT_SYMBOL_GPL(iwl_mei_set_netdev);
 
-void iwl_mei_device_down(void)
+void iwl_mei_device_state(bool up)
 {
        struct iwl_mei *mei;
 
@@ -1630,7 +1637,9 @@ void iwl_mei_device_down(void)
        if (!mei)
                goto out;
 
-       if (!mei->csme_taking_ownership)
+       mei->device_down = !up;
+
+       if (up || !mei->csme_taking_ownership)
                goto out;
 
        iwl_mei_send_sap_msg(mei->cldev,
@@ -1639,7 +1648,7 @@ void iwl_mei_device_down(void)
 out:
        mutex_unlock(&iwl_mei_mutex);
 }
-EXPORT_SYMBOL_GPL(iwl_mei_device_down);
+EXPORT_SYMBOL_GPL(iwl_mei_device_state);
 
 int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)
 {
@@ -1821,6 +1830,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
 
        mei_cldev_set_drvdata(cldev, mei);
        mei->cldev = cldev;
+       mei->device_down = true;
 
        do {
                ret = iwl_mei_alloc_shared_mem(cldev);
index f041e77af059e6685343c64138d3ef9e30bdb476..5de34edc51fe9f9e9a4b7ddcd6090ede92beb924 100644 (file)
@@ -1665,6 +1665,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                        iwl_rfi_send_config_cmd(mvm, NULL);
        }
 
+       iwl_mvm_mei_device_state(mvm, true);
+
        IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
        return 0;
  error:
index 97cba526e4651c589b4877c406af7dfd670362e1..1ccb3cad7cdc112c18a08434543e06bcbccc7c70 100644 (file)
@@ -2201,10 +2201,10 @@ static inline void iwl_mvm_mei_host_disassociated(struct iwl_mvm *mvm)
                iwl_mei_host_disassociated();
 }
 
-static inline void iwl_mvm_mei_device_down(struct iwl_mvm *mvm)
+static inline void iwl_mvm_mei_device_state(struct iwl_mvm *mvm, bool up)
 {
        if (mvm->mei_registered)
-               iwl_mei_device_down();
+               iwl_mei_device_state(up);
 }
 
 static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)
index d2d42cd48af22eda16fc8a63641d462a63a4e5fc..5b8e9a06f6d4a9b6e3dd09406b7e634cb95f19e7 100644 (file)
@@ -1375,7 +1375,7 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm)
        iwl_trans_stop_device(mvm->trans);
        iwl_free_fw_paging(&mvm->fwrt);
        iwl_fw_dump_conf_clear(&mvm->fwrt);
-       iwl_mvm_mei_device_down(mvm);
+       iwl_mvm_mei_device_state(mvm, false);
 }
 
 static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)