Commit 47c8b154 authored by Jonathan Doron's avatar Jonathan Doron Committed by Emmanuel Grumbach

iwlwifi: mvm: set LAR MCC on D3/D0 transitions

When moving to the D3 FW give it the valid MCC from the D0 FW. When
returning from D3 to D0, query the D3 FW for the latest MCC, as
it might have changed internally. This MCC will be replayed to the D0 FW
when it boots.
Signed-off-by: default avatarJonathan Doron <jonathanx.doron@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 7f0344c2
...@@ -694,6 +694,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -694,6 +694,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (ret) if (ret)
IWL_ERR(mvm, "Failed to send quota: %d\n", ret); IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
if (iwl_mvm_is_lar_supported(mvm) && iwl_mvm_init_fw_regd(mvm))
IWL_ERR(mvm, "Failed to initialize D3 LAR information\n");
return 0; return 0;
} }
...@@ -1874,6 +1877,12 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) ...@@ -1874,6 +1877,12 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
/* query SRAM first in case we want event logging */ /* query SRAM first in case we want event logging */
iwl_mvm_read_d3_sram(mvm); iwl_mvm_read_d3_sram(mvm);
/*
* Query the current location and source from the D3 firmware so we
* can play it back when we re-intiailize the D0 firmware
*/
iwl_mvm_update_changed_regdom(mvm);
if (mvm->net_detect) { if (mvm->net_detect) {
iwl_mvm_query_netdetect_reasons(mvm, vif); iwl_mvm_query_netdetect_reasons(mvm, vif);
/* has unlocked the mutex, so skip that */ /* has unlocked the mutex, so skip that */
......
...@@ -1503,7 +1503,7 @@ struct iwl_mcc_update_cmd { ...@@ -1503,7 +1503,7 @@ struct iwl_mcc_update_cmd {
* Contains the new channel control profile map, if changed, and the new MCC * Contains the new channel control profile map, if changed, and the new MCC
* (mobile country code). * (mobile country code).
* The new MCC may be different than what was requested in MCC_UPDATE_CMD. * The new MCC may be different than what was requested in MCC_UPDATE_CMD.
* @status: 0 for success, 1 no change in channel profile, 2 invalid input. * @status: see &enum iwl_mcc_update_status
* @mcc: the new applied MCC * @mcc: the new applied MCC
* @cap: capabilities for all channels which matches the MCC * @cap: capabilities for all channels which matches the MCC
* @source_id: the MCC source, see iwl_mcc_source * @source_id: the MCC source, see iwl_mcc_source
......
...@@ -304,7 +304,8 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) ...@@ -304,7 +304,8 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
const char *alpha2, const char *alpha2,
enum iwl_mcc_source src_id) enum iwl_mcc_source src_id,
bool *changed)
{ {
struct ieee80211_regdomain *regd = NULL; struct ieee80211_regdomain *regd = NULL;
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
...@@ -322,6 +323,9 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, ...@@ -322,6 +323,9 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
goto out; goto out;
} }
if (changed)
*changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE);
regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
__le32_to_cpu(resp->n_channels), __le32_to_cpu(resp->n_channels),
resp->channels, resp->channels,
...@@ -344,12 +348,31 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, ...@@ -344,12 +348,31 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
return regd; return regd;
} }
struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm) void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm)
{
bool changed;
struct ieee80211_regdomain *regd;
if (!iwl_mvm_is_lar_supported(mvm))
return;
regd = iwl_mvm_get_current_regdomain(mvm, &changed);
if (!IS_ERR_OR_NULL(regd)) {
/* only update the regulatory core if changed */
if (changed)
regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
kfree(regd);
}
}
struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm,
bool *changed)
{ {
return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ", return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ",
iwl_mvm_is_wifi_mcc_supported(mvm) ? iwl_mvm_is_wifi_mcc_supported(mvm) ?
MCC_SOURCE_GET_CURRENT : MCC_SOURCE_GET_CURRENT :
MCC_SOURCE_OLD_FW); MCC_SOURCE_OLD_FW, changed);
} }
int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm)
...@@ -366,13 +389,13 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) ...@@ -366,13 +389,13 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm)
used_src = mvm->mcc_src; used_src = mvm->mcc_src;
if (iwl_mvm_is_wifi_mcc_supported(mvm)) { if (iwl_mvm_is_wifi_mcc_supported(mvm)) {
/* Notify the firmware we support wifi location updates */ /* Notify the firmware we support wifi location updates */
regd = iwl_mvm_get_current_regdomain(mvm); regd = iwl_mvm_get_current_regdomain(mvm, NULL);
if (!IS_ERR_OR_NULL(regd)) if (!IS_ERR_OR_NULL(regd))
kfree(regd); kfree(regd);
} }
/* Now set our last stored MCC and source */ /* Now set our last stored MCC and source */
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src); regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, NULL);
if (IS_ERR_OR_NULL(regd)) if (IS_ERR_OR_NULL(regd))
return -EIO; return -EIO;
......
...@@ -1426,9 +1426,12 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, ...@@ -1426,9 +1426,12 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
struct iwl_device_cmd *cmd); struct iwl_device_cmd *cmd);
struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
const char *alpha2, const char *alpha2,
enum iwl_mcc_source src_id); enum iwl_mcc_source src_id,
struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm); bool *changed);
struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm,
bool *changed);
int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm); int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm);
void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm);
/* smart fifo */ /* smart fifo */
int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
......
...@@ -655,7 +655,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -655,7 +655,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
IWL_DEBUG_LAR(mvm, IWL_DEBUG_LAR(mvm,
"MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n", "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n",
status, mcc, mcc >> 8, mcc & 0xff, status, mcc, mcc >> 8, mcc & 0xff,
!!(status == MCC_RESP_SAME_CHAN_PROFILE), n_channels); !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels);
resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32); resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32);
resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
...@@ -802,7 +802,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) ...@@ -802,7 +802,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
*/ */
mvm->lar_regdom_set = false; mvm->lar_regdom_set = false;
regd = iwl_mvm_get_current_regdomain(mvm); regd = iwl_mvm_get_current_regdomain(mvm, NULL);
if (IS_ERR_OR_NULL(regd)) if (IS_ERR_OR_NULL(regd))
return -EIO; return -EIO;
...@@ -810,7 +810,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) ...@@ -810,7 +810,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
!iwl_mvm_get_bios_mcc(mvm, mcc)) { !iwl_mvm_get_bios_mcc(mvm, mcc)) {
kfree(regd); kfree(regd);
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc,
MCC_SOURCE_BIOS); MCC_SOURCE_BIOS, NULL);
if (IS_ERR_OR_NULL(regd)) if (IS_ERR_OR_NULL(regd))
return -EIO; return -EIO;
} }
...@@ -843,7 +843,7 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, ...@@ -843,7 +843,7 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
IWL_DEBUG_LAR(mvm, IWL_DEBUG_LAR(mvm,
"RX: received chub update mcc cmd (mcc '%s' src %d)\n", "RX: received chub update mcc cmd (mcc '%s' src %d)\n",
mcc, src); mcc, src);
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src); regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL);
if (IS_ERR_OR_NULL(regd)) if (IS_ERR_OR_NULL(regd))
return 0; return 0;
......
...@@ -1272,6 +1272,10 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) ...@@ -1272,6 +1272,10 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
iwl_free_resp(&get_status_cmd); iwl_free_resp(&get_status_cmd);
out: out:
iwl_mvm_d0i3_enable_tx(mvm, qos_seq); iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
/* the FW might have updated the regdomain */
iwl_mvm_update_changed_regdom(mvm);
iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK); iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK);
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment