aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2011-07-07 08:50:10 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-07-16 10:39:42 -0400
commitb3c2ce131c7cd8c53b72b0cc04241cde17ce0c1d (patch)
treedd6e9946011a2179749f4c2b0b0a394e6171bc50
parent1a361cd838173879672cb0f0ebe1e7654d7edff6 (diff)
iwlagn: add tx start API to transport layer
tx start will start the tx queues: basically configure the SCD Remove the IWLAGN prefix to SCD defines on the way. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.guy@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c51
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c136
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h82
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c153
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h5
7 files changed, 222 insertions, 210 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 554750d993ed..ece3202427f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -166,10 +166,10 @@ static int iwlagn_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
166 u32 tbl_dw; 166 u32 tbl_dw;
167 u16 scd_q2ratid; 167 u16 scd_q2ratid;
168 168
169 scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK; 169 scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
170 170
171 tbl_dw_addr = priv->scd_base_addr + 171 tbl_dw_addr = priv->scd_base_addr +
172 IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); 172 SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
173 173
174 tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr); 174 tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
175 175
@@ -188,9 +188,9 @@ static void iwlagn_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
188 /* Simply stop the queue, but don't change any configuration; 188 /* Simply stop the queue, but don't change any configuration;
189 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ 189 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
190 iwl_write_prph(priv, 190 iwl_write_prph(priv,
191 IWLAGN_SCD_QUEUE_STATUS_BITS(txq_id), 191 SCD_QUEUE_STATUS_BITS(txq_id),
192 (0 << IWLAGN_SCD_QUEUE_STTS_REG_POS_ACTIVE)| 192 (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
193 (1 << IWLAGN_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); 193 (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
194} 194}
195 195
196void iwlagn_set_wr_ptrs(struct iwl_priv *priv, 196void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
@@ -198,7 +198,7 @@ void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
198{ 198{
199 iwl_write_direct32(priv, HBUS_TARG_WRPTR, 199 iwl_write_direct32(priv, HBUS_TARG_WRPTR,
200 (index & 0xff) | (txq_id << 8)); 200 (index & 0xff) | (txq_id << 8));
201 iwl_write_prph(priv, IWLAGN_SCD_QUEUE_RDPTR(txq_id), index); 201 iwl_write_prph(priv, SCD_QUEUE_RDPTR(txq_id), index);
202} 202}
203 203
204void iwlagn_tx_queue_set_status(struct iwl_priv *priv, 204void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
@@ -208,11 +208,11 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
208 int txq_id = txq->q.id; 208 int txq_id = txq->q.id;
209 int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; 209 int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
210 210
211 iwl_write_prph(priv, IWLAGN_SCD_QUEUE_STATUS_BITS(txq_id), 211 iwl_write_prph(priv, SCD_QUEUE_STATUS_BITS(txq_id),
212 (active << IWLAGN_SCD_QUEUE_STTS_REG_POS_ACTIVE) | 212 (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
213 (tx_fifo_id << IWLAGN_SCD_QUEUE_STTS_REG_POS_TXF) | 213 (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
214 (1 << IWLAGN_SCD_QUEUE_STTS_REG_POS_WSL) | 214 (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
215 IWLAGN_SCD_QUEUE_STTS_REG_MSK); 215 SCD_QUEUE_STTS_REG_MSK);
216 216
217 txq->sched_retry = scd_retry; 217 txq->sched_retry = scd_retry;
218 218
@@ -271,10 +271,10 @@ void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
271 iwlagn_tx_queue_set_q2ratid(priv, ra_tid, txq_id); 271 iwlagn_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
272 272
273 /* Set this queue as a chain-building queue */ 273 /* Set this queue as a chain-building queue */
274 iwl_set_bits_prph(priv, IWLAGN_SCD_QUEUECHAIN_SEL, (1<<txq_id)); 274 iwl_set_bits_prph(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id));
275 275
276 /* enable aggregations for the queue */ 276 /* enable aggregations for the queue */
277 iwl_set_bits_prph(priv, IWLAGN_SCD_AGGR_SEL, (1<<txq_id)); 277 iwl_set_bits_prph(priv, SCD_AGGR_SEL, (1<<txq_id));
278 278
279 /* Place first TFD at index corresponding to start sequence number. 279 /* Place first TFD at index corresponding to start sequence number.
280 * Assumes that ssn_idx is valid (!= 0xFFF) */ 280 * Assumes that ssn_idx is valid (!= 0xFFF) */
@@ -284,16 +284,16 @@ void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
284 284
285 /* Set up Tx window size and frame limit for this queue */ 285 /* Set up Tx window size and frame limit for this queue */
286 iwl_write_targ_mem(priv, priv->scd_base_addr + 286 iwl_write_targ_mem(priv, priv->scd_base_addr +
287 IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + 287 SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
288 sizeof(u32), 288 sizeof(u32),
289 ((frame_limit << 289 ((frame_limit <<
290 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & 290 SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
291 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | 291 SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
292 ((frame_limit << 292 ((frame_limit <<
293 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & 293 SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
294 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); 294 SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
295 295
296 iwl_set_bits_prph(priv, IWLAGN_SCD_INTERRUPT_MASK, (1 << txq_id)); 296 iwl_set_bits_prph(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
297 297
298 /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ 298 /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
299 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); 299 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
@@ -317,29 +317,20 @@ static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
317 317
318 iwlagn_tx_queue_stop_scheduler(priv, txq_id); 318 iwlagn_tx_queue_stop_scheduler(priv, txq_id);
319 319
320 iwl_clear_bits_prph(priv, IWLAGN_SCD_AGGR_SEL, (1 << txq_id)); 320 iwl_clear_bits_prph(priv, SCD_AGGR_SEL, (1 << txq_id));
321 321
322 priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); 322 priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
323 priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); 323 priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
324 /* supposes that ssn_idx is valid (!= 0xFFF) */ 324 /* supposes that ssn_idx is valid (!= 0xFFF) */
325 iwlagn_set_wr_ptrs(priv, txq_id, ssn_idx); 325 iwlagn_set_wr_ptrs(priv, txq_id, ssn_idx);
326 326
327 iwl_clear_bits_prph(priv, IWLAGN_SCD_INTERRUPT_MASK, (1 << txq_id)); 327 iwl_clear_bits_prph(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
328 iwl_txq_ctx_deactivate(priv, txq_id); 328 iwl_txq_ctx_deactivate(priv, txq_id);
329 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); 329 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
330 330
331 return 0; 331 return 0;
332} 332}
333 333
334/*
335 * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
336 * must be called under priv->lock and mac access
337 */
338void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask)
339{
340 iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask);
341}
342
343static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, 334static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
344 struct ieee80211_tx_info *info, 335 struct ieee80211_tx_info *info,
345 __le16 fc, __le32 *tx_flags) 336 __le16 fc, __le32 *tx_flags)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index c15a1f7f4ff8..aebd5c71f9da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -41,38 +41,6 @@
41#include "iwl-agn-calib.h" 41#include "iwl-agn-calib.h"
42#include "iwl-trans.h" 42#include "iwl-trans.h"
43 43
44#define IWL_AC_UNSET -1
45
46struct queue_to_fifo_ac {
47 s8 fifo, ac;
48};
49
50static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
51 { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
52 { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
53 { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
54 { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
55 { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
56 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
57 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
58 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
59 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
60 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
61};
62
63static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
64 { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
65 { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
66 { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
67 { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
68 { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
69 { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
70 { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
71 { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
72 { IWL_TX_FIFO_BE_IPAN, 2, },
73 { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
74};
75
76static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { 44static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
77 {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, 45 {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
78 0, COEX_UNASSOC_IDLE_FLAGS}, 46 0, COEX_UNASSOC_IDLE_FLAGS},
@@ -379,111 +347,9 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
379 347
380static int iwlagn_alive_notify(struct iwl_priv *priv) 348static int iwlagn_alive_notify(struct iwl_priv *priv)
381{ 349{
382 const struct queue_to_fifo_ac *queue_to_fifo;
383 struct iwl_rxon_context *ctx;
384 u32 a;
385 unsigned long flags;
386 int i, chan;
387 u32 reg_val;
388 int ret; 350 int ret;
389 351
390 spin_lock_irqsave(&priv->lock, flags); 352 trans_tx_start(priv);
391
392 priv->scd_base_addr = iwl_read_prph(priv, IWLAGN_SCD_SRAM_BASE_ADDR);
393 a = priv->scd_base_addr + IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND;
394 /* reset conext data memory */
395 for (; a < priv->scd_base_addr + IWLAGN_SCD_CONTEXT_MEM_UPPER_BOUND;
396 a += 4)
397 iwl_write_targ_mem(priv, a, 0);
398 /* reset tx status memory */
399 for (; a < priv->scd_base_addr + IWLAGN_SCD_TX_STTS_MEM_UPPER_BOUND;
400 a += 4)
401 iwl_write_targ_mem(priv, a, 0);
402 for (; a < priv->scd_base_addr +
403 IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
404 iwl_write_targ_mem(priv, a, 0);
405
406 iwl_write_prph(priv, IWLAGN_SCD_DRAM_BASE_ADDR,
407 priv->scd_bc_tbls.dma >> 10);
408
409 /* Enable DMA channel */
410 for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
411 iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
412 FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
413 FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
414
415 /* Update FH chicken bits */
416 reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
417 iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
418 reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
419
420 iwl_write_prph(priv, IWLAGN_SCD_QUEUECHAIN_SEL,
421 IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv));
422 iwl_write_prph(priv, IWLAGN_SCD_AGGR_SEL, 0);
423
424 /* initiate the queues */
425 for (i = 0; i < priv->hw_params.max_txq_num; i++) {
426 iwl_write_prph(priv, IWLAGN_SCD_QUEUE_RDPTR(i), 0);
427 iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
428 iwl_write_targ_mem(priv, priv->scd_base_addr +
429 IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
430 iwl_write_targ_mem(priv, priv->scd_base_addr +
431 IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(i) +
432 sizeof(u32),
433 ((SCD_WIN_SIZE <<
434 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
435 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
436 ((SCD_FRAME_LIMIT <<
437 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
438 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
439 }
440
441 iwl_write_prph(priv, IWLAGN_SCD_INTERRUPT_MASK,
442 IWL_MASK(0, priv->hw_params.max_txq_num));
443
444 /* Activate all Tx DMA/FIFO channels */
445 iwlagn_txq_set_sched(priv, IWL_MASK(0, 7));
446
447 /* map queues to FIFOs */
448 if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
449 queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
450 else
451 queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
452
453 iwlagn_set_wr_ptrs(priv, priv->cmd_queue, 0);
454
455 /* make sure all queue are not stopped */
456 memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
457 for (i = 0; i < 4; i++)
458 atomic_set(&priv->queue_stop_count[i], 0);
459 for_each_context(priv, ctx)
460 ctx->last_tx_rejected = false;
461
462 /* reset to 0 to enable all the queue first */
463 priv->txq_ctx_active_msk = 0;
464
465 BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
466 BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10);
467
468 for (i = 0; i < 10; i++) {
469 int fifo = queue_to_fifo[i].fifo;
470 int ac = queue_to_fifo[i].ac;
471
472 iwl_txq_ctx_activate(priv, i);
473
474 if (fifo == IWL_TX_FIFO_UNUSED)
475 continue;
476
477 if (ac != IWL_AC_UNSET)
478 iwl_set_swq_id(&priv->txq[i], ac, i);
479 iwlagn_tx_queue_set_status(priv, &priv->txq[i], fifo, 0);
480 }
481
482 spin_unlock_irqrestore(&priv->lock, flags);
483
484 /* Enable L1-Active */
485 iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG,
486 APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
487 353
488 ret = iwlagn_send_wimax_coex(priv); 354 ret = iwlagn_send_wimax_coex(priv);
489 if (ret) 355 if (ret)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index c851fc2fb6b2..0e8ccb9c99b1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -136,7 +136,6 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
136void iwlagn_tx_queue_set_status(struct iwl_priv *priv, 136void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
137 struct iwl_tx_queue *txq, 137 struct iwl_tx_queue *txq,
138 int tx_fifo_id, int scd_retry); 138 int tx_fifo_id, int scd_retry);
139void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
140void iwl_free_tfds_in_queue(struct iwl_priv *priv, 139void iwl_free_tfds_in_queue(struct iwl_priv *priv,
141 int sta_id, int tid, int freed); 140 int sta_id, int tid, int freed);
142 141
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index cf6f4b2e2cd5..fddc23627644 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1234,10 +1234,11 @@ struct iwl_trans;
1234 1234
1235/** 1235/**
1236 * struct iwl_trans_ops - transport specific operations 1236 * struct iwl_trans_ops - transport specific operations
1237
1238 * @rx_init: inits the rx memory, allocate it if needed 1237 * @rx_init: inits the rx memory, allocate it if needed
1239 * @rx_free: frees the rx memory 1238 * @rx_free: frees the rx memory
1240 * @tx_init:inits the tx memory, allocate if needed 1239 * @tx_init:inits the tx memory, allocate if needed
1240 * @tx_start: starts and configures all the Tx fifo - usually done once the fw
1241 * is alive.
1241 * @tx_free: frees the tx memory 1242 * @tx_free: frees the tx memory
1242 * @stop_device:stops the whole device (embedded CPU put to reset) 1243 * @stop_device:stops the whole device (embedded CPU put to reset)
1243 * @send_cmd:send a host command 1244 * @send_cmd:send a host command
@@ -1256,6 +1257,7 @@ struct iwl_trans_ops {
1256 void (*rx_free)(struct iwl_priv *priv); 1257 void (*rx_free)(struct iwl_priv *priv);
1257 1258
1258 int (*tx_init)(struct iwl_priv *priv); 1259 int (*tx_init)(struct iwl_priv *priv);
1260 void (*tx_start)(struct iwl_priv *priv);
1259 void (*tx_free)(struct iwl_priv *priv); 1261 void (*tx_free)(struct iwl_priv *priv);
1260 1262
1261 void (*stop_device)(struct iwl_priv *priv); 1263 void (*stop_device)(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 1cc0ed1f488c..2f267b8aabbb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -178,61 +178,61 @@
178#define SCD_WIN_SIZE 64 178#define SCD_WIN_SIZE 64
179#define SCD_FRAME_LIMIT 64 179#define SCD_FRAME_LIMIT 64
180 180
181#define IWL_SCD_TXFIFO_POS_TID (0) 181#define SCD_TXFIFO_POS_TID (0)
182#define IWL_SCD_TXFIFO_POS_RA (4) 182#define SCD_TXFIFO_POS_RA (4)
183#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) 183#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
184 184
185/* agn SCD */ 185/* agn SCD */
186#define IWLAGN_SCD_QUEUE_STTS_REG_POS_TXF (0) 186#define SCD_QUEUE_STTS_REG_POS_TXF (0)
187#define IWLAGN_SCD_QUEUE_STTS_REG_POS_ACTIVE (3) 187#define SCD_QUEUE_STTS_REG_POS_ACTIVE (3)
188#define IWLAGN_SCD_QUEUE_STTS_REG_POS_WSL (4) 188#define SCD_QUEUE_STTS_REG_POS_WSL (4)
189#define IWLAGN_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) 189#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
190#define IWLAGN_SCD_QUEUE_STTS_REG_MSK (0x00FF0000) 190#define SCD_QUEUE_STTS_REG_MSK (0x00FF0000)
191 191
192#define IWLAGN_SCD_QUEUE_CTX_REG1_CREDIT_POS (8) 192#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8)
193#define IWLAGN_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) 193#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00)
194#define IWLAGN_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) 194#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24)
195#define IWLAGN_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) 195#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000)
196#define IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) 196#define SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0)
197#define IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) 197#define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F)
198#define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) 198#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
199#define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) 199#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
200 200
201/* Context Data */ 201/* Context Data */
202#define IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) 202#define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600)
203#define IWLAGN_SCD_CONTEXT_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x6A0) 203#define SCD_CONTEXT_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x6A0)
204 204
205/* Tx status */ 205/* Tx status */
206#define IWLAGN_SCD_TX_STTS_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x6A0) 206#define SCD_TX_STTS_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x6A0)
207#define IWLAGN_SCD_TX_STTS_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x7E0) 207#define SCD_TX_STTS_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x7E0)
208 208
209/* Translation Data */ 209/* Translation Data */
210#define IWLAGN_SCD_TRANS_TBL_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x7E0) 210#define SCD_TRANS_TBL_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x7E0)
211#define IWLAGN_SCD_TRANS_TBL_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x808) 211#define SCD_TRANS_TBL_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x808)
212 212
213#define IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(x)\ 213#define SCD_CONTEXT_QUEUE_OFFSET(x)\
214 (IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND + ((x) * 8)) 214 (SCD_CONTEXT_MEM_LOWER_BOUND + ((x) * 8))
215 215
216#define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ 216#define SCD_TRANS_TBL_OFFSET_QUEUE(x) \
217 ((IWLAGN_SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc) 217 ((SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc)
218 218
219#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv) \ 219#define SCD_QUEUECHAIN_SEL_ALL(priv) \
220 (((1<<(priv)->hw_params.max_txq_num) - 1) &\ 220 (((1<<(priv)->hw_params.max_txq_num) - 1) &\
221 (~(1<<(priv)->cmd_queue))) 221 (~(1<<(priv)->cmd_queue)))
222 222
223#define IWLAGN_SCD_BASE (PRPH_BASE + 0xa02c00) 223#define SCD_BASE (PRPH_BASE + 0xa02c00)
224 224
225#define IWLAGN_SCD_SRAM_BASE_ADDR (IWLAGN_SCD_BASE + 0x0) 225#define SCD_SRAM_BASE_ADDR (SCD_BASE + 0x0)
226#define IWLAGN_SCD_DRAM_BASE_ADDR (IWLAGN_SCD_BASE + 0x8) 226#define SCD_DRAM_BASE_ADDR (SCD_BASE + 0x8)
227#define IWLAGN_SCD_AIT (IWLAGN_SCD_BASE + 0x0c) 227#define SCD_AIT (SCD_BASE + 0x0c)
228#define IWLAGN_SCD_TXFACT (IWLAGN_SCD_BASE + 0x10) 228#define SCD_TXFACT (SCD_BASE + 0x10)
229#define IWLAGN_SCD_ACTIVE (IWLAGN_SCD_BASE + 0x14) 229#define SCD_ACTIVE (SCD_BASE + 0x14)
230#define IWLAGN_SCD_QUEUE_WRPTR(x) (IWLAGN_SCD_BASE + 0x18 + (x) * 4) 230#define SCD_QUEUE_WRPTR(x) (SCD_BASE + 0x18 + (x) * 4)
231#define IWLAGN_SCD_QUEUE_RDPTR(x) (IWLAGN_SCD_BASE + 0x68 + (x) * 4) 231#define SCD_QUEUE_RDPTR(x) (SCD_BASE + 0x68 + (x) * 4)
232#define IWLAGN_SCD_QUEUECHAIN_SEL (IWLAGN_SCD_BASE + 0xe8) 232#define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8)
233#define IWLAGN_SCD_AGGR_SEL (IWLAGN_SCD_BASE + 0x248) 233#define SCD_AGGR_SEL (SCD_BASE + 0x248)
234#define IWLAGN_SCD_INTERRUPT_MASK (IWLAGN_SCD_BASE + 0x108) 234#define SCD_INTERRUPT_MASK (SCD_BASE + 0x108)
235#define IWLAGN_SCD_QUEUE_STATUS_BITS(x) (IWLAGN_SCD_BASE + 0x10c + (x) * 4) 235#define SCD_QUEUE_STATUS_BITS(x) (SCD_BASE + 0x10c + (x) * 4)
236 236
237/*********************** END TX SCHEDULER *************************************/ 237/*********************** END TX SCHEDULER *************************************/
238 238
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
index 8d4555404799..7c748f65c86f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -547,7 +547,7 @@ static int iwl_trans_tx_init(struct iwl_priv *priv)
547 spin_lock_irqsave(&priv->lock, flags); 547 spin_lock_irqsave(&priv->lock, flags);
548 548
549 /* Turn off all Tx DMA fifos */ 549 /* Turn off all Tx DMA fifos */
550 iwl_write_prph(priv, IWLAGN_SCD_TXFACT, 0); 550 iwl_write_prph(priv, SCD_TXFACT, 0);
551 551
552 /* Tell NIC where to find the "keep warm" buffer */ 552 /* Tell NIC where to find the "keep warm" buffer */
553 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); 553 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -574,6 +574,154 @@ error:
574 return ret; 574 return ret;
575} 575}
576 576
577/*
578 * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
579 * must be called under priv->lock and mac access
580 */
581static void iwl_trans_txq_set_sched(struct iwl_priv *priv, u32 mask)
582{
583 iwl_write_prph(priv, SCD_TXFACT, mask);
584}
585
586#define IWL_AC_UNSET -1
587
588struct queue_to_fifo_ac {
589 s8 fifo, ac;
590};
591
592static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
593 { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
594 { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
595 { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
596 { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
597 { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
598 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
599 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
600 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
601 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
602 { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
603};
604
605static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
606 { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
607 { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
608 { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
609 { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
610 { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
611 { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
612 { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
613 { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
614 { IWL_TX_FIFO_BE_IPAN, 2, },
615 { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
616};
617static void iwl_trans_tx_start(struct iwl_priv *priv)
618{
619 const struct queue_to_fifo_ac *queue_to_fifo;
620 struct iwl_rxon_context *ctx;
621 u32 a;
622 unsigned long flags;
623 int i, chan;
624 u32 reg_val;
625
626 spin_lock_irqsave(&priv->lock, flags);
627
628 priv->scd_base_addr = iwl_read_prph(priv, SCD_SRAM_BASE_ADDR);
629 a = priv->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
630 /* reset conext data memory */
631 for (; a < priv->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
632 a += 4)
633 iwl_write_targ_mem(priv, a, 0);
634 /* reset tx status memory */
635 for (; a < priv->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
636 a += 4)
637 iwl_write_targ_mem(priv, a, 0);
638 for (; a < priv->scd_base_addr +
639 SCD_TRANS_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
640 iwl_write_targ_mem(priv, a, 0);
641
642 iwl_write_prph(priv, SCD_DRAM_BASE_ADDR,
643 priv->scd_bc_tbls.dma >> 10);
644
645 /* Enable DMA channel */
646 for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
647 iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
648 FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
649 FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
650
651 /* Update FH chicken bits */
652 reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
653 iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
654 reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
655
656 iwl_write_prph(priv, SCD_QUEUECHAIN_SEL,
657 SCD_QUEUECHAIN_SEL_ALL(priv));
658 iwl_write_prph(priv, SCD_AGGR_SEL, 0);
659
660 /* initiate the queues */
661 for (i = 0; i < priv->hw_params.max_txq_num; i++) {
662 iwl_write_prph(priv, SCD_QUEUE_RDPTR(i), 0);
663 iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
664 iwl_write_targ_mem(priv, priv->scd_base_addr +
665 SCD_CONTEXT_QUEUE_OFFSET(i), 0);
666 iwl_write_targ_mem(priv, priv->scd_base_addr +
667 SCD_CONTEXT_QUEUE_OFFSET(i) +
668 sizeof(u32),
669 ((SCD_WIN_SIZE <<
670 SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
671 SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
672 ((SCD_FRAME_LIMIT <<
673 SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
674 SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
675 }
676
677 iwl_write_prph(priv, SCD_INTERRUPT_MASK,
678 IWL_MASK(0, priv->hw_params.max_txq_num));
679
680 /* Activate all Tx DMA/FIFO channels */
681 iwl_trans_txq_set_sched(priv, IWL_MASK(0, 7));
682
683 /* map queues to FIFOs */
684 if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
685 queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
686 else
687 queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
688
689 iwlagn_set_wr_ptrs(priv, priv->cmd_queue, 0);
690
691 /* make sure all queue are not stopped */
692 memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
693 for (i = 0; i < 4; i++)
694 atomic_set(&priv->queue_stop_count[i], 0);
695 for_each_context(priv, ctx)
696 ctx->last_tx_rejected = false;
697
698 /* reset to 0 to enable all the queue first */
699 priv->txq_ctx_active_msk = 0;
700
701 BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
702 BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10);
703
704 for (i = 0; i < 10; i++) {
705 int fifo = queue_to_fifo[i].fifo;
706 int ac = queue_to_fifo[i].ac;
707
708 iwl_txq_ctx_activate(priv, i);
709
710 if (fifo == IWL_TX_FIFO_UNUSED)
711 continue;
712
713 if (ac != IWL_AC_UNSET)
714 iwl_set_swq_id(&priv->txq[i], ac, i);
715 iwlagn_tx_queue_set_status(priv, &priv->txq[i], fifo, 0);
716 }
717
718 spin_unlock_irqrestore(&priv->lock, flags);
719
720 /* Enable L1-Active */
721 iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG,
722 APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
723}
724
577/** 725/**
578 * iwlagn_txq_ctx_stop - Stop all Tx DMA channels 726 * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
579 */ 727 */
@@ -585,7 +733,7 @@ static int iwl_trans_tx_stop(struct iwl_priv *priv)
585 /* Turn off all Tx DMA fifos */ 733 /* Turn off all Tx DMA fifos */
586 spin_lock_irqsave(&priv->lock, flags); 734 spin_lock_irqsave(&priv->lock, flags);
587 735
588 iwlagn_txq_set_sched(priv, 0); 736 iwl_trans_txq_set_sched(priv, 0);
589 737
590 /* Stop each Tx DMA channel, and wait for it to be idle */ 738 /* Stop each Tx DMA channel, and wait for it to be idle */
591 for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { 739 for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
@@ -822,6 +970,7 @@ static const struct iwl_trans_ops trans_ops = {
822 .rx_free = iwl_trans_rx_free, 970 .rx_free = iwl_trans_rx_free,
823 971
824 .tx_init = iwl_trans_tx_init, 972 .tx_init = iwl_trans_tx_init,
973 .tx_start = iwl_trans_tx_start,
825 .tx_free = iwl_trans_tx_free, 974 .tx_free = iwl_trans_tx_free,
826 975
827 .stop_device = iwl_trans_stop_device, 976 .stop_device = iwl_trans_stop_device,
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 55e6c333bfa1..16cdb89b02fc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -79,6 +79,11 @@ static inline int trans_tx_init(struct iwl_priv *priv)
79 return priv->trans.ops->tx_init(priv); 79 return priv->trans.ops->tx_init(priv);
80} 80}
81 81
82static inline void trans_tx_start(struct iwl_priv *priv)
83{
84 priv->trans.ops->tx_start(priv);
85}
86
82static inline void trans_tx_free(struct iwl_priv *priv) 87static inline void trans_tx_free(struct iwl_priv *priv)
83{ 88{
84 priv->trans.ops->tx_free(priv); 89 priv->trans.ops->tx_free(priv);