diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-11-13 11:56:37 -0800 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-11-18 17:09:08 -0500 |
commit | 6ab10ff8738dfb098fd32132b7ebcf5cdb43ebde (patch) | |
tree | 7bb2cf0ce4d1b286aa14f4e0ae9d24dfee8b75c2 /drivers/net/wireless/iwlwifi/iwl-sta.c | |
parent | 9bb487b406692e172b15eba58de7d69358ac2005 (diff) | |
download | kernel_samsung_smdk4412-6ab10ff8738dfb098fd32132b7ebcf5cdb43ebde.zip kernel_samsung_smdk4412-6ab10ff8738dfb098fd32132b7ebcf5cdb43ebde.tar.gz kernel_samsung_smdk4412-6ab10ff8738dfb098fd32132b7ebcf5cdb43ebde.tar.bz2 |
iwlwifi: handle unicast PS buffering
Using the new mac80211 functionality, this makes
iwlwifi handle unicast PS buffering correctly.
The device works like this:
* when a station goes to sleep, the microcode notices
this and marks the station as asleep
* when the station is marked asleep, the microcode
refuses to transmit to the station and rejects all
frames queued to it with the failure status code
TX_STATUS_FAIL_DEST_PS (a previous patch handled
this correctly)
* when we need to send frames to the station _although_
it is asleep, we need to tell the ucode how many,
and this is asynchronous with sending so we cannot
just send the frames, we need to wait for all other
frames to be flushed, and then update the counter
before sending out the poll response frames. This
is handled partially in the driver and partially in
mac80211.
In order to do all this correctly, we need to
* keep track of how many frames are pending for each
associated client station (avoid doing it for other
stations to avoid the atomic ops)
* tell mac80211 that we driver-block the PS status
while there are still frames pending on the queues,
and once they are all rejected (due to the dest sta
being in PS) unblock mac80211
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index eba36f7..cd6a690 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1216,7 +1216,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) } EXPORT_SYMBOL(iwl_sta_rx_agg_stop); -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; @@ -1224,27 +1224,26 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.sleep_tx_count = 0; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } +EXPORT_SYMBOL(iwl_sta_modify_ps_wake); -void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) { - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); + unsigned long flags; - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = + STA_MODIFY_SLEEP_TX_COUNT_MSK; + priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } - |