diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2008-10-24 02:48:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-10-31 19:02:23 -0400 |
commit | 3fd07a1e5aba89d4be3696c46cb7297f1873195a (patch) | |
tree | 48a6c3b68e30136af93c48d35bd1ce08a9237c4d /drivers/net/wireless/iwlwifi/iwl-5000.c | |
parent | 8b30b1fe368ab03049435884c11c5c50e4c4ef0b (diff) |
iwlwifi: refactor TX response flow
This patch utilize 5000 new TX response command
which contains all necessary information and avoids
back referencing to the original TX frame.
It also change handling of software queue tracking
4965 flow is aligned with changes as much as possible.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Reviewed-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-5000.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 81 |
1 files changed, 34 insertions, 47 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ad566ef233b8..a8c8c858e209 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -683,7 +683,7 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, | |||
683 | int tx_fifo_id, int scd_retry) | 683 | int tx_fifo_id, int scd_retry) |
684 | { | 684 | { |
685 | int txq_id = txq->q.id; | 685 | int txq_id = txq->q.id; |
686 | int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; | 686 | int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; |
687 | 687 | ||
688 | iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), | 688 | iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), |
689 | (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | | 689 | (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | |
@@ -801,7 +801,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) | |||
801 | } | 801 | } |
802 | 802 | ||
803 | priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; | 803 | priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; |
804 | priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE; | ||
805 | priv->hw_params.max_stations = IWL5000_STATION_COUNT; | 804 | priv->hw_params.max_stations = IWL5000_STATION_COUNT; |
806 | priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; | 805 | priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; |
807 | priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; | 806 | priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; |
@@ -1159,7 +1158,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, | |||
1159 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 1158 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
1160 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; | 1159 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; |
1161 | info->flags |= iwl_is_tx_success(status)? | 1160 | info->flags |= iwl_is_tx_success(status)? |
1162 | IEEE80211_TX_STAT_ACK : 0; | 1161 | IEEE80211_TX_STAT_ACK : 0; |
1163 | iwl_hwrate_to_tx_control(priv, rate_n_flags, info); | 1162 | iwl_hwrate_to_tx_control(priv, rate_n_flags, info); |
1164 | 1163 | ||
1165 | /* FIXME: code repetition end */ | 1164 | /* FIXME: code repetition end */ |
@@ -1245,9 +1244,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, | |||
1245 | struct ieee80211_tx_info *info; | 1244 | struct ieee80211_tx_info *info; |
1246 | struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | 1245 | struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; |
1247 | u32 status = le16_to_cpu(tx_resp->status.status); | 1246 | u32 status = le16_to_cpu(tx_resp->status.status); |
1248 | int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; | 1247 | int tid; |
1249 | struct ieee80211_hdr *hdr; | 1248 | int sta_id; |
1250 | u8 *qc = NULL; | 1249 | int freed; |
1251 | 1250 | ||
1252 | if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { | 1251 | if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { |
1253 | IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " | 1252 | IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " |
@@ -1260,25 +1259,13 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, | |||
1260 | info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); | 1259 | info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); |
1261 | memset(&info->status, 0, sizeof(info->status)); | 1260 | memset(&info->status, 0, sizeof(info->status)); |
1262 | 1261 | ||
1263 | hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); | 1262 | tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS; |
1264 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 1263 | sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS; |
1265 | qc = ieee80211_get_qos_ctl(hdr); | ||
1266 | tid = qc[0] & 0xf; | ||
1267 | } | ||
1268 | |||
1269 | sta_id = iwl_get_ra_sta_id(priv, hdr); | ||
1270 | if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { | ||
1271 | IWL_ERROR("Station not known\n"); | ||
1272 | return; | ||
1273 | } | ||
1274 | 1264 | ||
1275 | if (txq->sched_retry) { | 1265 | if (txq->sched_retry) { |
1276 | const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); | 1266 | const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); |
1277 | struct iwl_ht_agg *agg = NULL; | 1267 | struct iwl_ht_agg *agg = NULL; |
1278 | 1268 | ||
1279 | if (!qc) | ||
1280 | return; | ||
1281 | |||
1282 | agg = &priv->stations[sta_id].tid[tid].agg; | 1269 | agg = &priv->stations[sta_id].tid[tid].agg; |
1283 | 1270 | ||
1284 | iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); | 1271 | iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); |
@@ -1288,53 +1275,53 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, | |||
1288 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | 1275 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; |
1289 | 1276 | ||
1290 | if (txq->q.read_ptr != (scd_ssn & 0xff)) { | 1277 | if (txq->q.read_ptr != (scd_ssn & 0xff)) { |
1291 | int freed, ampdu_q; | ||
1292 | index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); | 1278 | index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); |
1293 | IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " | 1279 | IWL_DEBUG_TX_REPLY("Retry scheduler reclaim " |
1294 | "%d index %d\n", scd_ssn , index); | 1280 | "scd_ssn=%d idx=%d txq=%d swq=%d\n", |
1281 | scd_ssn , index, txq_id, txq->swq_id); | ||
1282 | |||
1295 | freed = iwl_tx_queue_reclaim(priv, txq_id, index); | 1283 | freed = iwl_tx_queue_reclaim(priv, txq_id, index); |
1296 | priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; | 1284 | priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; |
1297 | 1285 | ||
1298 | if (iwl_queue_space(&txq->q) > txq->q.low_mark && | 1286 | if (priv->mac80211_registered && |
1299 | txq_id >= 0 && priv->mac80211_registered && | 1287 | (iwl_queue_space(&txq->q) > txq->q.low_mark) && |
1300 | agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { | 1288 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { |
1301 | /* calculate mac80211 ampdu sw queue to wake */ | ||
1302 | ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE + | ||
1303 | priv->hw->queues; | ||
1304 | if (agg->state == IWL_AGG_OFF) | 1289 | if (agg->state == IWL_AGG_OFF) |
1305 | ieee80211_wake_queue(priv->hw, txq_id); | 1290 | ieee80211_wake_queue(priv->hw, txq_id); |
1306 | else | 1291 | else |
1307 | ieee80211_wake_queue(priv->hw, ampdu_q); | 1292 | ieee80211_wake_queue(priv->hw, |
1293 | txq->swq_id); | ||
1308 | } | 1294 | } |
1309 | iwl_txq_check_empty(priv, sta_id, tid, txq_id); | ||
1310 | } | 1295 | } |
1311 | } else { | 1296 | } else { |
1297 | BUG_ON(txq_id != txq->swq_id); | ||
1298 | |||
1312 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 1299 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
1313 | info->flags = | 1300 | info->flags |= iwl_is_tx_success(status) ? |
1314 | iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; | 1301 | IEEE80211_TX_STAT_ACK : 0; |
1315 | iwl_hwrate_to_tx_control(priv, | 1302 | iwl_hwrate_to_tx_control(priv, |
1316 | le32_to_cpu(tx_resp->rate_n_flags), | 1303 | le32_to_cpu(tx_resp->rate_n_flags), |
1317 | info); | 1304 | info); |
1318 | 1305 | ||
1319 | IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " | 1306 | IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) rate_n_flags " |
1320 | "0x%x retries %d\n", txq_id, | 1307 | "0x%x retries %d\n", |
1321 | iwl_get_tx_fail_reason(status), | 1308 | txq_id, |
1322 | status, le32_to_cpu(tx_resp->rate_n_flags), | 1309 | iwl_get_tx_fail_reason(status), status, |
1323 | tx_resp->failure_frame); | 1310 | le32_to_cpu(tx_resp->rate_n_flags), |
1311 | tx_resp->failure_frame); | ||
1324 | 1312 | ||
1325 | IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); | 1313 | freed = iwl_tx_queue_reclaim(priv, txq_id, index); |
1326 | if (index != -1) { | 1314 | if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) |
1327 | int freed = iwl_tx_queue_reclaim(priv, txq_id, index); | ||
1328 | if (tid != MAX_TID_COUNT) | ||
1329 | priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; | 1315 | priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; |
1330 | if (iwl_queue_space(&txq->q) > txq->q.low_mark && | 1316 | |
1331 | (txq_id >= 0) && priv->mac80211_registered) | 1317 | if (priv->mac80211_registered && |
1318 | (iwl_queue_space(&txq->q) > txq->q.low_mark)) | ||
1332 | ieee80211_wake_queue(priv->hw, txq_id); | 1319 | ieee80211_wake_queue(priv->hw, txq_id); |
1333 | if (tid != MAX_TID_COUNT) | ||
1334 | iwl_txq_check_empty(priv, sta_id, tid, txq_id); | ||
1335 | } | ||
1336 | } | 1320 | } |
1337 | 1321 | ||
1322 | if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) | ||
1323 | iwl_txq_check_empty(priv, sta_id, tid, txq_id); | ||
1324 | |||
1338 | if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) | 1325 | if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) |
1339 | IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); | 1326 | IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); |
1340 | } | 1327 | } |