Commit 9eae88fa authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

iwlwifi: move queue mapping out of transport



The queue mapping is not only dynamic, it
is also dependent on the uCode, as we can
already see today with the dual-mode and
non-dual-mode being different.

Move the queue mapping out of the transport
layer and let the higher layer manage it.
Part of the transport configuration is how
to set up the queues.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e5610382
......@@ -157,7 +157,6 @@ static struct iwl_lib_ops iwl1000_lib = {
static const struct iwl_base_params iwl1000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
......
......@@ -171,7 +171,6 @@ static struct iwl_lib_ops iwl2030_lib = {
static const struct iwl_base_params iwl2000_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
......@@ -190,7 +189,6 @@ static const struct iwl_base_params iwl2000_base_params = {
static const struct iwl_base_params iwl2030_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
......
......@@ -308,7 +308,6 @@ static struct iwl_lib_ops iwl5150_lib = {
static const struct iwl_base_params iwl5000_base_params = {
.eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.led_compensation = 51,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
......
......@@ -269,7 +269,6 @@ static struct iwl_lib_ops iwl6030_lib = {
static const struct iwl_base_params iwl6000_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
......@@ -286,7 +285,6 @@ static const struct iwl_base_params iwl6000_base_params = {
static const struct iwl_base_params iwl6050_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
......@@ -303,7 +301,6 @@ static const struct iwl_base_params iwl6050_base_params = {
static const struct iwl_base_params iwl6000_g2_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
......
......@@ -103,9 +103,6 @@
/* EEPROM */
#define IWLAGN_EEPROM_IMG_SIZE 2048
#define IWLAGN_CMD_FIFO_NUM 7
#define IWLAGN_NUM_QUEUES 20
#define IWLAGN_NUM_AMPDU_QUEUES 9
#define IWLAGN_FIRST_AMPDU_QUEUE 11
#endif /* __iwl_agn_hw_h__ */
......@@ -40,6 +40,17 @@
#include "iwl-agn.h"
#include "iwl-trans.h"
static const u8 tid_to_ac[] = {
IEEE80211_AC_BE,
IEEE80211_AC_BK,
IEEE80211_AC_BK,
IEEE80211_AC_BE,
IEEE80211_AC_VI,
IEEE80211_AC_VI,
IEEE80211_AC_VO,
IEEE80211_AC_VO,
};
static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
__le16 fc, __le32 *tx_flags)
......@@ -293,6 +304,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u16 len, seq_number = 0;
u8 sta_id, tid = IWL_MAX_TID_COUNT;
bool is_agg = false;
int txq_id;
if (info->control.vif)
ctx = iwl_rxon_ctx_from_vif(info->control.vif);
......@@ -435,7 +447,27 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Copy MAC header from skb into command buffer */
memcpy(tx_cmd->hdr, hdr, hdr_len);
if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id, tid))
if (is_agg)
txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/*
* Send this frame after DTIM -- there's a special queue
* reserved for this for contexts that support AP mode.
*/
txq_id = ctx->mcast_queue;
/*
* The microcode will clear the more data
* bit in the last frame it transmits.
*/
hdr->frame_control |=
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
txq_id = IWL_AUX_QUEUE;
else
txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
if (iwl_trans_tx(trans(priv), skb, dev_cmd, txq_id))
goto drop_unlock_sta;
if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) &&
......@@ -464,11 +496,32 @@ drop_unlock_priv:
return -1;
}
static int iwlagn_alloc_agg_txq(struct iwl_priv *priv, int ac)
{
int q;
for (q = IWLAGN_FIRST_AMPDU_QUEUE;
q < cfg(priv)->base_params->num_of_queues; q++) {
if (!test_and_set_bit(q, priv->agg_q_alloc)) {
priv->queue_to_ac[q] = ac;
return q;
}
}
return -ENOSPC;
}
static void iwlagn_dealloc_agg_txq(struct iwl_priv *priv, int q)
{
clear_bit(q, priv->agg_q_alloc);
priv->queue_to_ac[q] = IWL_INVALID_AC;
}
int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid)
{
struct iwl_tid_data *tid_data;
int sta_id;
int sta_id, txq_id;
sta_id = iwl_sta_id(sta);
......@@ -480,6 +533,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
spin_lock_bh(&priv->sta_lock);
tid_data = &priv->tid_data[sta_id][tid];
txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
switch (priv->tid_data[sta_id][tid].agg.state) {
case IWL_EMPTYING_HW_QUEUE_ADDBA:
......@@ -504,9 +558,13 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
/* There are still packets for this RA / TID in the HW */
if (tid_data->agg.ssn != tid_data->next_reclaimed) {
if (!test_bit(txq_id, priv->agg_q_alloc)) {
IWL_DEBUG_TX_QUEUES(priv,
"stopping AGG on STA/TID %d/%d but hwq %d not used\n",
sta_id, tid, txq_id);
} else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
"next_recl = %d",
"next_recl = %d\n",
tid_data->agg.ssn,
tid_data->next_reclaimed);
priv->tid_data[sta_id][tid].agg.state =
......@@ -522,7 +580,10 @@ turn_off:
spin_unlock_bh(&priv->sta_lock);
iwl_trans_tx_agg_disable(trans(priv), sta_id, tid);
if (test_bit(txq_id, priv->agg_q_alloc)) {
iwl_trans_tx_agg_disable(trans(priv), txq_id);
iwlagn_dealloc_agg_txq(priv, txq_id);
}
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
......@@ -533,8 +594,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct iwl_tid_data *tid_data;
int sta_id;
int ret;
int sta_id, txq_id, ret;
IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n",
sta->addr, tid);
......@@ -552,23 +612,25 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
return -ENXIO;
}
txq_id = iwlagn_alloc_agg_txq(priv, tid_to_ac[tid]);
if (txq_id < 0) {
IWL_DEBUG_TX_QUEUES(priv,
"No free aggregation queue for %pM/%d\n",
sta->addr, tid);
return txq_id;
}
ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
if (ret)
return ret;
spin_lock_bh(&priv->sta_lock);
tid_data = &priv->tid_data[sta_id][tid];
tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
*ssn = tid_data->agg.ssn;
ret = iwl_trans_tx_agg_alloc(trans(priv), sta_id, tid);
if (ret) {
spin_unlock_bh(&priv->sta_lock);
return ret;
}
if (*ssn == tid_data->next_reclaimed) {
IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
tid_data->agg.ssn);
......@@ -581,7 +643,6 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
tid_data->next_reclaimed);
tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
}
spin_unlock_bh(&priv->sta_lock);
return ret;
......@@ -592,15 +653,20 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
{
struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
int q, fifo;
u16 ssn;
buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
spin_lock_bh(&priv->sta_lock);
ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn;
q = priv->tid_data[sta_priv->sta_id][tid].agg.txq_id;
spin_unlock_bh(&priv->sta_lock);
iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, sta_priv->sta_id, tid,
fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
iwl_trans_tx_agg_setup(trans(priv), q, fifo,
sta_priv->sta_id, tid,
buf_size, ssn);
/*
......@@ -666,7 +732,9 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
IWL_DEBUG_TX_QUEUES(priv,
"Can continue DELBA flow ssn = next_recl ="
" %d", tid_data->next_reclaimed);
iwl_trans_tx_agg_disable(trans(priv), sta_id, tid);
iwl_trans_tx_agg_disable(trans(priv),
tid_data->agg.txq_id);
iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
tid_data->agg.state = IWL_AGG_OFF;
ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
}
......@@ -1005,6 +1073,29 @@ static void iwl_check_abort_status(struct iwl_priv *priv,
}
}
static int iwl_reclaim(struct iwl_priv *priv, int sta_id, int tid,
int txq_id, int ssn, struct sk_buff_head *skbs)
{
if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
tid != IWL_TID_NON_QOS &&
txq_id != priv->tid_data[sta_id][tid].agg.txq_id)) {
/*
* FIXME: this is a uCode bug which need to be addressed,
* log the information and return for now.
* Since it is can possibly happen very often and in order
* not to fill the syslog, don't use IWL_ERR or IWL_WARN
*/
IWL_DEBUG_TX_QUEUES(priv,
"Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
txq_id, sta_id, tid,
priv->tid_data[sta_id][tid].agg.txq_id);
return 1;
}
iwl_trans_reclaim(trans(priv), txq_id, ssn, skbs);
return 0;
}
int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
......@@ -1064,8 +1155,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
}
/*we can free until ssn % q.n_bd not inclusive */
WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid,
txq_id, ssn, &skbs));
WARN_ON(iwl_reclaim(priv, sta_id, tid, txq_id, ssn, &skbs));
iwlagn_check_ratid_empty(priv, sta_id, tid);
freed = 0;
......@@ -1183,8 +1273,8 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
/* Release all TFDs before the SSN, i.e. all TFDs in front of
* block-ack window (we assume that they've been successfully
* transmitted ... if not, it's too late anyway). */
if (iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow,
ba_resp_scd_ssn, &reclaimed_skbs)) {
if (iwl_reclaim(priv, sta_id, tid, scd_flow,
ba_resp_scd_ssn, &reclaimed_skbs)) {
spin_unlock(&priv->sta_lock);
return 0;
}
......
......@@ -488,6 +488,93 @@ static void iwl_bg_tx_flush(struct work_struct *work)
iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
}
/*
* queue/FIFO/AC mapping definitions
*/
#define IWL_TX_FIFO_BK 0 /* shared */
#define IWL_TX_FIFO_BE 1
#define IWL_TX_FIFO_VI 2 /* shared */
#define IWL_TX_FIFO_VO 3
#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK
#define IWL_TX_FIFO_BE_IPAN 4
#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI
#define IWL_TX_FIFO_VO_IPAN 5
/* re-uses the VO FIFO, uCode will properly flush/schedule */
#define IWL_TX_FIFO_AUX 5
#define IWL_TX_FIFO_UNUSED -1
#define IWLAGN_CMD_FIFO_NUM 7
/*
* This queue number is required for proper operation
* because the ucode will stop/start the scheduler as
* required.
*/
#define IWL_IPAN_MCAST_QUEUE 8
static const u8 iwlagn_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_VO,
IWL_TX_FIFO_VI,
IWL_TX_FIFO_BE,
IWL_TX_FIFO_BK,
IWLAGN_CMD_FIFO_NUM,
};
static const u8 iwlagn_ipan_queue_to_tx_fifo[] = {
IWL_TX_FIFO_VO,
IWL_TX_FIFO_VI,
IWL_TX_FIFO_BE,
IWL_TX_FIFO_BK,
IWL_TX_FIFO_BK_IPAN,
IWL_TX_FIFO_BE_IPAN,
IWL_TX_FIFO_VI_IPAN,
IWL_TX_FIFO_VO_IPAN,
IWL_TX_FIFO_BE_IPAN,
IWLAGN_CMD_FIFO_NUM,
IWL_TX_FIFO_AUX,
};
static const u8 iwlagn_bss_ac_to_fifo[] = {
IWL_TX_FIFO_VO,
IWL_TX_FIFO_VI,
IWL_TX_FIFO_BE,
IWL_TX_FIFO_BK,
};
static const u8 iwlagn_bss_ac_to_queue[] = {
0, 1, 2, 3,
};
static const u8 iwlagn_pan_ac_to_fifo[] = {
IWL_TX_FIFO_VO_IPAN,
IWL_TX_FIFO_VI_IPAN,
IWL_TX_FIFO_BE_IPAN,
IWL_TX_FIFO_BK_IPAN,
};
static const u8 iwlagn_pan_ac_to_queue[] = {
7, 6, 5, 4,
};
static const u8 iwlagn_bss_queue_to_ac[] = {
IEEE80211_AC_VO,
IEEE80211_AC_VI,
IEEE80211_AC_BE,
IEEE80211_AC_BK,
};
static const u8 iwlagn_pan_queue_to_ac[] = {
IEEE80211_AC_VO,
IEEE80211_AC_VI,
IEEE80211_AC_BE,
IEEE80211_AC_BK,
IEEE80211_AC_BK,
IEEE80211_AC_BE,
IEEE80211_AC_VI,
IEEE80211_AC_VO,
};
static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
{
int i;
......@@ -520,6 +607,10 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue,
iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue));
memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo,
iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo));
priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
......@@ -542,6 +633,11 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue,
iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue));
memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo,
iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo));
priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
}
......@@ -869,6 +965,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv)
u8 bt_load;
u8 bt_status;
bool bt_is_sco;
int i;
lockdep_assert_held(&priv->mutex);
......@@ -898,6 +995,15 @@ void iwlagn_prepare_restart(struct iwl_priv *priv)
priv->bt_traffic_load = bt_load;
priv->bt_status = bt_status;
priv->bt_is_sco = bt_is_sco;
/* reset all queues */
for (i = 0; i < IEEE80211_NUM_ACS; i++)
atomic_set(&priv->ac_stop_count[i], 0);
for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++)
priv->queue_to_ac[i] = IWL_INVALID_AC;
memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc));
}
static void iwl_bg_restart(struct work_struct *data)
......@@ -1130,8 +1236,6 @@ static void iwl_set_hw_params(struct iwl_priv *priv)
if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
hw_params(priv).num_ampdu_queues =
cfg(priv)->base_params->num_of_ampdu_queues;
hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;
/* Device-specific setup */
......@@ -1192,6 +1296,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
STATISTICS_NOTIFICATION,
REPLY_TX,
};
const u8 *q_to_ac;
int n_q_to_ac;
int i;
/************************
* 1. Allocating HW data
......@@ -1228,9 +1335,19 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
trans_cfg.n_queue_to_fifo =
ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo);
q_to_ac = iwlagn_pan_queue_to_ac;
n_q_to_ac = ARRAY_SIZE(iwlagn_pan_queue_to_ac);
} else {
priv->sta_key_max_num = STA_KEY_MAX_NUM;
trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
trans_cfg.n_queue_to_fifo =
ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
q_to_ac = iwlagn_bss_queue_to_ac;
n_q_to_ac = ARRAY_SIZE(iwlagn_bss_queue_to_ac);
}
/* Configure transport layer */
......@@ -1319,6 +1436,11 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
priv->sta_key_max_num = STA_KEY_MAX_NUM;
trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
trans_cfg.n_queue_to_fifo =
ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
q_to_ac = iwlagn_bss_queue_to_ac;
n_q_to_ac = ARRAY_SIZE(iwlagn_bss_queue_to_ac);
/* Configure transport layer again*/
iwl_trans_configure(trans(priv), &trans_cfg);
......@@ -1327,6 +1449,18 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
/*******************
* 5. Setup priv
*******************/
for (i = 0; i < IEEE80211_NUM_ACS; i++)
atomic_set(&priv->ac_stop_count[i], 0);
for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
if (i < n_q_to_ac)
priv->queue_to_ac[i] = q_to_ac[i];
else
priv->queue_to_ac[i] = IWL_INVALID_AC;
}
WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] !=
IWLAGN_CMD_FIFO_NUM);
if (iwl_init_drv(priv))
goto out_free_eeprom;
......@@ -1439,17 +1573,39 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode)
cfg(priv)->lib->nic_config(priv);
}
static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
{
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
int ac = priv->queue_to_ac[queue];
if (WARN_ON_ONCE(ac == IWL_INVALID_AC))
return;
if (atomic_inc_return(&priv->ac_stop_count[ac]) > 1) {
IWL_DEBUG_TX_QUEUES(priv,
"queue %d (AC %d) already stopped\n",
queue, ac);
return;
}
set_bit(ac, &priv->transport_queue_stop);
ieee80211_stop_queue(priv->hw, ac);
}
static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
{
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
int ac = priv->queue_to_ac[queue];
if (WARN_ON_ONCE(ac == IWL_INVALID_AC))
return;
if (atomic_dec_return(&priv->ac_stop_count[ac]) > 0) {
IWL_DEBUG_TX_QUEUES(priv,
"queue %d (AC %d) already awake\n",
queue, ac);
return;
}
clear_bit(ac, &priv->transport_queue_stop);
......
......@@ -65,6 +65,13 @@
#include "iwl-dev.h"
/* The first 11 queues (0-10) are used otherwise */
#define IWLAGN_FIRST_AMPDU_QUEUE 11
/* AUX (TX during scan dwell) queue */
#define IWL_AUX_QUEUE 10
struct iwl_ucode_capabilities;
extern struct ieee80211_ops iwlagn_hw_ops;
......
......@@ -375,14 +375,19 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
i, station->sta.sta.addr,
station->sta.station_flags_msk);
pos += scnprintf(buf + pos, bufsz - pos,
"TID\tseq_num\trate_n_flags\n");
"TID seqno next_rclmd "
"rate_n_flags state txq\n");
for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
tid_data = &priv->tid_data[i][j];
pos += scnprintf(buf + pos, bufsz - pos,
"%d:\t%#x\t%#x",