wifi: iwlwifi: mei: implement PLDR flow
authorAvraham Stern <avraham.stern@intel.com>
Wed, 2 Nov 2022 14:59:55 +0000 (16:59 +0200)
committerGregory Greenman <gregory.greenman@intel.com>
Thu, 10 Nov 2022 11:27:00 +0000 (13:27 +0200)
If the FW needs to do OTP re-read, the driver must notify CSME before
loading the FW so CSME will not try to access the NIC during the
re-read. Once the alive notification is received, CSME is notified
that NIC access is allowed again.

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.49eb8c6d455f.I7f0a5debb2d3d662a4151199bbec24613f324c13@changeid
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h
drivers/net/wireless/intel/iwlwifi/mei/main.c
drivers/net/wireless/intel/iwlwifi/mei/sap.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c

index 157d1f31c4871021def8beab5ca8263f161859f9..82cf904e0b6d956a73642c7695c0fffdc92e238a 100644 (file)
@@ -377,6 +377,7 @@ enum {
 #define PREG_PRPH_WPROT_22000          0xA04D00
 
 #define SB_MODIFY_CFG_FLAG             0xA03088
+#define SB_CFG_RESIDES_IN_OTP_MASK     0x10
 #define SB_CPU_1_STATUS                        0xA01E30
 #define SB_CPU_2_STATUS                        0xA01E34
 #define UMAG_SB_CPU_1_STATUS           0xA038C0
@@ -500,4 +501,7 @@ enum {
 
 #define REG_OTP_MINOR 0xA0333C
 
+#define WFPM_LMAC2_PD_NOTIFICATION 0xA033CC
+#define WFPM_LMAC2_PD_RE_READ BIT(31)
+
 #endif                         /* __iwl_prph_h__ */
index 2e57438a70f0f297b50428fdc5f3f5ea57851fa6..2b639eef595df96d814aa402c0a60409502a1c2a 100644 (file)
@@ -453,6 +453,21 @@ void iwl_mei_host_disassociated(void);
  */
 void iwl_mei_device_state(bool up);
 
+/**
+ * iwl_mei_pldr_req() - must be called before loading the fw
+ *
+ * Return: 0 if the PLDR flow was successful and the fw can be loaded, negative
+ *     value otherwise.
+ */
+int iwl_mei_pldr_req(void);
+
+/**
+ * iwl_mei_alive_notif() - must be called when alive notificaiton is received
+ * @success: true if received alive notification, false if waiting for the
+ *     notificaiton timed out.
+ */
+void iwl_mei_alive_notif(bool success);
+
 #else
 
 static inline bool iwl_mei_is_connected(void)
@@ -503,6 +518,12 @@ static inline void iwl_mei_host_disassociated(void)
 static inline void iwl_mei_device_state(bool up)
 {}
 
+static inline int iwl_mei_pldr_req(void)
+{ return 0; }
+
+static inline void iwl_mei_alive_notif(bool success)
+{}
+
 #endif /* CONFIG_IWLMEI */
 
 #endif /* __iwl_mei_h__ */
index c0142093c768276305ecfcb33ba12d747e5f9f01..a467da8b2aed6f5ca1dbf7c0c8a49802e602ec3a 100644 (file)
@@ -150,6 +150,8 @@ struct iwl_mei_filters {
  * @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
+ * @pldr_wq: the wait queue for PLDR flow
+ * @pldr_active: PLDR flow is in progress
  * @data_q_lock: protects the access to the data queues which are
  *     accessed without the mutex.
  * @netdev_work: used to defer registering and unregistering of the netdev to
@@ -173,6 +175,8 @@ struct iwl_mei {
        bool link_prot_state;
        bool device_down;
        struct delayed_work csa_throttle_end_wk;
+       wait_queue_head_t pldr_wq;
+       bool pldr_active;
        spinlock_t data_q_lock;
        struct work_struct netdev_work;
 
@@ -881,6 +885,15 @@ static void iwl_mei_handle_rx_host_own_req(struct mei_cl_device *cldev,
                iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false);
 }
 
+static void iwl_mei_handle_pldr_ack(struct mei_cl_device *cldev,
+                                   const struct iwl_sap_pldr_ack_data *ack)
+{
+       struct iwl_mei *mei = mei_cldev_get_drvdata(cldev);
+
+       mei->pldr_active = le32_to_cpu(ack->status) == SAP_PLDR_STATUS_SUCCESS;
+       wake_up_all(&mei->pldr_wq);
+}
+
 static void iwl_mei_handle_ping(struct mei_cl_device *cldev,
                                const struct iwl_sap_hdr *hdr)
 {
@@ -961,6 +974,8 @@ static void iwl_mei_handle_sap_msg(struct mei_cl_device *cldev,
                        iwl_mei_handle_can_release_ownership, 0);
        SAP_MSG_HANDLER(CSME_TAKING_OWNERSHIP,
                        iwl_mei_handle_csme_taking_ownership, 0);
+       SAP_MSG_HANDLER(PLDR_ACK, iwl_mei_handle_pldr_ack,
+                       sizeof(struct iwl_sap_pldr_ack_data));
        default:
        /*
         * This is not really an error, there are message that we decided
@@ -1337,6 +1352,62 @@ out:
 }
 EXPORT_SYMBOL_GPL(iwl_mei_get_nvm);
 
+#define IWL_MEI_PLDR_NUM_RETRIES       3
+
+int iwl_mei_pldr_req(void)
+{
+       struct iwl_mei *mei;
+       int ret;
+       struct iwl_sap_pldr_data msg = {
+               .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_PLDR),
+               .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)),
+       };
+       int i;
+
+       mutex_lock(&iwl_mei_mutex);
+
+       /* In case we didn't have a bind */
+       if (!iwl_mei_is_connected()) {
+               ret = 0;
+               goto out;
+       }
+
+       mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
+
+       if (!mei) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (!mei->amt_enabled) {
+               ret = 0;
+               goto out;
+       }
+
+       for (i = 0; i < IWL_MEI_PLDR_NUM_RETRIES; i++) {
+               ret = iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
+               mutex_unlock(&iwl_mei_mutex);
+               if (ret)
+                       return ret;
+
+               ret = wait_event_timeout(mei->pldr_wq, mei->pldr_active, HZ / 2);
+               if (ret)
+                       break;
+
+               /* Take the mutex for the next iteration */
+               mutex_lock(&iwl_mei_mutex);
+       }
+
+       if (ret)
+               return 0;
+
+       ret = -ETIMEDOUT;
+out:
+       mutex_unlock(&iwl_mei_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iwl_mei_pldr_req);
+
 int iwl_mei_get_ownership(void)
 {
        struct iwl_mei *mei;
@@ -1402,6 +1473,33 @@ out:
 }
 EXPORT_SYMBOL_GPL(iwl_mei_get_ownership);
 
+void iwl_mei_alive_notif(bool success)
+{
+       struct iwl_mei *mei;
+       struct iwl_sap_pldr_end_data msg = {
+               .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_PLDR_END),
+               .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)),
+               .status = success ? cpu_to_le32(SAP_PLDR_STATUS_SUCCESS) :
+                       cpu_to_le32(SAP_PLDR_STATUS_FAILURE),
+       };
+
+       mutex_lock(&iwl_mei_mutex);
+
+       if (!iwl_mei_is_connected())
+               goto out;
+
+       mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
+       if (!mei || !mei->pldr_active)
+               goto out;
+
+       mei->pldr_active = false;
+
+       iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
+out:
+       mutex_unlock(&iwl_mei_mutex);
+}
+EXPORT_SYMBOL_GPL(iwl_mei_alive_notif);
+
 void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
                             const struct iwl_mei_colloc_info *colloc_info)
 {
@@ -1841,6 +1939,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
        INIT_DELAYED_WORK(&mei->csa_throttle_end_wk,
                          iwl_mei_csa_throttle_end_wk);
        init_waitqueue_head(&mei->get_ownership_wq);
+       init_waitqueue_head(&mei->pldr_wq);
        spin_lock_init(&mei->data_q_lock);
        INIT_WORK(&mei->netdev_work, iwl_mei_netdev_work);
 
@@ -2013,6 +2112,7 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
         * the device.
         */
        wake_up_all(&mei->get_ownership_wq);
+       wake_up_all(&mei->pldr_wq);
 
        mutex_lock(&iwl_mei_mutex);
 
index ef2664589fc1efe8c6fa1cc62637aec3534ac247..6c0ad4adbf32aba79cbb4c1ae199aa2c188a40fa 100644 (file)
@@ -203,6 +203,7 @@ struct iwl_sap_me_msg_start_ok {
  * @SAP_MSG_NOTIF_NIC_OWNER: Payload is a DW. See &enum iwl_sap_nic_owner.
  * @SAP_MSG_NOTIF_CSME_CONN_STATUS: See &struct iwl_sap_notif_conn_status.
  * @SAP_MSG_NOTIF_NVM: See &struct iwl_sap_nvm.
+ * @SAP_MSG_NOTIF_PLDR_ACK: See &struct iwl_sap_pldr_ack_data.
  * @SAP_MSG_NOTIF_FROM_CSME_MAX: Not used.
  *
  * @SAP_MSG_NOTIF_FROM_HOST_MIN: Not used.
@@ -226,6 +227,8 @@ struct iwl_sap_me_msg_start_ok {
  * @SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED: No payload.
  * @SAP_MSG_NOTIF_SAR_LIMITS: See &struct iwl_sap_notif_sar_limits.
  * @SAP_MSG_NOTIF_GET_NVM: No payload. Triggers %SAP_MSG_NOTIF_NVM.
+ * @SAP_MSG_NOTIF_PLDR: See &struct iwl_sap_pldr_data.
+ * @SAP_MSG_NOTIF_PLDR_END: See &struct iwl_sap_pldr_end_data.
  * @SAP_MSG_NOTIF_FROM_HOST_MAX: Not used.
  *
  * @SAP_MSG_DATA_MIN: Not used.
@@ -258,6 +261,8 @@ enum iwl_sap_msg {
        SAP_MSG_NOTIF_NIC_OWNER                         = 511,
        SAP_MSG_NOTIF_CSME_CONN_STATUS                  = 512,
        SAP_MSG_NOTIF_NVM                               = 513,
+       /* 514 - 517 not supported */
+       SAP_MSG_NOTIF_PLDR_ACK                          = 518,
        SAP_MSG_NOTIF_FROM_CSME_MAX,
 
        SAP_MSG_NOTIF_FROM_HOST_MIN                     = 1000,
@@ -279,6 +284,9 @@ enum iwl_sap_msg {
        SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED          = 1015,
        SAP_MSG_NOTIF_SAR_LIMITS                        = 1016,
        SAP_MSG_NOTIF_GET_NVM                           = 1017,
+       /* 1018 - 1023 not supported */
+       SAP_MSG_NOTIF_PLDR                              = 1024,
+       SAP_MSG_NOTIF_PLDR_END                          = 1025,
        SAP_MSG_NOTIF_FROM_HOST_MAX,
 
        SAP_MSG_DATA_MIN                                = 2000,
@@ -732,4 +740,47 @@ struct iwl_sap_cb_data {
        u8 payload[];
 };
 
+/**
+ * struct iwl_sap_pldr_data - payload of %SAP_MSG_NOTIF_PLDR
+ * @hdr: The SAP header.
+ * @version: SAP message version
+ */
+struct iwl_sap_pldr_data {
+       struct iwl_sap_hdr hdr;
+       __le32 version;
+} __packed;
+
+/**
+ * enum iwl_sap_pldr_status -
+ * @SAP_PLDR_STATUS_SUCCESS: PLDR started/ended successfully
+ * @SAP_PLDR_STATUS_FAILURE: PLDR failed to start/end
+ */
+enum iwl_sap_pldr_status {
+       SAP_PLDR_STATUS_SUCCESS = 0,
+       SAP_PLDR_STATUS_FAILURE = 1,
+};
+
+/*
+ * struct iwl_sap_pldr_end_data - payload of %SAP_MSG_NOTIF_PLDR_END
+ * @hdr: The SAP header.
+ * @version: SAP message version
+ * @status: PLDR end status
+ */
+struct iwl_sap_pldr_end_data {
+       struct iwl_sap_hdr hdr;
+       __le32 version;
+       __le32 status;
+} __packed;
+
+/*
+ * struct iwl_sap_pldr_ack_data - payload of %SAP_MSG_NOTIF_PLDR_ACK
+ * @version: SAP message version
+ * @status: CSME accept/refuse to the PLDR request
+ */
+struct iwl_sap_pldr_ack_data {
+       struct iwl_sap_hdr hdr;
+       __le32 version;
+       __le32 status;
+} __packed;
+
 #endif /* __sap_h__ */
index 5de34edc51fe9f9e9a4b7ddcd6090ede92beb924..ef43f6971cd9e5f387b87382d78eb6420dcb1dca 100644 (file)
@@ -404,6 +404,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
                return -EIO;
        }
 
+       iwl_mei_alive_notif(!ret);
+
        ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait);
        if (ret) {
                IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");
@@ -1456,6 +1458,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        struct ieee80211_channel *chan;
        struct cfg80211_chan_def chandef;
        struct ieee80211_supported_band *sband = NULL;
+       u32 sb_cfg;
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -1463,6 +1466,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
+       sb_cfg = iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG);
+       if (!(sb_cfg & SB_CFG_RESIDES_IN_OTP_MASK) && iwl_mei_pldr_req())
+               return ret;
+
        ret = iwl_mvm_load_rt_fw(mvm);
        if (ret) {
                IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);