Skip to content

Commit

Permalink
iwlwifi: move queue mapping out of transport
Browse files Browse the repository at this point in the history
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: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Apr 9, 2012
1 parent e561038 commit 9eae88f
Show file tree
Hide file tree
Showing 17 changed files with 419 additions and 575 deletions.
1 change: 0 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl-1000.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 0 additions & 2 deletions drivers/net/wireless/iwlwifi/iwl-2000.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl-5000.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 0 additions & 3 deletions drivers/net/wireless/iwlwifi/iwl-6000.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
3 changes: 0 additions & 3 deletions drivers/net/wireless/iwlwifi/iwl-agn-hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
132 changes: 111 additions & 21 deletions drivers/net/wireless/iwlwifi/iwl-agn-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) &&
Expand Down Expand Up @@ -464,11 +496,32 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
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);

Expand All @@ -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:
Expand All @@ -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 =
Expand All @@ -522,7 +580,10 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,

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);

Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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);

/*
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit 9eae88f

Please sign in to comment.