mac80211: introduce a QoS flag From: Johannes Berg The b43 driver needs to register more queues but doesn't always actually support QoS. Therefore, add a QoS flag that we can check and that works as follows: * the flag is set by default, QoS is assumed to be supported * if the driver registers with fewer than four queues, it can't support it and the flag is disabled * if the driver desires, it can disable the flag as well, and this is possible to do after HW registration (though still a hack) Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 +++++ net/mac80211/cfg.c | 2 +- net/mac80211/ibss.c | 2 +- net/mac80211/iface.c | 6 +++--- net/mac80211/main.c | 5 +++++ net/mac80211/mlme.c | 6 +++--- net/mac80211/tx.c | 2 +- net/mac80211/util.c | 4 ++-- net/mac80211/wme.c | 4 ++-- 9 files changed, 23 insertions(+), 13 deletions(-) --- a/include/net/mac80211.h 2012-06-08 20:03:44.000000000 +0200 +++ b/include/net/mac80211.h 2012-06-08 20:03:56.000000000 +0200 @@ -1197,6 +1197,10 @@ enum sta_notify_cmd { * queue mapping in order to use different queues (not just one per AC) * for different virtual interfaces. See the doc section on HW queue * control for more details. + * + * @IEEE80211_HW_SUPPORTS_QOS: The device supports QoS frames and will + * use AC parameters for medium access. When registering 4 or more + * queues, this is assumed unless explicitly disabled. */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -1224,6 +1228,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_AP_LINK_PS = 1<<22, IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, IEEE80211_HW_SCAN_WHILE_IDLE = 1<<24, + IEEE80211_HW_SUPPORTS_QOS = 1<<25, }; /** --- a/net/mac80211/cfg.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/cfg.c 2012-06-08 20:03:56.000000000 +0200 @@ -1704,7 +1704,7 @@ static int ieee80211_set_txq_params(stru if (!local->ops->conf_tx) return -EOPNOTSUPP; - if (local->hw.queues < IEEE80211_NUM_ACS) + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_QOS)) return -EOPNOTSUPP; memset(&p, 0, sizeof(p)); --- a/net/mac80211/ibss.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/ibss.c 2012-06-08 20:03:56.000000000 +0200 @@ -171,7 +171,7 @@ static void __ieee80211_sta_join_ibss(st chan, channel_type, 0); } - if (local->hw.queues >= IEEE80211_NUM_ACS) { + if (local->hw.flags & IEEE80211_HW_SUPPORTS_QOS) { pos = skb_put(skb, 9); *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = 7; /* len */ --- a/net/mac80211/iface.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/iface.c 2012-06-08 20:03:56.000000000 +0200 @@ -206,7 +206,7 @@ static void ieee80211_set_default_queues for (i = 0; i < IEEE80211_NUM_ACS; i++) { if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE; - else if (local->hw.queues >= IEEE80211_NUM_ACS) + else if (local->hw.flags & IEEE80211_HW_SUPPORTS_QOS) sdata->vif.hw_queue[i] = i; else sdata->vif.hw_queue[i] = 0; @@ -799,7 +799,7 @@ static u16 ieee80211_monitor_select_queu struct ieee80211_hdr *hdr; struct ieee80211_radiotap_header *rtap = (void *)skb->data; - if (local->hw.queues < IEEE80211_NUM_ACS) + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_QOS)) return 0; if (skb->len < 4 || @@ -1279,7 +1279,7 @@ int ieee80211_if_add(struct ieee80211_lo ASSERT_RTNL(); - if (local->hw.queues >= IEEE80211_NUM_ACS) + if (local->hw.flags & IEEE80211_HW_SUPPORTS_QOS) txqs = IEEE80211_NUM_ACS; ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, --- a/net/mac80211/main.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/main.c 2012-06-08 20:03:56.000000000 +0200 @@ -589,6 +589,8 @@ struct ieee80211_hw *ieee80211_alloc_hw( /* set up some defaults */ local->hw.queues = 1; + /* assume QoS, will be turned off later if not enough queues */ + local->hw.flags = IEEE80211_HW_SUPPORTS_QOS; local->hw.max_rates = 1; local->hw.max_report_rates = 0; local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; @@ -697,6 +699,9 @@ int ieee80211_register_hw(struct ieee802 local->hw.offchannel_tx_hw_queue >= local->hw.queues)) return -EINVAL; + if (hw->queues < IEEE80211_NUM_ACS) + hw->flags &= ~IEEE80211_HW_SUPPORTS_QOS; + if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) #ifdef CONFIG_PM && (!local->ops->suspend || !local->ops->resume) --- a/net/mac80211/mlme.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/mlme.c 2012-06-08 20:03:56.000000000 +0200 @@ -1119,7 +1119,7 @@ static void ieee80211_sta_wmm_params(str if (!local->ops->conf_tx) return; - if (local->hw.queues < IEEE80211_NUM_ACS) + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_QOS)) return; if (!wmm_param) @@ -3327,7 +3327,7 @@ int ieee80211_mgd_assoc(struct ieee80211 /* Also disable HT if we don't support it or the AP doesn't use WMM */ sband = local->hw.wiphy->bands[req->bss->channel->band]; if (!sband->ht_cap.ht_supported || - local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { + !(local->hw.flags & IEEE80211_HW_SUPPORTS_QOS) || !bss->wmm_used) { ifmgd->flags |= IEEE80211_STA_DISABLE_11N; netdev_info(sdata->dev, "disabling HT as WMM/QoS is not supported\n"); @@ -3354,7 +3354,7 @@ int ieee80211_mgd_assoc(struct ieee80211 assoc_data->capability = req->bss->capability; assoc_data->wmm = bss->wmm_used && - (local->hw.queues >= IEEE80211_NUM_ACS); + (local->hw.flags & IEEE80211_HW_SUPPORTS_QOS); assoc_data->supp_rates = bss->supp_rates; assoc_data->supp_rates_len = bss->supp_rates_len; --- a/net/mac80211/tx.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/tx.c 2012-06-08 20:03:56.000000000 +0200 @@ -1949,7 +1949,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s wme_sta = true; /* receiver and we are QoS enabled, use a QoS type frame */ - if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) { + if (wme_sta && local->hw.flags & IEEE80211_HW_SUPPORTS_QOS) { fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); hdrlen += 2; } --- a/net/mac80211/util.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/util.c 2012-06-08 20:03:56.000000000 +0200 @@ -810,7 +810,7 @@ void ieee80211_set_wmm_default(struct ie if (!local->ops->conf_tx) return; - if (local->hw.queues < IEEE80211_NUM_ACS) + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_QOS)) return; memset(&qparam, 0, sizeof(qparam)); @@ -1296,7 +1296,7 @@ int ieee80211_reconfig(struct ieee80211_ mutex_unlock(&local->sta_mtx); /* reconfigure tx conf */ - if (hw->queues >= IEEE80211_NUM_ACS) { + if (hw->flags & IEEE80211_HW_SUPPORTS_QOS) { list_for_each_entry(sdata, &local->interfaces, list) { if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || sdata->vif.type == NL80211_IFTYPE_MONITOR || --- a/net/mac80211/wme.c 2012-06-08 20:03:44.000000000 +0200 +++ b/net/mac80211/wme.c 2012-06-08 20:03:56.000000000 +0200 @@ -79,7 +79,7 @@ u16 ieee80211_select_queue_80211(struct { u8 *p; - if (local->hw.queues < IEEE80211_NUM_ACS) + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_QOS)) return 0; if (!ieee80211_is_data(hdr->frame_control)) { @@ -106,7 +106,7 @@ u16 ieee80211_select_queue(struct ieee80 const u8 *ra = NULL; bool qos = false; - if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_QOS) || skb->len < 6) { skb->priority = 0; /* required for correct WPA/11i MIC */ return 0; }