aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-4965.c
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/iwlwifi/iwl-4965.c
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/iwlwifi/iwl-4965.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c224
1 files changed, 20 insertions, 204 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,