diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2008-05-29 04:35:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-03 15:00:25 -0400 |
commit | 30e553e3ea3572bee3118fcde36e043c0cb2174c (patch) | |
tree | 5cb6bd4634e4dba343b69df0b1971ff275ec25fa /drivers/net/wireless/iwlwifi/iwl-4965.c | |
parent | 5083e56326208f9a1d4e597529912004968c77d7 (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.c | 224 |
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 | |||
60 | static 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 */ |
83 | static int iwl4965_verify_bsm(struct iwl_priv *priv) | 59 | static 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 | */ |
2989 | static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, | 2965 | static 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 | ||
3022 | int 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 | */ |
3164 | static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, | 3108 | static 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 | */ | ||
3278 | static 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 | |||
3288 | static 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 | |||
3347 | static 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 | |||
3403 | int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, | 3215 | int 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, |