mac80211/iwlwifi: move virtual A-MDPU queue bookkeeping to iwlwifi

This patch removes all the virtual A-MPDU-queue bookkeeping from
mac80211. Curiously, iwlwifi already does its own bookkeeping, so
it doesn't require much changes except where it needs to handle
starting and stopping the queues in mac80211.

To handle the queue stop/wake properly, we rewrite the software
queue number for aggregation frames and internally to iwlwifi keep
track of the queues that map into the same AC queue, and only talk
to mac80211 about the AC queue. The implementation requires calling
two new functions, iwl_stop_queue and iwl_wake_queue instead of the
mac80211 counterparts.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Reinette Chattre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 64b839b..947aaaa 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -131,14 +131,6 @@
 
 	state = &sta->ampdu_mlme.tid_state_tx[tid];
 
-	if (local->hw.ampdu_queues) {
-		/*
-		 * Pretend the driver woke the queue, just in case
-		 * it disabled it before the session was stopped.
-		 */
-		ieee80211_wake_queue(
-			&local->hw, local->hw.queues + sta->tid_to_tx_q[tid]);
-	}
 	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
 		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 
@@ -206,7 +198,7 @@
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata;
 	u8 *state;
-	int i, qn = -1, ret = 0;
+	int ret = 0;
 	u16 start_seq_num;
 
 	if (WARN_ON(!local->ops->ampdu_action))
@@ -275,29 +267,6 @@
 		goto err_unlock_sta;
 	}
 
-	if (hw->ampdu_queues) {
-		spin_lock(&local->queue_stop_reason_lock);
-		/* reserve a new queue for this session */
-		for (i = 0; i < local->hw.ampdu_queues; i++) {
-			if (local->ampdu_ac_queue[i] < 0) {
-				qn = i;
-				local->ampdu_ac_queue[qn] =
-					ieee80211_ac_from_tid(tid);
-				break;
-			}
-		}
-		spin_unlock(&local->queue_stop_reason_lock);
-
-		if (qn < 0) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-			printk(KERN_DEBUG "BA request denied - "
-			       "queue unavailable for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-			ret = -ENOSPC;
-			goto err_unlock_sta;
-		}
-	}
-
 	/*
 	 * While we're asking the driver about the aggregation,
 	 * stop the AC queue so that we don't have to worry
@@ -319,7 +288,7 @@
 					tid);
 #endif
 		ret = -ENOMEM;
-		goto err_return_queue;
+		goto err_wake_queue;
 	}
 
 	skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
@@ -348,7 +317,6 @@
 		*state = HT_AGG_STATE_IDLE;
 		goto err_free;
 	}
-	sta->tid_to_tx_q[tid] = qn;
 
 	/* Driver vetoed or OKed, but we can take packets again now */
 	ieee80211_wake_queue_by_reason(
@@ -380,13 +348,7 @@
  err_free:
 	kfree(sta->ampdu_mlme.tid_tx[tid]);
 	sta->ampdu_mlme.tid_tx[tid] = NULL;
- err_return_queue:
-	if (qn >= 0) {
-		/* give queue back to pool */
-		spin_lock(&local->queue_stop_reason_lock);
-		local->ampdu_ac_queue[qn] = -1;
-		spin_unlock(&local->queue_stop_reason_lock);
-	}
+ err_wake_queue:
 	ieee80211_wake_queue_by_reason(
 		&local->hw, ieee80211_ac_from_tid(tid),
 		IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 32345b4..e6ed78c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -594,12 +594,7 @@
 
 	const struct ieee80211_ops *ops;
 
-	/* AC queue corresponding to each AMPDU queue */
-	s8 ampdu_ac_queue[IEEE80211_MAX_AMPDU_QUEUES];
-	unsigned int amdpu_ac_stop_refcnt[IEEE80211_MAX_AMPDU_QUEUES];
-
-	unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES +
-					 IEEE80211_MAX_AMPDU_QUEUES];
+	unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
 	/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
 	spinlock_t queue_stop_reason_lock;
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 756284e..a6f1d8a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -774,11 +774,6 @@
 	setup_timer(&local->dynamic_ps_timer,
 		    ieee80211_dynamic_ps_timer, (unsigned long) local);
 
-	for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++)
-		local->ampdu_ac_queue[i] = -1;
-	/* using an s8 won't work with more than that */
-	BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127);
-
 	sta_info_init(local);
 
 	for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
@@ -874,10 +869,6 @@
 	 */
 	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;
 
 	mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
 			       "wmaster%d", ieee80211_master_setup,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index dd3593c..c5f14e6 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -203,17 +203,6 @@
 		if (tid_rx)
 			tid_rx->shutdown = true;
 
