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>
This commit is contained in:

committed by
John W. Linville

parent
cd8ffc800c
commit
e4e72fb4de
@@ -293,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
|
||||
if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
|
||||
(txq_id != IWL_CMD_QUEUE_NUM) &&
|
||||
priv->mac80211_registered)
|
||||
ieee80211_wake_queue(priv->hw, txq_id);
|
||||
iwl_wake_queue(priv, txq_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -2178,10 +2178,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
||||
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
|
||||
(agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
|
||||
if (agg->state == IWL_AGG_OFF)
|
||||
ieee80211_wake_queue(priv->hw, txq_id);
|
||||
iwl_wake_queue(priv, txq_id);
|
||||
else
|
||||
ieee80211_wake_queue(priv->hw,
|
||||
txq->swq_id);
|
||||
iwl_wake_queue(priv, txq->swq_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2205,7 +2204,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
||||
|
||||
if (priv->mac80211_registered &&
|
||||
(iwl_queue_space(&txq->q) > txq->q.low_mark))
|
||||
ieee80211_wake_queue(priv->hw, txq_id);
|
||||
iwl_wake_queue(priv, txq_id);
|
||||
}
|
||||
|
||||
if (qc && likely(sta_id != IWL_INVALID_STATION))
|
||||
|
@@ -1295,10 +1295,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
|
||||
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
|
||||
(agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
|
||||
if (agg->state == IWL_AGG_OFF)
|
||||
ieee80211_wake_queue(priv->hw, txq_id);
|
||||
iwl_wake_queue(priv, txq_id);
|
||||
else
|
||||
ieee80211_wake_queue(priv->hw,
|
||||
txq->swq_id);
|
||||
iwl_wake_queue(priv, txq->swq_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1324,7 +1323,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
|
||||
|
||||
if (priv->mac80211_registered &&
|
||||
(iwl_queue_space(&txq->q) > txq->q.low_mark))
|
||||
ieee80211_wake_queue(priv->hw, txq_id);
|
||||
iwl_wake_queue(priv, txq_id);
|
||||
}
|
||||
|
||||
if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
|
||||
|
@@ -1309,9 +1309,6 @@ int iwl_setup_mac(struct iwl_priv *priv)
|
||||
|
||||
/* Default value; 4 EDCA QOS priorities */
|
||||
hw->queues = 4;
|
||||
/* queues to support 11n aggregation */
|
||||
if (priv->cfg->sku & IWL_SKU_N)
|
||||
hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues;
|
||||
|
||||
hw->conf.beacon_int = 100;
|
||||
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
|
||||
|
@@ -996,6 +996,12 @@ struct iwl_priv {
|
||||
u8 key_mapping_key;
|
||||
unsigned long ucode_key_table;
|
||||
|
||||
/* queue refcounts */
|
||||
#define IWL_MAX_HW_QUEUES 32
|
||||
unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
|
||||
/* for each AC */
|
||||
atomic_t queue_stop_count[4];
|
||||
|
||||
/* Indication if ieee80211_ops->open has been called */
|
||||
u8 is_open;
|
||||
|
||||
|
@@ -93,4 +93,56 @@ static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
|
||||
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* we have 8 bits used like this:
|
||||
*
|
||||
* 7 6 5 4 3 2 1 0
|
||||
* | | | | | | | |
|
||||
* | | | | | | +-+-------- AC queue (0-3)
|
||||
* | | | | | |
|
||||
* | +-+-+-+-+------------ HW A-MPDU queue
|
||||
* |
|
||||
* +---------------------- indicates agg queue
|
||||
*/
|
||||
static inline u8 iwl_virtual_agg_queue_num(u8 ac, u8 hwq)
|
||||
{
|
||||
BUG_ON(ac > 3); /* only have 2 bits */
|
||||
BUG_ON(hwq > 31); /* only have 5 bits */
|
||||
|
||||
return 0x80 | (hwq << 2) | ac;
|
||||
}
|
||||
|
||||
static inline void iwl_wake_queue(struct iwl_priv *priv, u8 queue)
|
||||
{
|
||||
u8 ac = queue;
|
||||
u8 hwq = queue;
|
||||
|
||||
if (queue & 0x80) {
|
||||
ac = queue & 3;
|
||||
hwq = (queue >> 2) & 0x1f;
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(hwq, priv->queue_stopped))
|
||||
if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0)
|
||||
ieee80211_wake_queue(priv->hw, ac);
|
||||
}
|
||||
|
||||
static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
|
||||
{
|
||||
u8 ac = queue;
|
||||
u8 hwq = queue;
|
||||
|
||||
if (queue & 0x80) {
|
||||
ac = queue & 3;
|
||||
hwq = (queue >> 2) & 0x1f;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(hwq, priv->queue_stopped))
|
||||
if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0)
|
||||
ieee80211_stop_queue(priv->hw, ac);
|
||||
}
|
||||
|
||||
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
|
||||
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
|
||||
|
||||
#endif /* __iwl_helpers_h__ */
|
||||
|
@@ -763,8 +763,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
||||
hdr->seq_ctrl |= cpu_to_le16(seq_number);
|
||||
seq_number += 0x10;
|
||||
/* aggregation is on for this <sta,tid> */
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
|
||||
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
|
||||
swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
|
||||
}
|
||||
priv->stations[sta_id].tid[tid].tfds_in_queue++;
|
||||
}
|
||||
|
||||
@@ -895,7 +897,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
||||
iwl_txq_update_write_ptr(priv, txq);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
} else {
|
||||
ieee80211_stop_queue(priv->hw, txq->swq_id);
|
||||
iwl_stop_queue(priv, txq->swq_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1433,7 +1435,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
|
||||
if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
|
||||
priv->mac80211_registered &&
|
||||
(agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
|
||||
ieee80211_wake_queue(priv->hw, txq->swq_id);
|
||||
iwl_wake_queue(priv, txq->swq_id);
|
||||
|
||||
iwl_txq_check_empty(priv, sta_id, tid, scd_flow);
|
||||
}
|
||||
|
@@ -1168,7 +1168,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
|
||||
iwl_stop_queue(priv, skb_get_queue_mapping(skb));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -933,7 +933,6 @@ static int __init init_mac80211_hwsim(void)
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
hw->ampdu_queues = 1;
|
||||
|
||||
hw->flags = IEEE80211_HW_MFP_CAPABLE;
|
||||
|
||||
|
Reference in New Issue
Block a user