diff options
author | Kalle Valo <kalle.valo@nokia.com> | 2010-01-12 03:42:31 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-01-12 14:20:58 -0500 |
commit | ab13315af97919fae0e014748105fdc2e30afb2d (patch) | |
tree | befa549272ecff20b2839bd6671e4cccbce448f9 /net/mac80211/mlme.c | |
parent | 2d46d7c121436f1dafe91b0a8d9b99e534cfa5f8 (diff) |
mac80211: add U-APSD client support
Add Unscheduled Automatic Power-Save Delivery (U-APSD) client support. The
idea is that the data frames from the client trigger AP to send the buffered
frames with ACs which have U-APSD enabled. This decreases latency and makes it
possible to save even more power.
Driver needs to use IEEE80211_HW_UAPSD to enable the feature. The current
implementation assumes that firmware takes care of the wakeup and
hardware needing IEEE80211_HW_PS_NULLFUNC_STACK is not yet supported.
Tested with wl1251 on a Nokia N900 and Cisco Aironet 1231G AP and running
various test traffic with ping.
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86f025bc9456..39c27d83a4f2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -569,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
569 | struct ieee80211_tx_queue_params params; | 569 | struct ieee80211_tx_queue_params params; |
570 | size_t left; | 570 | size_t left; |
571 | int count; | 571 | int count; |
572 | u8 *pos; | 572 | u8 *pos, uapsd_queues = 0; |
573 | 573 | ||
574 | if (local->hw.queues < 4) | 574 | if (local->hw.queues < 4) |
575 | return; | 575 | return; |
@@ -579,6 +579,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
579 | 579 | ||
580 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 580 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
581 | return; | 581 | return; |
582 | |||
583 | if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | ||
584 | uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | ||
585 | |||
582 | count = wmm_param[6] & 0x0f; | 586 | count = wmm_param[6] & 0x0f; |
583 | if (count == ifmgd->wmm_last_param_set) | 587 | if (count == ifmgd->wmm_last_param_set) |
584 | return; | 588 | return; |
@@ -593,6 +597,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
593 | for (; left >= 4; left -= 4, pos += 4) { | 597 | for (; left >= 4; left -= 4, pos += 4) { |
594 | int aci = (pos[0] >> 5) & 0x03; | 598 | int aci = (pos[0] >> 5) & 0x03; |
595 | int acm = (pos[0] >> 4) & 0x01; | 599 | int acm = (pos[0] >> 4) & 0x01; |
600 | bool uapsd = false; | ||
596 | int queue; | 601 | int queue; |
597 | 602 | ||
598 | switch (aci) { | 603 | switch (aci) { |
@@ -600,22 +605,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
600 | queue = 3; | 605 | queue = 3; |
601 | if (acm) | 606 | if (acm) |
602 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ | 607 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ |
608 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) | ||
609 | uapsd = true; | ||
603 | break; | 610 | break; |
604 | case 2: /* AC_VI */ | 611 | case 2: /* AC_VI */ |
605 | queue = 1; | 612 | queue = 1; |
606 | if (acm) | 613 | if (acm) |
607 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ | 614 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ |
615 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) | ||
616 | uapsd = true; | ||
608 | break; | 617 | break; |
609 | case 3: /* AC_VO */ | 618 | case 3: /* AC_VO */ |
610 | queue = 0; | 619 | queue = 0; |
611 | if (acm) | 620 | if (acm) |
612 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ | 621 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ |
622 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
623 | uapsd = true; | ||
613 | break; | 624 | break; |
614 | case 0: /* AC_BE */ | 625 | case 0: /* AC_BE */ |
615 | default: | 626 | default: |
616 | queue = 2; | 627 | queue = 2; |
617 | if (acm) | 628 | if (acm) |
618 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ | 629 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ |
630 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | ||
631 | uapsd = true; | ||
619 | break; | 632 | break; |
620 | } | 633 | } |
621 | 634 | ||
@@ -623,11 +636,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
623 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); | 636 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); |
624 | params.cw_min = ecw2cw(pos[1] & 0x0f); | 637 | params.cw_min = ecw2cw(pos[1] & 0x0f); |
625 | params.txop = get_unaligned_le16(pos + 2); | 638 | params.txop = get_unaligned_le16(pos + 2); |
639 | params.uapsd = uapsd; | ||
640 | |||
626 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 641 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
627 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 642 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " |
628 | "cWmin=%d cWmax=%d txop=%d\n", | 643 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", |
629 | wiphy_name(local->hw.wiphy), queue, aci, acm, | 644 | wiphy_name(local->hw.wiphy), queue, aci, acm, |
630 | params.aifs, params.cw_min, params.cw_max, params.txop); | 645 | params.aifs, params.cw_min, params.cw_max, params.txop, |
646 | params.uapsd); | ||
631 | #endif | 647 | #endif |
632 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) | 648 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) |
633 | printk(KERN_DEBUG "%s: failed to set TX queue " | 649 | printk(KERN_DEBUG "%s: failed to set TX queue " |
@@ -1906,6 +1922,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
1906 | wk->assoc.ht_information_ie = | 1922 | wk->assoc.ht_information_ie = |
1907 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | 1923 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); |
1908 | 1924 | ||
1925 | if (bss->wmm_used && bss->uapsd_supported && | ||
1926 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | ||
1927 | wk->assoc.uapsd_used = true; | ||
1928 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | ||
1929 | } else { | ||
1930 | wk->assoc.uapsd_used = false; | ||
1931 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; | ||
1932 | } | ||
1933 | |||
1909 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 1934 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
1910 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); | 1935 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); |
1911 | wk->assoc.ssid_len = ssid[1]; | 1936 | wk->assoc.ssid_len = ssid[1]; |