wlcore/wl18xx: handle rc updates in a separate work

sta_rc_update runs in atomic context. thus, a new work
should be scheduled in order to configure the fw
with the required configuration.

Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Eliad Peller 2014-12-29 08:24:03 +02:00 committed by Kalle Valo
parent 16129d1d59
commit 7d3b29e5c8
5 changed files with 44 additions and 21 deletions

View File

@ -1559,26 +1559,19 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
}
static void wl18xx_sta_rc_update(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta,
u32 changed)
struct wl12xx_vif *wlvif)
{
bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40;
wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
if (!(changed & IEEE80211_RC_BW_CHANGED))
return;
mutex_lock(&wl->mutex);
/* sanity */
if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
goto out;
return;
/* ignore the change before association */
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
goto out;
return;
/*
* If we started out as wide, we can change the operation mode. If we
@ -1589,9 +1582,6 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl,
wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
else
ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
out:
mutex_unlock(&wl->mutex);
}
static int wl18xx_set_peer_cap(struct wl1271 *wl,

View File

@ -211,11 +211,10 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
}
static inline void
wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta, u32 changed)
wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
if (wl->ops->sta_rc_update)
wl->ops->sta_rc_update(wl, wlvif, sta, changed);
wl->ops->sta_rc_update(wl, wlvif);
}
static inline int

View File

@ -226,6 +226,29 @@ void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl)
msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout));
}
static void wlcore_rc_update_work(struct work_struct *work)
{
int ret;
struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
rc_update_work);
struct wl1271 *wl = wlvif->wl;
mutex_lock(&wl->mutex);
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
wlcore_hw_sta_rc_update(wl, wlvif);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
static void wl12xx_tx_watchdog_work(struct work_struct *work)
{
struct delayed_work *dwork;
@ -2279,6 +2302,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_rx_streaming_enable_work);
INIT_WORK(&wlvif->rx_streaming_disable_work,
wl1271_rx_streaming_disable_work);
INIT_WORK(&wlvif->rc_update_work, wlcore_rc_update_work);
INIT_DELAYED_WORK(&wlvif->channel_switch_work,
wlcore_channel_switch_work);
INIT_DELAYED_WORK(&wlvif->connection_loss_work,
@ -2723,6 +2747,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
del_timer_sync(&wlvif->rx_streaming_timer);
cancel_work_sync(&wlvif->rx_streaming_enable_work);
cancel_work_sync(&wlvif->rx_streaming_disable_work);
cancel_work_sync(&wlvif->rc_update_work);
cancel_delayed_work_sync(&wlvif->connection_loss_work);
cancel_delayed_work_sync(&wlvif->channel_switch_work);
cancel_delayed_work_sync(&wlvif->pending_auth_complete_work);
@ -5370,9 +5395,15 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
u32 changed)
{
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct wl1271 *wl = hw->priv;
wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update");
if (!(changed & IEEE80211_RC_BW_CHANGED))
return;
/* this callback is atomic, so schedule a new work */
wlvif->rc_update_bw = sta->bandwidth;
ieee80211_queue_work(hw, &wlvif->rc_update_work);
}
static int wlcore_op_get_rssi(struct ieee80211_hw *hw,

View File

@ -106,8 +106,7 @@ struct wlcore_ops {
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta, u32 changed);
void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int (*set_peer_cap)(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,

View File

@ -463,6 +463,10 @@ struct wl12xx_vif {
/* work for canceling ROC after pending auth reply */
struct delayed_work pending_auth_complete_work;
/* update rate conrol */
enum ieee80211_sta_rx_bandwidth rc_update_bw;
struct work_struct rc_update_work;
/*
* total freed FW packets on the link.
* For STA this holds the PN of the link to the AP.