aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2008-06-11 21:46:56 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-14 12:18:06 -0400
commite26e47d94473af0c2a18beac664e526317b4f0b9 (patch)
tree034700425e4d2097c9a4b21a665429c95fab5fb1 /drivers/net/wireless/iwlwifi
parent7f3e4bb60f81dd172d5e4b89220cb3f80c6dc552 (diff)
iwlwifi: add TX aggregation code for 5000 HW
This patch adds TX aggregation handler for 5000 HW. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 0ae5421c81c..d3c0e10397c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -41,6 +41,7 @@
41#include "iwl-dev.h" 41#include "iwl-dev.h"
42#include "iwl-core.h" 42#include "iwl-core.h"
43#include "iwl-io.h" 43#include "iwl-io.h"
44#include "iwl-sta.h"
44#include "iwl-helpers.h" 45#include "iwl-helpers.h"
45#include "iwl-5000-hw.h" 46#include "iwl-5000-hw.h"
46 47
@@ -976,6 +977,135 @@ static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
976 } 977 }
977} 978}
978 979
980static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
981 u16 txq_id)
982{
983 u32 tbl_dw_addr;
984 u32 tbl_dw;
985 u16 scd_q2ratid;
986
987 scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
988
989 tbl_dw_addr = priv->scd_base_addr +
990 IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
991
992 tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
993
994 if (txq_id & 0x1)
995 tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
996 else
997 tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
998
999 iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
1000
1001 return 0;
1002}
1003static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
1004{
1005 /* Simply stop the queue, but don't change any configuration;
1006 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
1007 iwl_write_prph(priv,
1008 IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
1009 (0 << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE)|
1010 (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
1011}
1012
1013static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
1014 int tx_fifo, int sta_id, int tid, u16 ssn_idx)
1015{
1016 unsigned long flags;
1017 int ret;
1018 u16 ra_tid;
1019
1020 if (IWL50_FIRST_AMPDU_QUEUE > txq_id)
1021 IWL_WARNING("queue number too small: %d, must be > %d\n",
1022 txq_id, IWL50_FIRST_AMPDU_QUEUE);
1023
1024 ra_tid = BUILD_RAxTID(sta_id, tid);
1025
1026 /* Modify device's station table to Tx this TID */
1027 iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
1028
1029 spin_lock_irqsave(&priv->lock, flags);
1030 ret = iwl_grab_nic_access(priv);
1031 if (ret) {
1032 spin_unlock_irqrestore(&priv->lock, flags);
1033 return ret;
1034 }
1035
1036 /* Stop this Tx queue before configuring it */
1037 iwl5000_tx_queue_stop_scheduler(priv, txq_id);
1038
1039 /* Map receiver-address / traffic-ID to this queue */
1040 iwl5000_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
1041
1042 /* Set this queue as a chain-building queue */
1043 iwl_set_bits_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, (1<<txq_id));
1044
1045 /* enable aggregations for the queue */
1046 iwl_set_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1<<txq_id));
1047
1048 /* Place first TFD at index corresponding to start sequence number.
1049 * Assumes that ssn_idx is valid (!= 0xFFF) */
1050 priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
1051 priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
1052 iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx);
1053
1054 /* Set up Tx window size and frame limit for this queue */
1055 iwl_write_targ_mem(priv, priv->scd_base_addr +
1056 IWL50_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
1057 sizeof(u32),
1058 ((SCD_WIN_SIZE <<
1059 IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
1060 IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
1061 ((SCD_FRAME_LIMIT <<
1062 IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
1063 IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
1064
1065 iwl_set_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
1066
1067 /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
1068 iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
1069
1070 iwl_release_nic_access(priv);
1071 spin_unlock_irqrestore(&priv->lock, flags);
1072
1073 return 0;
1074}
1075
1076static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
1077 u16 ssn_idx, u8 tx_fifo)
1078{
1079 int ret;
1080
1081 if (IWL50_FIRST_AMPDU_QUEUE > txq_id) {
1082 IWL_WARNING("queue number too small: %d, must be > %d\n",
1083 txq_id, IWL50_FIRST_AMPDU_QUEUE);
1084 return -EINVAL;
1085 }
1086
1087 ret = iwl_grab_nic_access(priv);
1088 if (ret)
1089 return ret;
1090
1091 iwl5000_tx_queue_stop_scheduler(priv, txq_id);
1092
1093 iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id));
1094
1095 priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
1096 priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
1097 /* supposes that ssn_idx is valid (!= 0xFFF) */
1098 iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx);
1099
1100 iwl_clear_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
1101 iwl_txq_ctx_deactivate(priv, txq_id);
1102 iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
1103
1104 iwl_release_nic_access(priv);
1105
1106 return 0;
1107}
1108
979static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) 1109static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
980{ 1110{
981 u16 size = (u16)sizeof(struct iwl_addsta_cmd); 1111 u16 size = (u16)sizeof(struct iwl_addsta_cmd);
@@ -1319,6 +1449,8 @@ static struct iwl_lib_ops iwl5000_lib = {
1319 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, 1449 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
1320 .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, 1450 .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
1321 .txq_set_sched = iwl5000_txq_set_sched, 1451 .txq_set_sched = iwl5000_txq_set_sched,
1452 .txq_agg_enable = iwl5000_txq_agg_enable,
1453 .txq_agg_disable = iwl5000_txq_agg_disable,
1322 .rx_handler_setup = iwl5000_rx_handler_setup, 1454 .rx_handler_setup = iwl5000_rx_handler_setup,
1323 .setup_deferred_work = iwl5000_setup_deferred_work, 1455 .setup_deferred_work = iwl5000_setup_deferred_work,
1324 .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, 1456 .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,