| From 2fa4cb905605c863bf570027233af7afd8149ae4 Mon Sep 17 00:00:00 2001 |
| From: Stanislaw Gruszka <sgruszka@redhat.com> |
| Date: Tue, 28 Jan 2014 09:14:48 +0100 |
| Subject: ath9k_htc: make ->sta_rc_update atomic for most calls |
| |
| From: Stanislaw Gruszka <sgruszka@redhat.com> |
| |
| commit 2fa4cb905605c863bf570027233af7afd8149ae4 upstream. |
| |
| sta_rc_update() callback must be atomic, hence we can not take mutexes |
| or do other operations, which can sleep in ath9k_htc_sta_rc_update(). |
| |
| I think we can just return from ath9k_htc_sta_rc_update(), if it is |
| called without IEEE80211_RC_SUPP_RATES_CHANGED bit. That will help |
| with scheduling while atomic bug for most cases (except mesh and IBSS |
| modes). |
| |
| For mesh and IBSS I do not see other solution like creating additional |
| workqueue, because sending firmware command require us to sleep, but |
| this can be done in additional patch. |
| |
| Patch partially fixes bug: |
| https://bugzilla.redhat.com/show_bug.cgi?id=990955 |
| |
| Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> |
| Signed-off-by: John W. Linville <linville@tuxdriver.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/net/wireless/ath/ath9k/htc_drv_main.c | 25 +++++++++++++------------ |
| 1 file changed, 13 insertions(+), 12 deletions(-) |
| |
| --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c |
| +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c |
| @@ -1331,21 +1331,22 @@ static void ath9k_htc_sta_rc_update(stru |
| struct ath_common *common = ath9k_hw_common(priv->ah); |
| struct ath9k_htc_target_rate trate; |
| |
| + if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED)) |
| + return; |
| + |
| mutex_lock(&priv->mutex); |
| ath9k_htc_ps_wakeup(priv); |
| |
| - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { |
| - memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); |
| - ath9k_htc_setup_rate(priv, sta, &trate); |
| - if (!ath9k_htc_send_rate_cmd(priv, &trate)) |
| - ath_dbg(common, CONFIG, |
| - "Supported rates for sta: %pM updated, rate caps: 0x%X\n", |
| - sta->addr, be32_to_cpu(trate.capflags)); |
| - else |
| - ath_dbg(common, CONFIG, |
| - "Unable to update supported rates for sta: %pM\n", |
| - sta->addr); |
| - } |
| + memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); |
| + ath9k_htc_setup_rate(priv, sta, &trate); |
| + if (!ath9k_htc_send_rate_cmd(priv, &trate)) |
| + ath_dbg(common, CONFIG, |
| + "Supported rates for sta: %pM updated, rate caps: 0x%X\n", |
| + sta->addr, be32_to_cpu(trate.capflags)); |
| + else |
| + ath_dbg(common, CONFIG, |
| + "Unable to update supported rates for sta: %pM\n", |
| + sta->addr); |
| |
| ath9k_htc_ps_restore(priv); |
| mutex_unlock(&priv->mutex); |