From e2530083609148a7835b54c431f6b8956407c1f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 17 May 2008 00:57:14 +0200 Subject: [PATCH] mac80211: use multi-queue master netdevice This patch updates mac80211 and drivers to be multi-queue aware and use that instead of the internal queue mapping. Also does a number of cleanups in various pieces of the code that fall out and reduces internal mac80211 state size. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 2 +- drivers/net/wireless/b43/dma.c | 7 +- drivers/net/wireless/b43/pio.c | 8 +- drivers/net/wireless/b43legacy/dma.c | 3 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +- drivers/net/wireless/p54/p54common.c | 8 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 10 +-- drivers/net/wireless/rt2x00/rt2x00queue.h | 13 --- drivers/net/wireless/rtl8180_dev.c | 4 +- include/net/mac80211.h | 20 ++++- net/mac80211/Kconfig | 14 ++- net/mac80211/Makefile | 2 +- net/mac80211/ieee80211_i.h | 16 ++-- net/mac80211/iface.c | 2 +- net/mac80211/main.c | 29 ++++-- net/mac80211/sta_info.c | 2 +- net/mac80211/tx.c | 97 ++++++++++----------- net/mac80211/util.c | 29 +++--- net/mac80211/wme.c | 14 ++- net/mac80211/wme.h | 2 +- 21 files changed, 158 insertions(+), 132 deletions(-) diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 7d97934265..18e9422d26 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2657,7 +2657,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, info->queue); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index aced9866d8..b4eadd908b 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1297,7 +1297,8 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, info->queue); + ring = select_ring_by_priority( + dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&ring->lock, flags); @@ -1315,7 +1316,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = info->queue; + ring->queue_prio = skb_get_queue_mapping(skb); err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { @@ -1333,7 +1334,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 284786a94e..8b1555d95f 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -509,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, info->queue); + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&q->lock, flags); @@ -532,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out_unlock; } @@ -540,7 +540,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = info->queue; + q->queue_prio = skb_get_queue_mapping(skb); err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { @@ -560,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, info->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index c1c501d963..33cc256c5b 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1325,11 +1325,10 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb) { struct b43legacy_dmaring *ring; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int err = 0; unsigned long flags; - ring = priority_to_txring(dev, info->queue); + ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a61293ba3f..0ebab967d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -696,7 +696,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tfd_frame *tfd; u32 *control_flags; - int txq_id = info->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; dma_addr_t phys_addr; @@ -917,7 +917,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, info->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a740a1817d..e0f52e2644 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2552,7 +2552,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = info->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2765,7 +2765,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, info->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 850857932e..91ac9208b7 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -407,7 +407,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); memset(&info->status, 0, sizeof(info->status)); - priv->tx_stats[info->queue].len--; + priv->tx_stats[skb_get_queue_mapping(skb)].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -551,13 +551,13 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) size_t padding, len; u8 rate; - current_queue = &priv->tx_stats[info->queue]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, info->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; @@ -589,7 +589,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(info->queue + 4); + txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4); txhdr->magic4 = 0; txhdr->antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index b5379b027b..c05e05b588 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -102,7 +102,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - enum data_queue_qid qid = mac80211_queue_to_qid(tx_info->queue); + enum data_queue_qid qid = skb_get_queue_mapping(skb); struct data_queue *queue; u16 frame_control; @@ -149,23 +149,23 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IEEE80211_TX_CTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } } if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, tx_info->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index f263fe422f..4d00ced14c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -79,19 +79,6 @@ enum data_queue_qid { QID_ATIM, }; -/** - * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid - * @queue: mac80211 queue. - */ -static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) -{ - /* Regular TX queues are mapped directly */ - if (queue < 4) - return queue; - WARN_ON(1); - return QID_OTHER; -} - /** * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc * diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 4427bc9f78..b7172a12c0 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -246,7 +246,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) u16 plcp_len = 0; __le16 rts_duration = 0; - prio = info->queue; + prio = skb_get_queue_mapping(skb); ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, @@ -298,7 +298,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, info->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4df39eb911..c80e3be8f7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -293,7 +293,7 @@ struct ieee80211_tx_info { s8 tx_rate_idx; u8 antenna_sel_tx; - u8 queue; /* use skb_queue_mapping soon */ + /* 1 byte hole */ union { struct { @@ -802,6 +802,24 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_QOS + return hw->queues; +#else + return 1; +#endif +} + +static inline int ieee80211_num_queues(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_QOS + return hw->queues + hw->ampdu_queues; +#else + return 1; +#endif +} + static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index a24b459dd4..590e00b276 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -7,11 +7,23 @@ config MAC80211 select CRC32 select WIRELESS_EXT select CFG80211 - select NET_SCH_FIFO ---help--- This option enables the hardware independent IEEE 802.11 networking stack. +config MAC80211_QOS + def_bool y + depends on MAC80211 + depends on NET_SCHED + depends on NETDEVICES_MULTIQUEUE + +comment "QoS/HT support disabled" + depends on MAC80211 && !MAC80211_QOS +comment "QoS/HT support needs CONFIG_NET_SCHED" + depends on MAC80211 && !NET_SCHED +comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE" + depends on MAC80211 && !NETDEVICES_MULTIQUEUE + menu "Rate control algorithm selection" depends on MAC80211 != n diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 4e5847fd31..1d2a4e010e 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -29,7 +29,7 @@ mac80211-y := \ event.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o -mac80211-$(CONFIG_NET_SCHED) += wme.o +mac80211-$(CONFIG_MAC80211_QOS) += wme.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs.o \ debugfs_sta.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 86a861251e..7d614cdcef 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -594,7 +594,7 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; + unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; @@ -758,6 +758,15 @@ struct ieee80211_local { #endif }; +static inline int ieee80211_is_multiqueue(struct ieee80211_local *local) +{ +#ifdef CONFIG_MAC80211_QOS + return netif_is_multiqueue(local->mdev); +#else + return 0; +#endif +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; @@ -827,11 +836,6 @@ static inline struct ieee80211_hw *local_to_hw( return &local->hw; } -enum ieee80211_link_state_t { - IEEE80211_LINK_STATE_XOFF = 0, - IEEE80211_LINK_STATE_PENDING, -}; - struct sta_attribute { struct attribute attr; ssize_t (*show)(const struct sta_info *, char *buf); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3c64e42eb1..9844727023 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -168,7 +168,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ifsta->flags |= IEEE80211_STA_CREATE_IBSS | IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL; - if (sdata->local->hw.queues >= 4) + if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) ifsta->flags |= IEEE80211_STA_WMM_ENABLED; msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8f1ff7ef16..97d4a537ca 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1634,12 +1634,32 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) return result; + /* + * We use the number of queues for feature tests (QoS, HT) internally + * so restrict them appropriately. + */ +#ifdef CONFIG_MAC80211_QOS + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; + if (hw->queues < 4) + hw->ampdu_queues = 0; +#else + hw->queues = 1; + hw->ampdu_queues = 0; +#endif + /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); + mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup, + ieee80211_num_queues(hw)); if (!mdev) goto fail_mdev_alloc; + if (ieee80211_num_queues(hw) > 1) + mdev->features |= NETIF_F_MULTI_QUEUE; + sdata = IEEE80211_DEV_TO_SUB_IF(mdev); mdev->ieee80211_ptr = &sdata->wdev; sdata->wdev.wiphy = local->hw.wiphy; @@ -1728,11 +1748,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_wep; } - if (hw->queues > IEEE80211_MAX_QUEUES) - hw->queues = IEEE80211_MAX_QUEUES; - if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) - hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; - ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ef3149324d..c24770cb02 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -255,7 +255,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; /* tid to tx queue: initialize according to HW (0 is valid) */ - sta->tid_to_tx_q[i] = local->hw.queues + local->hw.ampdu_queues; + sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw); /* rx */ sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; sta->ampdu_mlme.tid_rx[i] = NULL; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6268bbca14..9273651d3d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -213,18 +213,6 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, return dur; } -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); -} - static int inline is_ieee80211_device(struct net_device *dev, struct net_device *master) { @@ -680,7 +668,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) * etc. */ if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU || - IEEE80211_SKB_CB(tx->skb)->queue >= tx->local->hw.queues)) + skb_get_queue_mapping(tx->skb) >= + ieee80211_num_regular_queues(&tx->local->hw))) return TX_DROP; first = tx->skb; @@ -1098,11 +1087,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); + if (netif_subqueue_stopped(local->mdev, skb)) return IEEE80211_TX_AGAIN; - } + if (skb) { ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); @@ -1121,7 +1108,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, IEEE80211_TX_CTL_USE_CTS_PROTECT | IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT); - if (__ieee80211_queue_stopped(local, info->queue)) + if (netif_subqueue_stopped(local->mdev, + tx->extra_frag[i])) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { info->tx_rate_idx = tx->last_frag_rate_idx; @@ -1160,9 +1148,11 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) ieee80211_tx_result res = TX_DROP, res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret, i; - int queue = info->queue; + u16 queue; - WARN_ON(__ieee80211_queue_pending(local, queue)); + queue = skb_get_queue_mapping(skb); + + WARN_ON(test_bit(queue, local->queues_pending)); if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); @@ -1233,28 +1223,28 @@ retry: * queues, there's no reason for a driver to reject * a frame there, warn and drop it. */ - if (WARN_ON(queue >= local->hw.queues)) + if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw))) goto drop; store = &local->pending_packet[queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue]); + set_bit(queue, local->queues_pending); smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer + /* + * When the driver gets out of buffers during sending of + * fragments and calls ieee80211_stop_queue, the netif + * subqueue is stopped. There is, however, a small window + * in which the PENDING bit is not yet set. If a buffer * gets available in that window (i.e. driver calls * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by + * called with the PENDING bit still set. Prevent this by * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue]); + * possible to have happened. + */ + if (!__netif_subqueue_stopped(local->mdev, queue)) { + clear_bit(queue, local->queues_pending); goto retry; } store->skb = skb; @@ -1509,7 +1499,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, } /* receiver and we are QoS enabled, use a QoS type frame */ - if (sta_flags & WLAN_STA_WME && local->hw.queues >= 4) { + if (sta_flags & WLAN_STA_WME && + ieee80211_num_regular_queues(&local->hw) >= 4) { fc |= IEEE80211_STYPE_QOS_DATA; hdrlen += 2; } @@ -1661,41 +1652,51 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, return ret; } -/* helper functions for pending packets for when queues are stopped */ +/* + * ieee80211_clear_tx_pending may not be called in a context where + * it is possible that it packets could come in again. + */ void ieee80211_clear_tx_pending(struct ieee80211_local *local) { int i, j; struct ieee80211_tx_stored_packet *store; - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + if (!test_bit(i, local->queues_pending)) continue; store = &local->pending_packet[i]; kfree_skb(store->skb); for (j = 0; j < store->num_extra_frag; j++) kfree_skb(store->extra_frag[j]); kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); + clear_bit(i, local->queues_pending); } } +/* + * Transmit all pending packets. Called from tasklet, locks master device + * TX lock so that no new packets can come in. + */ void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; struct net_device *dev = local->mdev; struct ieee80211_tx_stored_packet *store; struct ieee80211_tx_data tx; - int i, ret, reschedule = 0; + int i, ret; netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) + for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { + /* Check that this queue is ok */ + if (__netif_subqueue_stopped(local->mdev, i)) continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; + + if (!test_bit(i, local->queues_pending)) { + ieee80211_wake_queue(&local->hw, i); continue; } + store = &local->pending_packet[i]; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; @@ -1708,19 +1709,11 @@ void ieee80211_tx_pending(unsigned long data) if (ret == IEEE80211_TX_FRAG_AGAIN) store->skb = NULL; } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; + clear_bit(i, local->queues_pending); + ieee80211_wake_queue(&local->hw, i); } } netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } } /* functions for drivers to get certain frames */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d9109dee46..4f7180b287 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -331,17 +331,15 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); + if (test_bit(queue, local->queues_pending)) { + tasklet_schedule(&local->tx_pending_tasklet); + } else { + if (ieee80211_is_multiqueue(local)) { + netif_wake_subqueue(local->mdev, queue); + } else { + WARN_ON(queue != 0); + netif_wake_queue(local->mdev); + } } } EXPORT_SYMBOL(ieee80211_wake_queue); @@ -350,9 +348,12 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) + if (ieee80211_is_multiqueue(local)) { + netif_stop_subqueue(local->mdev, queue); + } else { + WARN_ON(queue != 0); netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); + } } EXPORT_SYMBOL(ieee80211_stop_queue); @@ -360,7 +361,7 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw) { int i; - for (i = 0; i < hw->queues + hw->ampdu_queues; i++) + for (i = 0; i < ieee80211_num_queues(hw); i++) ieee80211_stop_queue(hw, i); } EXPORT_SYMBOL(ieee80211_stop_queues); diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 477690f4dc..14a9ff10a1 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -158,7 +158,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) u8 tid; if (info->flags & IEEE80211_TX_CTL_REQUEUE) { - queue = info->queue; + queue = skb_get_queue_mapping(skb); rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; @@ -219,7 +219,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) err = NET_XMIT_DROP; } else { tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - info->queue = (unsigned int) queue; + skb_set_queue_mapping(skb, queue); qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); if (err == NET_XMIT_SUCCESS) { @@ -240,12 +240,11 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct Qdisc *qdisc; int err; /* we recorded which queue to use earlier! */ - qdisc = q->queues[info->queue]; + qdisc = q->queues[skb_get_queue_mapping(skb)]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { qd->q.qlen++; @@ -269,11 +268,8 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < QD_NUM(hw); queue++) { /* see if there is room in this hardware queue */ - if ((test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) || - (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) + if (__netif_subqueue_stopped(local->mdev, queue) || + !test_bit(queue, q->qdisc_pool)) continue; /* there is space - try and get a frame */ diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index fcc6b05508..bbdb533448 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc) return (fc & 0x8C) == 0x88; } -#ifdef CONFIG_NET_SCHED +#ifdef CONFIG_MAC80211_QOS void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, -- 2.39.5