wifi: iwlwifi: mei: implement PLDR flow

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
This commit is contained in:
Avraham Stern 2022-11-02 16:59:55 +02:00 committed by Gregory Greenman
parent ef2e7a5109
commit 733eb54f62
5 changed files with 183 additions and 0 deletions

View 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__ */

View 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__ */

View 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 @@ struct iwl_mei_nvm *iwl_mei_get_nvm(void)
}
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 @@ int iwl_mei_get_ownership(void)
}
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);

View 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__ */

View 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);