aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-13 14:56:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-18 17:09:08 -0500
commit6ab10ff8738dfb098fd32132b7ebcf5cdb43ebde (patch)
tree7bb2cf0ce4d1b286aa14f4e0ae9d24dfee8b75c2 /drivers/net/wireless/iwlwifi/iwl-agn.c
parent9bb487b406692e172b15eba58de7d69358ac2005 (diff)
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-agn.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 1c6506529b6e..6385cdf24d13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2744,6 +2744,45 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
2744 return 0; 2744 return 0;
2745} 2745}
2746 2746
2747static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
2748 struct ieee80211_vif *vif,
2749 enum sta_notify_cmd cmd,
2750 struct ieee80211_sta *sta)
2751{
2752 struct iwl_priv *priv = hw->priv;
2753 struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
2754 int sta_id;
2755
2756 /*
2757 * TODO: We really should use this callback to
2758 * actually maintain the station table in
2759 * the device.
2760 */
2761
2762 switch (cmd) {
2763 case STA_NOTIFY_ADD:
2764 atomic_set(&sta_priv->pending_frames, 0);
2765 if (vif->type == NL80211_IFTYPE_AP)
2766 sta_priv->client = true;
2767 break;
2768 case STA_NOTIFY_SLEEP:
2769 WARN_ON(!sta_priv->client);
2770 sta_priv->asleep = true;
2771 if (atomic_read(&sta_priv->pending_frames) > 0)
2772 ieee80211_sta_block_awake(hw, sta, true);
2773 break;
2774 case STA_NOTIFY_AWAKE:
2775 WARN_ON(!sta_priv->client);
2776 sta_priv->asleep = false;
2777 sta_id = iwl_find_station(priv, sta->addr);
2778 if (sta_id != IWL_INVALID_STATION)
2779 iwl_sta_modify_ps_wake(priv, sta_id);
2780 break;
2781 default:
2782 break;
2783 }
2784}
2785
2747/***************************************************************************** 2786/*****************************************************************************
2748 * 2787 *
2749 * sysfs attributes 2788 * sysfs attributes
@@ -3175,7 +3214,8 @@ static struct ieee80211_ops iwl_hw_ops = {
3175 .reset_tsf = iwl_mac_reset_tsf, 3214 .reset_tsf = iwl_mac_reset_tsf,
3176 .bss_info_changed = iwl_bss_info_changed, 3215 .bss_info_changed = iwl_bss_info_changed,
3177 .ampdu_action = iwl_mac_ampdu_action, 3216 .ampdu_action = iwl_mac_ampdu_action,
3178 .hw_scan = iwl_mac_hw_scan 3217 .hw_scan = iwl_mac_hw_scan,
3218 .sta_notify = iwl_mac_sta_notify,
3179}; 3219};
3180 3220
3181static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 3221static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)