Commit ad088bfa authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: fix scheduling while atomic config bug

Recent HTC/WMI changes introduced the bug. ath10k
was using _atomic iteration function with
sleepable functions.

mac80211 provides another iteration function but
it cannot be safely called in hw_config() callback
due to local->iflist_mtx being possibly acquired
already.

The patch uses internal vif list for iteration
purposes and removes/refactors no longer necessary
_iter functions.
Reported-By: default avatarKalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 0579119f
...@@ -723,35 +723,30 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ...@@ -723,35 +723,30 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
/* /*
* Review this when mac80211 gains per-interface powersave support. * Review this when mac80211 gains per-interface powersave support.
*/ */
static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
{ {
struct ath10k_generic_iter *ar_iter = data; struct ath10k *ar = arvif->ar;
struct ieee80211_conf *conf = &ar_iter->ar->hw->conf; struct ieee80211_conf *conf = &ar->hw->conf;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
enum wmi_sta_powersave_param param; enum wmi_sta_powersave_param param;
enum wmi_sta_ps_mode psmode; enum wmi_sta_ps_mode psmode;
int ret; int ret;
lockdep_assert_held(&arvif->ar->conf_mutex); lockdep_assert_held(&arvif->ar->conf_mutex);
if (vif->type != NL80211_IFTYPE_STATION) if (arvif->vif->type != NL80211_IFTYPE_STATION)
return; return 0;
if (conf->flags & IEEE80211_CONF_PS) { if (conf->flags & IEEE80211_CONF_PS) {
psmode = WMI_STA_PS_MODE_ENABLED; psmode = WMI_STA_PS_MODE_ENABLED;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME; param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
ret = ath10k_wmi_set_sta_ps_param(ar_iter->ar, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
arvif->vdev_id,
param,
conf->dynamic_ps_timeout); conf->dynamic_ps_timeout);
if (ret) { if (ret) {
ath10k_warn("Failed to set inactivity time for VDEV: %d\n", ath10k_warn("Failed to set inactivity time for VDEV: %d\n",
arvif->vdev_id); arvif->vdev_id);
return; return ret;
} }
ar_iter->ret = ret;
} else { } else {
psmode = WMI_STA_PS_MODE_DISABLED; psmode = WMI_STA_PS_MODE_DISABLED;
} }
...@@ -759,11 +754,14 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ...@@ -759,11 +754,14 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
arvif->vdev_id, psmode ? "enable" : "disable"); arvif->vdev_id, psmode ? "enable" : "disable");
ar_iter->ret = ath10k_wmi_set_psmode(ar_iter->ar, arvif->vdev_id, ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
psmode); if (ret) {
if (ar_iter->ret)
ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n", ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n",
psmode, arvif->vdev_id); psmode, arvif->vdev_id);
return ret;
}
return 0;
} }
/**********************/ /**********************/
...@@ -1959,9 +1957,10 @@ static void ath10k_stop(struct ieee80211_hw *hw) ...@@ -1959,9 +1957,10 @@ static void ath10k_stop(struct ieee80211_hw *hw)
cancel_work_sync(&ar->restart_work); cancel_work_sync(&ar->restart_work);
} }
static void ath10k_config_ps(struct ath10k *ar) static int ath10k_config_ps(struct ath10k *ar)
{ {
struct ath10k_generic_iter ar_iter; struct ath10k_vif *arvif;
int ret = 0;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
...@@ -1970,17 +1969,17 @@ static void ath10k_config_ps(struct ath10k *ar) ...@@ -1970,17 +1969,17 @@ static void ath10k_config_ps(struct ath10k *ar)
* vdevs at this point we must not iterate over this interface list. * vdevs at this point we must not iterate over this interface list.
* This setting will be updated upon add_interface(). */ * This setting will be updated upon add_interface(). */
if (ar->state == ATH10K_STATE_RESTARTED) if (ar->state == ATH10K_STATE_RESTARTED)
return; return 0;
memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
ar_iter.ar = ar;
ieee80211_iterate_active_interfaces_atomic( list_for_each_entry(arvif, &ar->arvifs, list) {
ar->hw, IEEE80211_IFACE_ITER_NORMAL, ret = ath10k_mac_vif_setup_ps(arvif);
ath10k_ps_iter, &ar_iter); if (ret) {
ath10k_warn("could not setup powersave (%d)\n", ret);
break;
}
}
if (ar_iter.ret) return ret;
ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret);
} }
static int ath10k_config(struct ieee80211_hw *hw, u32 changed) static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
...@@ -2882,86 +2881,65 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) ...@@ -2882,86 +2881,65 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)
* Both RTS and Fragmentation threshold are interface-specific * Both RTS and Fragmentation threshold are interface-specific
* in ath10k, but device-specific in mac80211. * in ath10k, but device-specific in mac80211.
*/ */
static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct ath10k_generic_iter *ar_iter = data;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
u32 rts = ar_iter->ar->hw->wiphy->rts_threshold;
lockdep_assert_held(&arvif->ar->conf_mutex); static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif;
int ret = 0;
/* During HW reconfiguration mac80211 reports all interfaces that were /* During HW reconfiguration mac80211 reports all interfaces that were
* running until reconfiguration was started. Since FW doesn't have any * running until reconfiguration was started. Since FW doesn't have any
* vdevs at this point we must not iterate over this interface list. * vdevs at this point we must not iterate over this interface list.
* This setting will be updated upon add_interface(). */ * This setting will be updated upon add_interface(). */
if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) if (ar->state == ATH10K_STATE_RESTARTED)
return; return 0;
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts_threshold %d\n",
arvif->vdev_id, rts);
ar_iter->ret = ath10k_mac_set_rts(arvif, rts);
if (ar_iter->ret)
ath10k_warn("Failed to set RTS threshold for VDEV: %d\n",
arvif->vdev_id);
}
static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
struct ath10k_generic_iter ar_iter;
struct ath10k *ar = hw->priv;
memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
ar_iter.ar = ar;
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
ieee80211_iterate_active_interfaces_atomic( list_for_each_entry(arvif, &ar->arvifs, list) {
hw, IEEE80211_IFACE_ITER_NORMAL, ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
ath10k_set_rts_iter, &ar_iter); arvif->vdev_id, value);
ret = ath10k_mac_set_rts(arvif, value);
if (ret) {
ath10k_warn("could not set rts threshold for vdev %d (%d)\n",
arvif->vdev_id, ret);
break;
}
}
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
return ar_iter.ret; return ret;
} }
static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
{ {
struct ath10k_generic_iter *ar_iter = data; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif;
u32 frag = ar_iter->ar->hw->wiphy->frag_threshold; int ret = 0;
lockdep_assert_held(&arvif->ar->conf_mutex);
/* During HW reconfiguration mac80211 reports all interfaces that were /* During HW reconfiguration mac80211 reports all interfaces that were
* running until reconfiguration was started. Since FW doesn't have any * running until reconfiguration was started. Since FW doesn't have any
* vdevs at this point we must not iterate over this interface list. * vdevs at this point we must not iterate over this interface list.
* This setting will be updated upon add_interface(). */ * This setting will be updated upon add_interface(). */
if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) if (ar->state == ATH10K_STATE_RESTARTED)
return; return 0;
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation_threshold %d\n",
arvif->vdev_id, frag);
ar_iter->ret = ath10k_mac_set_frag(arvif, frag);
if (ar_iter->ret)
ath10k_warn("Failed to set frag threshold for VDEV: %d\n",
arvif->vdev_id);
}
static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
{
struct ath10k_generic_iter ar_iter;
struct ath10k *ar = hw->priv;
memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
ar_iter.ar = ar;
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
ieee80211_iterate_active_interfaces_atomic( list_for_each_entry(arvif, &ar->arvifs, list) {
hw, IEEE80211_IFACE_ITER_NORMAL, ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
ath10k_set_frag_iter, &ar_iter); arvif->vdev_id, value);
ret = ath10k_mac_set_rts(arvif, value);
if (ret) {
ath10k_warn("could not set fragmentation threshold for vdev %d (%d)\n",
arvif->vdev_id, ret);
break;
}
}
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
return ar_iter.ret; return ret;
} }
static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
......
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