-		/*
-		 * The stop callback cannot find this station any more, but
-		 * it didn't complete its work -- start the queue if necessary
-		 */
-		if (sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_INITIATOR_MSK &&
-		    sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_REQ_STOP_BA_MSK &&
-		    local->hw.ampdu_queues)
-			ieee80211_wake_queue_by_reason(&local->hw,
-				local->hw.queues + sta->tid_to_tx_q[i],
-				IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-
 		spin_unlock_bh(&sta->lock);
 
 		/*
@@ -292,7 +281,6 @@
 		 * enable session_timer's data differentiation. refer to
 		 * sta_rx_agg_session_timer_expired for useage */
 		sta->timer_to_tid[i] = i;
-		sta->tid_to_tx_q[i] = -1;
 		/* rx */
 		sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
 		sta->ampdu_mlme.tid_rx[i] = NULL;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 18fd5d1..5534d48 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -206,7 +206,6 @@
  * @tid_seq: per-TID sequence numbers for sending to this STA
  * @ampdu_mlme: A-MPDU state machine state
  * @timer_to_tid: identity mapping to ID timers
- * @tid_to_tx_q: map tid to tx queue (invalid == negative values)
  * @llid: Local link ID
  * @plid: Peer link ID
  * @reason: Cancel reason on PLINK_HOLDING state
@@ -281,7 +280,6 @@
 	 */
 	struct sta_ampdu_mlme ampdu_mlme;
 	u8 timer_to_tid[STA_TID_NUM];
-	s8 tid_to_tx_q[STA_TID_NUM];
 
 #ifdef CONFIG_MAC80211_MESH
 	/*
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 906ab78..3fb04a8 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1145,25 +1145,6 @@
 			info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
 					 IEEE80211_TX_CTL_FIRST_FRAGMENT);
 
-		/*
-		 * Internally, we need to have the queue mapping point to
-		 * the real AC queue, not the virtual A-MPDU queue. This
-		 * now finally sets the queue to what the driver wants.
-		 * We will later move this down into the only driver that
-		 * needs it, iwlwifi.
-		 */
-		if (sta && local->hw.ampdu_queues &&
-		    info->flags & IEEE80211_TX_CTL_AMPDU) {
-			unsigned long flags;
-			u8 *qc = ieee80211_get_qos_ctl((void *) skb->data);
-			int tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
-
-			spin_lock_irqsave(&sta->lock, flags);
-			skb_set_queue_mapping(skb, local->hw.queues +
-						   sta->tid_to_tx_q[tid]);
-			spin_unlock_irqrestore(&sta->lock, flags);
-		}
-
 		next = skb->next;
 		len = skb->len;
 		ret = local->ops->tx(local_to_hw(local), skb);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0247d80..fdf432f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -339,29 +339,8 @@
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
-	if (queue >= hw->queues) {
-		if (local->ampdu_ac_queue[queue - hw->queues] < 0)
-			return;
-
-		/*
-		 * for virtual aggregation queues, we need to refcount the
-		 * internal mac80211 disable (multiple times!), keep track of
-		 * driver disable _and_ make sure the regular queue is
-		 * actually enabled.
-		 */
-		if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
-			local->amdpu_ac_stop_refcnt[queue - hw->queues]--;
-		else
-			__clear_bit(reason, &local->queue_stop_reasons[queue]);
-
-		if (local->queue_stop_reasons[queue] ||
-		    local->amdpu_ac_stop_refcnt[queue - hw->queues])
-			return;
-
-		/* now go on to treat the corresponding regular queue */
-		queue = local->ampdu_ac_queue[queue - hw->queues];
-		reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
-	}
+	if (WARN_ON(queue >= hw->queues))
+		return;
 
 	__clear_bit(reason, &local->queue_stop_reasons[queue]);
 
@@ -400,25 +379,8 @@
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
-	if (queue >= hw->queues) {
-		if (local->ampdu_ac_queue[queue - hw->queues] < 0)
-			return;
-
-		/*
-		 * for virtual aggregation queues, we need to refcount the
-		 * internal mac80211 disable (multiple times!), keep track of
-		 * driver disable _and_ make sure the regular queue is
-		 * actually enabled.
-		 */
-		if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
-			local->amdpu_ac_stop_refcnt[queue - hw->queues]++;
-		else
-			__set_bit(reason, &local->queue_stop_reasons[queue]);
-
-		/* now go on to treat the corresponding regular queue */
-		queue = local->ampdu_ac_queue[queue - hw->queues];
-		reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
-	}
+	if (WARN_ON(queue >= hw->queues))
+		return;
 
 	/*
 	 * Only stop if it was previously running, this is necessary
@@ -474,15 +436,9 @@
 int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	unsigned long flags;
 
-	if (queue >= hw->queues) {
-		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-		queue = local->ampdu_ac_queue[queue - hw->queues];
-		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-		if (queue < 0)
-			return true;
-	}
+	if (WARN_ON(queue >= hw->queues))
+		return true;
 
 	return __netif_subqueue_stopped(local->mdev, queue);
 }
@@ -497,7 +453,7 @@
 
 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
 
-	for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
+	for (i = 0; i < hw->queues; i++)
 		__ieee80211_wake_queue(hw, i, reason);
 
 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);