aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2008-05-29 04:35:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-03 15:00:25 -0400
commit30e553e3ea3572bee3118fcde36e043c0cb2174c (patch)
tree5cb6bd4634e4dba343b69df0b1971ff275ec25fa /drivers/net/wireless
parent5083e56326208f9a1d4e597529912004968c77d7 (diff)
iwlwifi: move aggregation code to iwl-tx.c
This patch moves aggregation action code to iwl-tx.c in iwlcore. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c224
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c190
5 files changed, 228 insertions, 210 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index b719d19361ac..556e59ef70e1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -55,30 +55,6 @@ static struct iwl_mod_params iwl4965_mod_params = {
55 /* the rest are 0 by default */ 55 /* the rest are 0 by default */
56}; 56};
57 57
58#ifdef CONFIG_IWL4965_HT
59
60static const u16 default_tid_to_tx_fifo[] = {
61 IWL_TX_FIFO_AC1,
62 IWL_TX_FIFO_AC0,
63 IWL_TX_FIFO_AC0,
64 IWL_TX_FIFO_AC1,
65 IWL_TX_FIFO_AC2,
66 IWL_TX_FIFO_AC2,
67 IWL_TX_FIFO_AC3,
68 IWL_TX_FIFO_AC3,
69 IWL_TX_FIFO_NONE,
70 IWL_TX_FIFO_NONE,
71 IWL_TX_FIFO_NONE,
72 IWL_TX_FIFO_NONE,
73 IWL_TX_FIFO_NONE,
74 IWL_TX_FIFO_NONE,
75 IWL_TX_FIFO_NONE,
76 IWL_TX_FIFO_NONE,
77 IWL_TX_FIFO_AC3
78};
79
80#endif /*CONFIG_IWL4965_HT */
81
82/* check contents of special bootstrap uCode SRAM */ 58/* check contents of special bootstrap uCode SRAM */
83static int iwl4965_verify_bsm(struct iwl_priv *priv) 59static int iwl4965_verify_bsm(struct iwl_priv *priv)
84{ 60{
@@ -2986,8 +2962,8 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv,
2986 * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID 2962 * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
2987 * priv->lock must be held by the caller 2963 * priv->lock must be held by the caller
2988 */ 2964 */
2989static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, 2965static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
2990 u16 ssn_idx, u8 tx_fifo) 2966 u16 ssn_idx, u8 tx_fifo)
2991{ 2967{
2992 int ret = 0; 2968 int ret = 0;
2993 2969
@@ -3019,39 +2995,6 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
3019 return 0; 2995 return 0;
3020} 2996}
3021 2997
3022int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
3023 u8 tid, int txq_id)
3024{
3025 struct iwl_queue *q = &priv->txq[txq_id].q;
3026 u8 *addr = priv->stations[sta_id].sta.sta.addr;
3027 struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
3028
3029 switch (priv->stations[sta_id].tid[tid].agg.state) {
3030 case IWL_EMPTYING_HW_QUEUE_DELBA:
3031 /* We are reclaiming the last packet of the */
3032 /* aggregated HW queue */
3033 if (txq_id == tid_data->agg.txq_id &&
3034 q->read_ptr == q->write_ptr) {
3035 u16 ssn = SEQ_TO_SN(tid_data->seq_number);
3036 int tx_fifo = default_tid_to_tx_fifo[tid];
3037 IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
3038 iwl4965_tx_queue_agg_disable(priv, txq_id,
3039 ssn, tx_fifo);
3040 tid_data->agg.state = IWL_AGG_OFF;
3041 ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
3042 }
3043 break;
3044 case IWL_EMPTYING_HW_QUEUE_ADDBA:
3045 /* We are reclaiming the last packet of the queue */
3046 if (tid_data->tfds_in_queue == 0) {
3047 IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n");
3048 tid_data->agg.state = IWL_AGG_ON;
3049 ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
3050 }
3051 break;
3052 }
3053 return 0;
3054}
3055 2998
3056/** 2999/**
3057 * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA 3000 * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
@@ -3122,8 +3065,9 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
3122 priv->mac80211_registered && 3065 priv->mac80211_registered &&
3123 agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) 3066 agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
3124 ieee80211_wake_queue(priv->hw, ampdu_q); 3067 ieee80211_wake_queue(priv->hw, ampdu_q);
3125 iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id, 3068
3126 ba_resp->tid, scd_flow); 3069 iwl_txq_check_empty(priv, ba_resp->sta_id,
3070 ba_resp->tid, scd_flow);
3127 } 3071 }
3128} 3072}
3129 3073
@@ -3137,7 +3081,7 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
3137 u32 tbl_dw; 3081 u32 tbl_dw;
3138 u16 scd_q2ratid; 3082 u16 scd_q2ratid;
3139 3083
3140 scd_q2ratid = ra_tid & IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK; 3084 scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
3141 3085
3142 tbl_dw_addr = priv->scd_base_addr + 3086 tbl_dw_addr = priv->scd_base_addr +
3143 IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); 3087 IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
@@ -3161,12 +3105,11 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
3161 * NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID, 3105 * NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID,
3162 * i.e. it must be one of the higher queues used for aggregation 3106 * i.e. it must be one of the higher queues used for aggregation
3163 */ 3107 */
3164static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, 3108static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
3165 int tx_fifo, int sta_id, int tid, 3109 int tx_fifo, int sta_id, int tid, u16 ssn_idx)
3166 u16 ssn_idx)
3167{ 3110{
3168 unsigned long flags; 3111 unsigned long flags;
3169 int rc; 3112 int ret;
3170 u16 ra_tid; 3113 u16 ra_tid;
3171 3114
3172 if (IWL_BACK_QUEUE_FIRST_ID > txq_id) 3115 if (IWL_BACK_QUEUE_FIRST_ID > txq_id)
@@ -3179,10 +3122,10 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
3179 iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); 3122 iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
3180 3123
3181 spin_lock_irqsave(&priv->lock, flags); 3124 spin_lock_irqsave(&priv->lock, flags);
3182 rc = iwl_grab_nic_access(priv); 3125 ret = iwl_grab_nic_access(priv);
3183 if (rc) { 3126 if (ret) {
3184 spin_unlock_irqrestore(&priv->lock, flags); 3127 spin_unlock_irqrestore(&priv->lock, flags);
3185 return rc; 3128 return ret;
3186 } 3129 }
3187 3130
3188 /* Stop this Tx queue before configuring it */ 3131 /* Stop this Tx queue before configuring it */
@@ -3269,137 +3212,6 @@ static int iwl4965_rx_agg_stop(struct iwl_priv *priv,
3269 CMD_ASYNC); 3212 CMD_ASYNC);
3270} 3213}
3271 3214
3272/*
3273 * Find first available (lowest unused) Tx Queue, mark it "active".
3274 * Called only when finding queue for aggregation.
3275 * Should never return anything < 7, because they should already
3276 * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
3277 */
3278static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv)
3279{
3280 int txq_id;
3281
3282 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
3283 if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
3284 return txq_id;
3285 return -1;
3286}
3287
3288static int iwl4965_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra,
3289 u16 tid, u16 *start_seq_num)
3290{
3291 struct iwl_priv *priv = hw->priv;
3292 int sta_id;
3293 int tx_fifo;
3294 int txq_id;
3295 int ssn = -1;
3296 int ret = 0;
3297 unsigned long flags;
3298 struct iwl_tid_data *tid_data;
3299 DECLARE_MAC_BUF(mac);
3300
3301 if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
3302 tx_fifo = default_tid_to_tx_fifo[tid];
3303 else
3304 return -EINVAL;
3305
3306 IWL_WARNING("%s on ra = %s tid = %d\n",
3307 __func__, print_mac(mac, ra), tid);
3308
3309 sta_id = iwl_find_station(priv, ra);
3310 if (sta_id == IWL_INVALID_STATION)
3311 return -ENXIO;
3312
3313 if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
3314 IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n");
3315 return -ENXIO;
3316 }
3317
3318 txq_id = iwl4965_txq_ctx_activate_free(priv);
3319 if (txq_id == -1)
3320 return -ENXIO;
3321
3322 spin_lock_irqsave(&priv->sta_lock, flags);
3323 tid_data = &priv->stations[sta_id].tid[tid];
3324 ssn = SEQ_TO_SN(tid_data->seq_number);
3325 tid_data->agg.txq_id = txq_id;
3326 spin_unlock_irqrestore(&priv->sta_lock, flags);
3327
3328 *start_seq_num = ssn;
3329 ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
3330 sta_id, tid, ssn);
3331 if (ret)
3332 return ret;
3333
3334 ret = 0;
3335 if (tid_data->tfds_in_queue == 0) {
3336 printk(KERN_ERR "HW queue is empty\n");
3337 tid_data->agg.state = IWL_AGG_ON;
3338 ieee80211_start_tx_ba_cb_irqsafe(hw, ra, tid);
3339 } else {
3340 IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
3341 tid_data->tfds_in_queue);
3342 tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
3343 }
3344 return ret;
3345}
3346
3347static int iwl4965_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid)
3348{
3349 struct iwl_priv *priv = hw->priv;
3350 int tx_fifo_id, txq_id, sta_id, ssn = -1;
3351 struct iwl_tid_data *tid_data;
3352 int ret, write_ptr, read_ptr;
3353 unsigned long flags;
3354 DECLARE_MAC_BUF(mac);
3355
3356 if (!ra) {
3357 IWL_ERROR("ra = NULL\n");
3358 return -EINVAL;
3359 }
3360
3361 if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
3362 tx_fifo_id = default_tid_to_tx_fifo[tid];
3363 else
3364 return -EINVAL;
3365
3366 sta_id = iwl_find_station(priv, ra);
3367
3368 if (sta_id == IWL_INVALID_STATION)
3369 return -ENXIO;
3370
3371 if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
3372 IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n");
3373
3374 tid_data = &priv->stations[sta_id].tid[tid];
3375 ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
3376 txq_id = tid_data->agg.txq_id;
3377 write_ptr = priv->txq[txq_id].q.write_ptr;
3378 read_ptr = priv->txq[txq_id].q.read_ptr;
3379
3380 /* The queue is not empty */
3381 if (write_ptr != read_ptr) {
3382 IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n");
3383 priv->stations[sta_id].tid[tid].agg.state =
3384 IWL_EMPTYING_HW_QUEUE_DELBA;
3385 return 0;
3386 }
3387
3388 IWL_DEBUG_HT("HW queue is empty\n");
3389 priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
3390
3391 spin_lock_irqsave(&priv->lock, flags);
3392 ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
3393 spin_unlock_irqrestore(&priv->lock, flags);
3394
3395 if (ret)
3396 return ret;
3397
3398 ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
3399
3400 return 0;
3401}
3402
3403int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, 3215int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
3404 enum ieee80211_ampdu_mlme_action action, 3216 enum ieee80211_ampdu_mlme_action action,
3405 const u8 *addr, u16 tid, u16 *ssn) 3217 const u8 *addr, u16 tid, u16 *ssn)
@@ -3419,10 +3231,10 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
3419 return iwl4965_rx_agg_stop(priv, addr, tid); 3231 return iwl4965_rx_agg_stop(priv, addr, tid);
3420 case IEEE80211_AMPDU_TX_START: 3232 case IEEE80211_AMPDU_TX_START:
3421 IWL_DEBUG_HT("start Tx\n"); 3233 IWL_DEBUG_HT("start Tx\n");
3422 return iwl4965_tx_agg_start(hw, addr, tid, ssn); 3234 return iwl_tx_agg_start(priv, addr, tid, ssn);
3423 case IEEE80211_AMPDU_TX_STOP: 3235 case IEEE80211_AMPDU_TX_STOP:
3424 IWL_DEBUG_HT("stop Tx\n"); 3236 IWL_DEBUG_HT("stop Tx\n");
3425 return iwl4965_tx_agg_stop(hw, addr, tid); 3237 return iwl_tx_agg_stop(priv, addr, tid);
3426 default: 3238 default:
3427 IWL_DEBUG_HT("unknown\n"); 3239 IWL_DEBUG_HT("unknown\n");
3428 return -EINVAL; 3240 return -EINVAL;
@@ -3670,7 +3482,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
3670 else 3482 else
3671 ieee80211_wake_queue(priv->hw, ampdu_q); 3483 ieee80211_wake_queue(priv->hw, ampdu_q);
3672 } 3484 }
3673 iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); 3485 iwl_txq_check_empty(priv, sta_id, tid, txq_id);
3674 } 3486 }
3675 } else { 3487 } else {
3676#endif /* CONFIG_IWL4965_HT */ 3488#endif /* CONFIG_IWL4965_HT */
@@ -3695,7 +3507,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
3695 (txq_id >= 0) && priv->mac80211_registered) 3507 (txq_id >= 0) && priv->mac80211_registered)
3696 ieee80211_wake_queue(priv->hw, txq_id); 3508 ieee80211_wake_queue(priv->hw, txq_id);
3697 if (tid != MAX_TID_COUNT) 3509 if (tid != MAX_TID_COUNT)
3698 iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); 3510 iwl_txq_check_empty(priv, sta_id, tid, txq_id);
3699 } 3511 }
3700 } 3512 }
3701#endif /* CONFIG_IWL4965_HT */ 3513#endif /* CONFIG_IWL4965_HT */
@@ -3761,6 +3573,10 @@ static struct iwl_lib_ops iwl4965_lib = {
3761 .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, 3573 .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx,
3762 .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, 3574 .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
3763 .txq_set_sched = iwl4965_txq_set_sched, 3575 .txq_set_sched = iwl4965_txq_set_sched,
3576#ifdef CONFIG_IWL4965_HT
3577 .txq_agg_enable = iwl4965_txq_agg_enable,
3578 .txq_agg_disable = iwl4965_txq_agg_disable,
3579#endif
3764 .rx_handler_setup = iwl4965_rx_handler_setup, 3580 .rx_handler_setup = iwl4965_rx_handler_setup,
3765 .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, 3581 .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
3766 .alive_notify = iwl4965_alive_notify, 3582 .alive_notify = iwl4965_alive_notify,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 217c6a9596cd..9ef4468327af 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1193,7 +1193,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
1193 else 1193 else
1194 ieee80211_wake_queue(priv->hw, ampdu_q); 1194 ieee80211_wake_queue(priv->hw, ampdu_q);
1195 } 1195 }
1196 iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); 1196 iwl_txq_check_empty(priv, sta_id, tid, txq_id);
1197 } 1197 }
1198 } else { 1198 } else {
1199#endif /* CONFIG_IWL4965_HT */ 1199#endif /* CONFIG_IWL4965_HT */
@@ -1218,7 +1218,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
1218 (txq_id >= 0) && priv->mac80211_registered) 1218 (txq_id >= 0) && priv->mac80211_registered)
1219 ieee80211_wake_queue(priv->hw, txq_id); 1219 ieee80211_wake_queue(priv->hw, txq_id);
1220 if (tid != MAX_TID_COUNT) 1220 if (tid != MAX_TID_COUNT)
1221 iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); 1221 iwl_txq_check_empty(priv, sta_id, tid, txq_id);
1222 } 1222 }
1223 } 1223 }
1224#endif /* CONFIG_IWL4965_HT */ 1224#endif /* CONFIG_IWL4965_HT */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 1941a9184aa2..004c68444006 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -104,15 +104,22 @@ struct iwl_lib_ops {
104 int (*alloc_shared_mem)(struct iwl_priv *priv); 104 int (*alloc_shared_mem)(struct iwl_priv *priv);
105 void (*free_shared_mem)(struct iwl_priv *priv); 105 void (*free_shared_mem)(struct iwl_priv *priv);
106 int (*shared_mem_rx_idx)(struct iwl_priv *priv); 106 int (*shared_mem_rx_idx)(struct iwl_priv *priv);
107 /* Handling TX */
107 void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, 108 void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
108 struct iwl_tx_queue *txq, 109 struct iwl_tx_queue *txq,
109 u16 byte_cnt); 110 u16 byte_cnt);
110 void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, 111 void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv,
111 struct iwl_tx_queue *txq); 112 struct iwl_tx_queue *txq);
112 void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); 113 void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
114#ifdef CONFIG_IWL4965_HT
115 /* aggregations */
116 int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo,
117 int sta_id, int tid, u16 ssn_idx);
118 int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx,
119 u8 tx_fifo);
120#endif /* CONFIG_IWL4965_HT */
113 /* setup Rx handler */ 121 /* setup Rx handler */
114 void (*rx_handler_setup)(struct iwl_priv *priv); 122 void (*rx_handler_setup)(struct iwl_priv *priv);
115 /* nic Tx fifo handling */
116 /* alive notification after init uCode load */ 123 /* alive notification after init uCode load */
117 void (*init_alive_start)(struct iwl_priv *priv); 124 void (*init_alive_start)(struct iwl_priv *priv);
118 /* alive notification */ 125 /* alive notification */
@@ -226,6 +233,11 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
226int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, 233int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
227 dma_addr_t addr, u16 len); 234 dma_addr_t addr, u16 len);
228int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); 235int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
236#ifdef CONFIG_IWL4965_HT
237int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
238int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
239int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
240#endif
229 241
230/***************************************************** 242/*****************************************************
231 * S e n d i n g H o s t C o m m a n d s * 243 * S e n d i n g H o s t C o m m a n d s *
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 15cb7ff4f7aa..70d9c7568b98 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -507,9 +507,9 @@
507#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ 507#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
508 ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) 508 ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
509 509
510#define IWL49_SCD_TXFIFO_POS_TID (0) 510#define IWL_SCD_TXFIFO_POS_TID (0)
511#define IWL49_SCD_TXFIFO_POS_RA (4) 511#define IWL_SCD_TXFIFO_POS_RA (4)
512#define IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) 512#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
513 513
514/* 5000 SCD */ 514/* 5000 SCD */
515#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0) 515#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0)
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 224bcec21e5b..cfe6f4b233dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -36,6 +36,32 @@
36#include "iwl-io.h" 36#include "iwl-io.h"
37#include "iwl-helpers.h" 37#include "iwl-helpers.h"
38 38
39#ifdef CONFIG_IWL4965_HT
40
41static const u16 default_tid_to_tx_fifo[] = {
42 IWL_TX_FIFO_AC1,
43 IWL_TX_FIFO_AC0,
44 IWL_TX_FIFO_AC0,
45 IWL_TX_FIFO_AC1,
46 IWL_TX_FIFO_AC2,
47 IWL_TX_FIFO_AC2,
48 IWL_TX_FIFO_AC3,
49 IWL_TX_FIFO_AC3,
50 IWL_TX_FIFO_NONE,
51 IWL_TX_FIFO_NONE,
52 IWL_TX_FIFO_NONE,
53 IWL_TX_FIFO_NONE,
54 IWL_TX_FIFO_NONE,
55 IWL_TX_FIFO_NONE,
56 IWL_TX_FIFO_NONE,
57 IWL_TX_FIFO_NONE,
58 IWL_TX_FIFO_AC3
59};
60
61#endif /*CONFIG_IWL4965_HT */
62
63
64
39/** 65/**
40 * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] 66 * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
41 * 67 *
@@ -1171,6 +1197,170 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1171EXPORT_SYMBOL(iwl_tx_cmd_complete); 1197EXPORT_SYMBOL(iwl_tx_cmd_complete);
1172 1198
1173 1199
1200#ifdef CONFIG_IWL4965_HT
1201/*
1202 * Find first available (lowest unused) Tx Queue, mark it "active".
1203 * Called only when finding queue for aggregation.
1204 * Should never return anything < 7, because they should already
1205 * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
1206 */
1207static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
1208{
1209 int txq_id;
1210
1211 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
1212 if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
1213 return txq_id;
1214 return -1;
1215}
1216
1217int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
1218{
1219 int sta_id;
1220 int tx_fifo;
1221 int txq_id;
1222 int ret;
1223 unsigned long flags;
1224 struct iwl_tid_data *tid_data;
1225 DECLARE_MAC_BUF(mac);
1226
1227 if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
1228 tx_fifo = default_tid_to_tx_fifo[tid];
1229 else
1230 return -EINVAL;
1231
1232 IWL_WARNING("%s on ra = %s tid = %d\n",
1233 __func__, print_mac(mac, ra), tid);
1234
1235 sta_id = iwl_find_station(priv, ra);
1236 if (sta_id == IWL_INVALID_STATION)
1237 return -ENXIO;
1238
1239 if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
1240 IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n");
1241 return -ENXIO;
1242 }
1243
1244 txq_id = iwl_txq_ctx_activate_free(priv);
1245 if (txq_id == -1)
1246 return -ENXIO;
1247
1248 spin_lock_irqsave(&priv->sta_lock, flags);
1249 tid_data = &priv->stations[sta_id].tid[tid];
1250 *ssn = SEQ_TO_SN(tid_data->seq_number);
1251 tid_data->agg.txq_id = txq_id;
1252 spin_unlock_irqrestore(&priv->sta_lock, flags);
1253
1254 ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
1255 sta_id, tid, *ssn);
1256 if (ret)
1257 return ret;
1258
1259 if (tid_data->tfds_in_queue == 0) {
1260 printk(KERN_ERR "HW queue is empty\n");
1261 tid_data->agg.state = IWL_AGG_ON;
1262 ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid);
1263 } else {
1264 IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
1265 tid_data->tfds_in_queue);
1266 tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
1267 }
1268 return ret;
1269}
1270EXPORT_SYMBOL(iwl_tx_agg_start);
1271
1272int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
1273{
1274 int tx_fifo_id, txq_id, sta_id, ssn = -1;
1275 struct iwl_tid_data *tid_data;
1276 int ret, write_ptr, read_ptr;
1277 unsigned long flags;
1278 DECLARE_MAC_BUF(mac);
1279
1280 if (!ra) {
1281 IWL_ERROR("ra = NULL\n");
1282 return -EINVAL;
1283 }
1284
1285 if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
1286 tx_fifo_id = default_tid_to_tx_fifo[tid];
1287 else
1288 return -EINVAL;
1289
1290 sta_id = iwl_find_station(priv, ra);
1291
1292 if (sta_id == IWL_INVALID_STATION)
1293 return -ENXIO;
1294
1295 if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
1296 IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n");
1297
1298 tid_data = &priv->stations[sta_id].tid[tid];
1299 ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
1300 txq_id = tid_data->agg.txq_id;
1301 write_ptr = priv->txq[txq_id].q.write_ptr;
1302 read_ptr = priv->txq[txq_id].q.read_ptr;
1303
1304 /* The queue is not empty */
1305 if (write_ptr != read_ptr) {
1306 IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n");
1307 priv->stations[sta_id].tid[tid].agg.state =
1308 IWL_EMPTYING_HW_QUEUE_DELBA;
1309 return 0;
1310 }
1311
1312 IWL_DEBUG_HT("HW queue is empty\n");
1313 priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
1314
1315 spin_lock_irqsave(&priv->lock, flags);
1316 ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
1317 tx_fifo_id);
1318 spin_unlock_irqrestore(&priv->lock, flags);
1319
1320 if (ret)
1321 return ret;
1322
1323 ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
1324
1325 return 0;
1326}
1327EXPORT_SYMBOL(iwl_tx_agg_stop);
1328
1329int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
1330{
1331 struct iwl_queue *q = &priv->txq[txq_id].q;
1332 u8 *addr = priv->stations[sta_id].sta.sta.addr;
1333 struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
1334
1335 switch (priv->stations[sta_id].tid[tid].agg.state) {
1336 case IWL_EMPTYING_HW_QUEUE_DELBA:
1337 /* We are reclaiming the last packet of the */
1338 /* aggregated HW queue */
1339 if (txq_id == tid_data->agg.txq_id &&
1340 q->read_ptr == q->write_ptr) {
1341 u16 ssn = SEQ_TO_SN(tid_data->seq_number);
1342 int tx_fifo = default_tid_to_tx_fifo[tid];
1343 IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
1344 priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
1345 ssn, tx_fifo);
1346 tid_data->agg.state = IWL_AGG_OFF;
1347 ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
1348 }
1349 break;
1350 case IWL_EMPTYING_HW_QUEUE_ADDBA:
1351 /* We are reclaiming the last packet of the queue */
1352 if (tid_data->tfds_in_queue == 0) {
1353 IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n");
1354 tid_data->agg.state = IWL_AGG_ON;
1355 ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
1356 }
1357 break;
1358 }
1359 return 0;
1360}
1361EXPORT_SYMBOL(iwl_txq_check_empty);
1362#endif /* CONFIG_IWL4965_HT */
1363
1174#ifdef CONFIG_IWLWIF_DEBUG 1364#ifdef CONFIG_IWLWIF_DEBUG
1175#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x 1365#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
1176 1366