summaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-10-07 03:38:50 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-10-22 04:42:09 -0400
commit02219b3abca59fca81711bfe7ee78df7abad97ce (patch)
treeafaa7b17ffde140c2791a87c9dde1a489a949f36 /net/mac80211/mlme.c
parentf409079bb678600be0201cd03afb4731f0480b4e (diff)
mac80211: add WMM admission control support
Use the currently existing APIs between mac80211 and the low level driver to implement WMM admission control. The low level driver needs to report the media time used by each transmitted packet in ieee80211_tx_status. Based on that information, mac80211 will modify the QoS parameters of the admission controlled Access Category when the limit is reached. Once the original QoS parameters can be restored, mac80211 will do so. One issue with this approach is that management frames will also erroneously be downgraded, but the upside is that the implementation is simple. In the future, it can be extended to driver- or device-based implementations that are better. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c142
1 files changed, 138 insertions, 4 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index fb6561509caf..4d9b4d165ce8 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1606,6 +1606,95 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
1606 mutex_unlock(&sdata->local->mtx); 1606 mutex_unlock(&sdata->local->mtx);
1607} 1607}
1608 1608
1609static bool
1610__ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
1611{
1612 struct ieee80211_local *local = sdata->local;
1613 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1614 bool ret;
1615 int ac;
1616
1617 if (local->hw.queues < IEEE80211_NUM_ACS)
1618 return false;
1619
1620 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
1621 struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
1622 int non_acm_ac;
1623 unsigned long now = jiffies;
1624
1625 if (tx_tspec->action == TX_TSPEC_ACTION_NONE &&
1626 tx_tspec->admitted_time &&
1627 time_after(now, tx_tspec->time_slice_start + HZ)) {
1628 tx_tspec->consumed_tx_time = 0;
1629 tx_tspec->time_slice_start = now;
1630
1631 if (tx_tspec->downgraded)
1632 tx_tspec->action =
1633 TX_TSPEC_ACTION_STOP_DOWNGRADE;
1634 }
1635
1636 switch (tx_tspec->action) {
1637 case TX_TSPEC_ACTION_STOP_DOWNGRADE:
1638 /* take the original parameters */
1639 if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac]))
1640 sdata_err(sdata,
1641 "failed to set TX queue parameters for queue %d\n",
1642 ac);
1643 tx_tspec->action = TX_TSPEC_ACTION_NONE;
1644 tx_tspec->downgraded = false;
1645 ret = true;
1646 break;
1647 case TX_TSPEC_ACTION_DOWNGRADE:
1648 if (time_after(now, tx_tspec->time_slice_start + HZ)) {
1649 tx_tspec->action = TX_TSPEC_ACTION_NONE;
1650 ret = true;
1651 break;
1652 }
1653 /* downgrade next lower non-ACM AC */
1654 for (non_acm_ac = ac + 1;
1655 non_acm_ac < IEEE80211_NUM_ACS;
1656 non_acm_ac++)
1657 if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac)))
1658 break;
1659 /* The loop will result in using BK even if it requires
1660 * admission control, such configuration makes no sense
1661 * and we have to transmit somehow - the AC selection
1662 * does the same thing.
1663 */
1664 if (drv_conf_tx(local, sdata, ac,
1665 &sdata->tx_conf[non_acm_ac]))
1666 sdata_err(sdata,
1667 "failed to set TX queue parameters for queue %d\n",
1668 ac);
1669 tx_tspec->action = TX_TSPEC_ACTION_NONE;
1670 ret = true;
1671 schedule_delayed_work(&ifmgd->tx_tspec_wk,
1672 tx_tspec->time_slice_start + HZ - now + 1);
1673 break;
1674 case TX_TSPEC_ACTION_NONE:
1675 /* nothing now */
1676 break;
1677 }
1678 }
1679
1680 return ret;
1681}
1682
1683void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
1684{
1685 if (__ieee80211_sta_handle_tspec_ac_params(sdata))
1686 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
1687}
1688
1689static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
1690{
1691 struct ieee80211_sub_if_data *sdata;
1692
1693 sdata = container_of(work, struct ieee80211_sub_if_data,
1694 u.mgd.tx_tspec_wk.work);
1695 ieee80211_sta_handle_tspec_ac_params(sdata);
1696}
1697
1609/* MLME */ 1698/* MLME */
1610static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, 1699static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1611 struct ieee80211_sub_if_data *sdata, 1700 struct ieee80211_sub_if_data *sdata,
@@ -1690,12 +1779,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1690 params.uapsd = uapsd; 1779 params.uapsd = uapsd;
1691 1780
1692 mlme_dbg(sdata, 1781 mlme_dbg(sdata,
1693 "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", 1782 "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
1694 queue, aci, acm, 1783 queue, aci, acm,
1695 params.aifs, params.cw_min, params.cw_max, 1784 params.aifs, params.cw_min, params.cw_max,
1696 params.txop, params.uapsd); 1785 params.txop, params.uapsd,
1786 ifmgd->tx_tspec[queue].downgraded);
1697 sdata->tx_conf[queue] = params; 1787 sdata->tx_conf[queue] = params;
1698 if (drv_conf_tx(local, sdata, queue, &params)) 1788 if (!ifmgd->tx_tspec[queue].downgraded &&
1789 drv_conf_tx(local, sdata, queue, &params))
1699 sdata_err(sdata, 1790 sdata_err(sdata,
1700 "failed to set TX queue parameters for queue %d\n", 1791 "failed to set TX queue parameters for queue %d\n",
1701 queue); 1792 queue);
@@ -1958,6 +2049,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1958 } 2049 }
1959 mutex_unlock(&local->mtx); 2050 mutex_unlock(&local->mtx);
1960 2051
2052 /* existing TX TSPEC sessions no longer exist */
2053 memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec));
2054 cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
2055
1961 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; 2056 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
1962} 2057}
1963 2058
@@ -2010,9 +2105,46 @@ out:
2010 mutex_unlock(&local->mtx); 2105 mutex_unlock(&local->mtx);
2011} 2106}
2012 2107
2108static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
2109 struct ieee80211_hdr *hdr,
2110 u16 tx_time)
2111{
2112 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2113 u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
2114 int ac = ieee80211_ac_from_tid(tid);
2115 struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
2116 unsigned long now = jiffies;
2117
2118 if (likely(!tx_tspec->admitted_time))
2119 return;
2120
2121 if (time_after(now, tx_tspec->time_slice_start + HZ)) {
2122 tx_tspec->consumed_tx_time = 0;
2123 tx_tspec->time_slice_start = now;
2124
2125 if (tx_tspec->downgraded) {
2126 tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
2127 schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
2128 }
2129 }
2130
2131 if (tx_tspec->downgraded)
2132 return;
2133
2134 tx_tspec->consumed_tx_time += tx_time;
2135
2136 if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) {
2137 tx_tspec->downgraded = true;
2138 tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE;
2139 schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
2140 }
2141}
2142
2013void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, 2143void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
2014 struct ieee80211_hdr *hdr, bool ack) 2144 struct ieee80211_hdr *hdr, bool ack, u16 tx_time)
2015{ 2145{
2146 ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time);
2147
2016 if (!ieee80211_is_data(hdr->frame_control)) 2148 if (!ieee80211_is_data(hdr->frame_control))
2017 return; 2149 return;
2018 2150
@@ -3834,6 +3966,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
3834 (unsigned long) sdata); 3966 (unsigned long) sdata);
3835 setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, 3967 setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
3836 (unsigned long) sdata); 3968 (unsigned long) sdata);
3969 INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk,
3970 ieee80211_sta_handle_tspec_ac_params_wk);
3837 3971
3838 ifmgd->flags = 0; 3972 ifmgd->flags = 0;
3839 ifmgd->powersave = sdata->wdev.ps; 3973 ifmgd->powersave = sdata->wdev.ps;