OSDN Git Service

iwlagn: fix aggregation queue scheduler setup
authorJohannes Berg <johannes.berg@intel.com>
Tue, 15 Mar 2011 18:33:03 +0000 (11:33 -0700)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Fri, 25 Mar 2011 13:57:40 +0000 (06:57 -0700)
iwlagn's hardware scheduler needs to be set up
with the right aggregation frame limit and
buffer sizes. To achieve this, we need to move
the hardware queue setup to when the session
becomes operational.

Tested-by: Daniel Halperin <dhalperi@cs.washington.edu>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-dev.h

index 23e5667..fb63a03 100644 (file)
@@ -222,13 +222,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
                       scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
 }
 
-static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
-                                int tx_fifo, int sta_id, int tid, u16 ssn_idx)
+static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid)
 {
-       unsigned long flags;
-       u16 ra_tid;
-       int ret;
-
        if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
            (IWLAGN_FIRST_AMPDU_QUEUE +
                priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
@@ -240,12 +235,33 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
                return -EINVAL;
        }
 
-       ra_tid = BUILD_RAxTID(sta_id, tid);
-
        /* Modify device's station table to Tx this TID */
-       ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
-       if (ret)
-               return ret;
+       return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+}
+
+void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
+                               struct ieee80211_sta *sta,
+                               int tid, int frame_limit)
+{
+       int sta_id, tx_fifo, txq_id, ssn_idx;
+       u16 ra_tid;
+       unsigned long flags;
+       struct iwl_tid_data *tid_data;
+
+       sta_id = iwl_sta_id(sta);
+       if (WARN_ON(sta_id == IWL_INVALID_STATION))
+               return;
+       if (WARN_ON(tid >= MAX_TID_COUNT))
+               return;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       tid_data = &priv->stations[sta_id].tid[tid];
+       ssn_idx = SEQ_TO_SN(tid_data->seq_number);
+       txq_id = tid_data->agg.txq_id;
+       tx_fifo = tid_data->agg.tx_fifo;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       ra_tid = BUILD_RAxTID(sta_id, tid);
 
        spin_lock_irqsave(&priv->lock, flags);
 
@@ -271,10 +287,10 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        iwl_write_targ_mem(priv, priv->scd_base_addr +
                        IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
                        sizeof(u32),
-                       ((SCD_WIN_SIZE <<
+                       ((frame_limit <<
                        IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
                        IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                       ((SCD_FRAME_LIMIT <<
+                       ((frame_limit <<
                        IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
                        IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
 
@@ -284,8 +300,6 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
        iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
 
        spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
 }
 
 static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
@@ -1034,10 +1048,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
        tid_data = &priv->stations[sta_id].tid[tid];
        *ssn = SEQ_TO_SN(tid_data->seq_number);
        tid_data->agg.txq_id = txq_id;
+       tid_data->agg.tx_fifo = tx_fifo;
        iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       ret = iwlagn_txq_agg_enable(priv, txq_id, tx_fifo, sta_id, tid, *ssn);
+       ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid);
        if (ret)
                return ret;
 
index b57fbbf..8fdd174 100644 (file)
@@ -3345,6 +3345,10 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                }
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
+               buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+               iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size);
+
                /*
                 * If the limit is 0, then it wasn't initialised yet,
                 * use the default. We can do that since we take the
index 8d918ea..4f7c9ce 100644 (file)
@@ -202,6 +202,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta, u16 tid);
+void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
+                               struct ieee80211_sta *sta,
+                               int tid, int frame_limit);
 int iwlagn_txq_check_empty(struct iwl_priv *priv,
                           int sta_id, u8 tid, int txq_id);
 void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
index 68b953f..a5d438d 100644 (file)
@@ -416,6 +416,7 @@ struct iwl_ht_agg {
 #define IWL_EMPTYING_HW_QUEUE_ADDBA 2
 #define IWL_EMPTYING_HW_QUEUE_DELBA 3
        u8 state;
+       u8 tx_fifo;
 };