mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
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:
parent
ef2e7a5109
commit
733eb54f62
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user