aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorSamuel Ortiz <samuel.ortiz@intel.com>2009-01-23 16:45:14 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:01:34 -0500
commita8e74e2774cd1aecfef0460de07e6e178df89232 (patch)
treebccf507738fb8753e7ab16a8de9644e9d99ae07c /drivers/net/wireless/iwlwifi
parent59606ffa9146538b73bbe1ca1285321cd7474bc0 (diff)
iwl3945: Use iwlcore TX queue management routines
By adding an additional hw_params (tfd_size) and a new iwl_lib ops (txq_init), we can now use the iwlcore TX queue management routines. We had to add a new hw_params because we need to allocate the right DMA buffer for TFDs, and those have a different sizes depending if you're on 3945 or agn. Signed-off-by: Samuel Ortiz <samuel.ortiz@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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c49
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c204
8 files changed, 60 insertions, 246 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 22770f44c2fa..2689113f4e60 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -1068,8 +1068,8 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
1068 for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) { 1068 for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) {
1069 slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? 1069 slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
1070 TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; 1070 TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
1071 rc = iwl3945_tx_queue_init(priv, &priv->txq[txq_id], slots_num, 1071 rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
1072 txq_id); 1072 txq_id);
1073 if (rc) { 1073 if (rc) {
1074 IWL_ERR(priv, "Tx %d queue init failed\n", txq_id); 1074 IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
1075 goto error; 1075 goto error;
@@ -1258,7 +1258,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
1258 1258
1259 /* Tx queues */ 1259 /* Tx queues */
1260 for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) 1260 for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++)
1261 iwl3945_tx_queue_free(priv, &priv->txq[txq_id]); 1261 iwl_tx_queue_free(priv, txq_id);
1262} 1262}
1263 1263
1264void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) 1264void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
@@ -2491,6 +2491,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
2491 return -ENOMEM; 2491 return -ENOMEM;
2492 } 2492 }
2493 2493
2494 priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
2494 priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; 2495 priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
2495 priv->hw_params.max_pkt_size = 2342; 2496 priv->hw_params.max_pkt_size = 2342;
2496 priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; 2497 priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
@@ -2705,6 +2706,7 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
2705static struct iwl_lib_ops iwl3945_lib = { 2706static struct iwl_lib_ops iwl3945_lib = {
2706 .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, 2707 .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
2707 .txq_free_tfd = iwl3945_hw_txq_free_tfd, 2708 .txq_free_tfd = iwl3945_hw_txq_free_tfd,
2709 .txq_init = iwl3945_hw_tx_queue_init,
2708 .load_ucode = iwl3945_load_bsm, 2710 .load_ucode = iwl3945_load_bsm,
2709 .apm_ops = { 2711 .apm_ops = {
2710 .init = iwl3945_apm_init, 2712 .init = iwl3945_apm_init,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index b2985e25dc83..d7d956db19d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -815,6 +815,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
815 priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; 815 priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
816 priv->hw_params.scd_bc_tbls_size = 816 priv->hw_params.scd_bc_tbls_size =
817 IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); 817 IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl);
818 priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
818 priv->hw_params.max_stations = IWL4965_STATION_COUNT; 819 priv->hw_params.max_stations = IWL4965_STATION_COUNT;
819 priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; 820 priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
820 priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; 821 priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
@@ -2297,6 +2298,7 @@ static struct iwl_lib_ops iwl4965_lib = {
2297 .txq_agg_disable = iwl4965_txq_agg_disable, 2298 .txq_agg_disable = iwl4965_txq_agg_disable,
2298 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, 2299 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
2299 .txq_free_tfd = iwl_hw_txq_free_tfd, 2300 .txq_free_tfd = iwl_hw_txq_free_tfd,
2301 .txq_init = iwl_hw_tx_queue_init,
2300 .rx_handler_setup = iwl4965_rx_handler_setup, 2302 .rx_handler_setup = iwl4965_rx_handler_setup,
2301 .setup_deferred_work = iwl4965_setup_deferred_work, 2303 .setup_deferred_work = iwl4965_setup_deferred_work,
2302 .cancel_deferred_work = iwl4965_cancel_deferred_work, 2304 .cancel_deferred_work = iwl4965_cancel_deferred_work,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 04c2585a6341..89d92a8ca157 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -837,6 +837,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
837 priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; 837 priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
838 priv->hw_params.scd_bc_tbls_size = 838 priv->hw_params.scd_bc_tbls_size =
839 IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); 839 IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl);
840 priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
840 priv->hw_params.max_stations = IWL5000_STATION_COUNT; 841 priv->hw_params.max_stations = IWL5000_STATION_COUNT;
841 priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; 842 priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
842 priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; 843 priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
@@ -1494,6 +1495,7 @@ static struct iwl_lib_ops iwl5000_lib = {
1494 .txq_agg_disable = iwl5000_txq_agg_disable, 1495 .txq_agg_disable = iwl5000_txq_agg_disable,
1495 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, 1496 .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
1496 .txq_free_tfd = iwl_hw_txq_free_tfd, 1497 .txq_free_tfd = iwl_hw_txq_free_tfd,
1498 .txq_init = iwl_hw_tx_queue_init,
1497 .rx_handler_setup = iwl5000_rx_handler_setup, 1499 .rx_handler_setup = iwl5000_rx_handler_setup,
1498 .setup_deferred_work = iwl5000_setup_deferred_work, 1500 .setup_deferred_work = iwl5000_setup_deferred_work,
1499 .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, 1501 .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 4ce3d6a63d18..5c6b3fe3eedf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -592,6 +592,38 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
592 return 0; 592 return 0;
593} 593}
594 594
595/*
596 * Tell nic where to find circular buffer of Tx Frame Descriptors for
597 * given Tx queue, and enable the DMA channel used for that queue.
598 *
599 * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
600 * channels supported in hardware.
601 */
602int iwl_hw_tx_queue_init(struct iwl_priv *priv,
603 struct iwl_tx_queue *txq)
604{
605 int ret;
606 unsigned long flags;
607 int txq_id = txq->q.id;
608
609 spin_lock_irqsave(&priv->lock, flags);
610 ret = iwl_grab_nic_access(priv);
611 if (ret) {
612 spin_unlock_irqrestore(&priv->lock, flags);
613 return ret;
614 }
615
616 /* Circular buffer (TFD queue in DRAM) physical base address */
617 iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
618 txq->q.dma_addr >> 8);
619
620 iwl_release_nic_access(priv);
621 spin_unlock_irqrestore(&priv->lock, flags);
622
623 return 0;
624}
625
626
595/****************************************************************************** 627/******************************************************************************
596 * 628 *
597 * Misc. internal state and helper functions 629 * Misc. internal state and helper functions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 409caaa31bb1..9a350806a21e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -116,6 +116,8 @@ struct iwl_lib_ops {
116 u16 len, u8 reset, u8 pad); 116 u16 len, u8 reset, u8 pad);
117 void (*txq_free_tfd)(struct iwl_priv *priv, 117 void (*txq_free_tfd)(struct iwl_priv *priv,
118 struct iwl_tx_queue *txq); 118 struct iwl_tx_queue *txq);
119 int (*txq_init)(struct iwl_priv *priv,
120 struct iwl_tx_queue *txq);
119 /* aggregations */ 121 /* aggregations */
120 int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, 122 int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo,
121 int sta_id, int tid, u16 ssn_idx); 123 int sta_id, int tid, u16 ssn_idx);
@@ -264,7 +266,12 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
264 dma_addr_t addr, u16 len, u8 reset, u8 pad); 266 dma_addr_t addr, u16 len, u8 reset, u8 pad);
265int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); 267int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
266void iwl_hw_txq_ctx_free(struct iwl_priv *priv); 268void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
269int iwl_hw_tx_queue_init(struct iwl_priv *priv,
270 struct iwl_tx_queue *txq);
267int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); 271int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
272int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
273 int slots_num, u32 txq_id);
274void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
268int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); 275int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
269int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); 276int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
270int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); 277int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 78ce4f49c568..5aa22d61e398 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -567,6 +567,7 @@ struct iwl_sensitivity_ranges {
567 * @max_txq_num: Max # Tx queues supported 567 * @max_txq_num: Max # Tx queues supported
568 * @dma_chnl_num: Number of Tx DMA/FIFO channels 568 * @dma_chnl_num: Number of Tx DMA/FIFO channels
569 * @scd_bc_tbls_size: size of scheduler byte count tables 569 * @scd_bc_tbls_size: size of scheduler byte count tables
570 * @tfd_size: TFD size
570 * @tx/rx_chains_num: Number of TX/RX chains 571 * @tx/rx_chains_num: Number of TX/RX chains
571 * @valid_tx/rx_ant: usable antennas 572 * @valid_tx/rx_ant: usable antennas
572 * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) 573 * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
@@ -587,6 +588,7 @@ struct iwl_hw_params {
587 u8 max_txq_num; 588 u8 max_txq_num;
588 u8 dma_chnl_num; 589 u8 dma_chnl_num;
589 u16 scd_bc_tbls_size; 590 u16 scd_bc_tbls_size;
591 u32 tfd_size;
590 u8 tx_chains_num; 592 u8 tx_chains_num;
591 u8 rx_chains_num; 593 u8 rx_chains_num;
592 u8 valid_tx_ant; 594 u8 valid_tx_ant;
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 83e9f32cbd8e..58118c8224cf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -131,7 +131,7 @@ EXPORT_SYMBOL(iwl_txq_update_write_ptr);
131 * Free all buffers. 131 * Free all buffers.
132 * 0-fill, but do not free "txq" descriptor structure. 132 * 0-fill, but do not free "txq" descriptor structure.
133 */ 133 */
134static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) 134void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
135{ 135{
136 struct iwl_tx_queue *txq = &priv->txq[txq_id]; 136 struct iwl_tx_queue *txq = &priv->txq[txq_id];
137 struct iwl_queue *q = &txq->q; 137 struct iwl_queue *q = &txq->q;
@@ -154,7 +154,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
154 154
155 /* De-alloc circular buffer of TFDs */ 155 /* De-alloc circular buffer of TFDs */
156 if (txq->q.n_bd) 156 if (txq->q.n_bd)
157 pci_free_consistent(dev, sizeof(struct iwl_tfd) * 157 pci_free_consistent(dev, priv->hw_params.tfd_size *
158 txq->q.n_bd, txq->tfds, txq->q.dma_addr); 158 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
159 159
160 /* De-alloc array of per-TFD driver data */ 160 /* De-alloc array of per-TFD driver data */
@@ -164,7 +164,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
164 /* 0-fill queue descriptor structure */ 164 /* 0-fill queue descriptor structure */
165 memset(txq, 0, sizeof(*txq)); 165 memset(txq, 0, sizeof(*txq));
166} 166}
167 167EXPORT_SYMBOL(iwl_tx_queue_free);
168 168
169/** 169/**
170 * iwl_cmd_queue_free - Deallocate DMA queue. 170 * iwl_cmd_queue_free - Deallocate DMA queue.
@@ -295,12 +295,12 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
295 /* Circular buffer of transmit frame descriptors (TFDs), 295 /* Circular buffer of transmit frame descriptors (TFDs),
296 * shared with device */ 296 * shared with device */
297 txq->tfds = pci_alloc_consistent(dev, 297 txq->tfds = pci_alloc_consistent(dev,
298 sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX, 298 priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX,
299 &txq->q.dma_addr); 299 &txq->q.dma_addr);
300 300
301 if (!txq->tfds) { 301 if (!txq->tfds) {
302 IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", 302 IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n",
303 sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX); 303 priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX);
304 goto error; 304 goto error;
305 } 305 }
306 txq->q.id = id; 306 txq->q.id = id;
@@ -314,42 +314,11 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
314 return -ENOMEM; 314 return -ENOMEM;
315} 315}
316 316
317/*
318 * Tell nic where to find circular buffer of Tx Frame Descriptors for
319 * given Tx queue, and enable the DMA channel used for that queue.
320 *
321 * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
322 * channels supported in hardware.
323 */
324static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
325 struct iwl_tx_queue *txq)
326{
327 int ret;
328 unsigned long flags;
329 int txq_id = txq->q.id;
330
331 spin_lock_irqsave(&priv->lock, flags);
332 ret = iwl_grab_nic_access(priv);
333 if (ret) {
334 spin_unlock_irqrestore(&priv->lock, flags);
335 return ret;
336 }
337
338 /* Circular buffer (TFD queue in DRAM) physical base address */
339 iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
340 txq->q.dma_addr >> 8);
341
342 iwl_release_nic_access(priv);
343 spin_unlock_irqrestore(&priv->lock, flags);
344
345 return 0;
346}
347
348/** 317/**
349 * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue 318 * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
350 */ 319 */
351static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, 320int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
352 int slots_num, u32 txq_id) 321 int slots_num, u32 txq_id)
353{ 322{
354 int i, len; 323 int i, len;
355 int ret; 324 int ret;
@@ -391,7 +360,7 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
391 iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); 360 iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
392 361
393 /* Tell device where to find queue */ 362 /* Tell device where to find queue */
394 iwl_hw_tx_queue_init(priv, txq); 363 priv->cfg->ops->lib->txq_init(priv, txq);
395 364
396 return 0; 365 return 0;
397err: 366err:
@@ -406,6 +375,8 @@ err:
406 } 375 }
407 return -ENOMEM; 376 return -ENOMEM;
408} 377}
378EXPORT_SYMBOL(iwl_tx_queue_init);
379
409/** 380/**
410 * iwl_hw_txq_ctx_free - Free TXQ Context 381 * iwl_hw_txq_ctx_free - Free TXQ Context
411 * 382 *
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index bc10e2ae597d..14f95238059a 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -93,210 +93,6 @@ struct iwl_mod_params iwl3945_mod_params = {
93 /* the rest are 0 by default */ 93 /* the rest are 0 by default */
94}; 94};
95 95
96/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
97 * DMA services
98 *
99 * Theory of operation
100 *
101 * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
102 * of buffer descriptors, each of which points to one or more data buffers for
103 * the device to read from or fill. Driver and device exchange status of each
104 * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty
105 * entries in each circular buffer, to protect against confusing empty and full
106 * queue states.
107 *
108 * The device reads or writes the data in the queues via the device's several
109 * DMA/FIFO channels. Each queue is mapped to a single DMA channel.
110 *
111 * For Tx queue, there are low mark and high mark limits. If, after queuing
112 * the packet for Tx, free space become < low mark, Tx queue stopped. When
113 * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
114 * Tx queue resumed.
115 *
116 * The 3945 operates with six queues: One receive queue, one transmit queue
117 * (#4) for sending commands to the device firmware, and four transmit queues
118 * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused.
119 ***************************************************/
120
121/**
122 * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes
123 */
124static int iwl3945_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
125 int count, int slots_num, u32 id)
126{
127 q->n_bd = count;
128 q->n_window = slots_num;
129 q->id = id;
130
131 /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
132 * and iwl_queue_dec_wrap are broken. */
133 BUG_ON(!is_power_of_2(count));
134
135 /* slots_num must be power-of-two size, otherwise
136 * get_cmd_index is broken. */
137 BUG_ON(!is_power_of_2(slots_num));
138
139 q->low_mark = q->n_window / 4;
140 if (q->low_mark < 4)
141 q->low_mark = 4;
142
143 q->high_mark = q->n_window / 8;
144 if (q->high_mark < 2)
145 q->high_mark = 2;
146
147 q->write_ptr = q->read_ptr = 0;
148
149 return 0;
150}
151
152/**
153 * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
154 */
155static int iwl3945_tx_queue_alloc(struct iwl_priv *priv,
156 struct iwl_tx_queue *txq, u32 id)
157{
158 struct pci_dev *dev = priv->pci_dev;
159
160 /* Driver private data, only for Tx (not command) queues,
161 * not shared with device. */
162 if (id != IWL_CMD_QUEUE_NUM) {
163 txq->txb = kmalloc(sizeof(txq->txb[0]) *
164 TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
165 if (!txq->txb) {
166 IWL_ERR(priv, "kmalloc for auxiliary BD "
167 "structures failed\n");
168 goto error;
169 }
170 } else
171 txq->txb = NULL;
172
173 /* Circular buffer of transmit frame descriptors (TFDs),
174 * shared with device */
175 txq->tfds = pci_alloc_consistent(dev,
176 sizeof(struct iwl3945_tfd) * TFD_QUEUE_SIZE_MAX,
177 &txq->q.dma_addr);
178
179 if (!txq->tfds) {
180 IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n",
181 sizeof(struct iwl3945_tfd) * TFD_QUEUE_SIZE_MAX);
182 goto error;
183 }
184 txq->q.id = id;
185
186 return 0;
187
188 error:
189 kfree(txq->txb);
190 txq->txb = NULL;
191
192 return -ENOMEM;
193}
194
195/**
196 * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue
197 */
198int iwl3945_tx_queue_init(struct iwl_priv *priv,
199 struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
200{
201 int len, i;
202 int rc = 0;
203
204 /*
205 * Alloc buffer array for commands (Tx or other types of commands).
206 * For the command queue (#4), allocate command space + one big
207 * command for scan, since scan command is very huge; the system will
208 * not have two scans at the same time, so only one is needed.
209 * For data Tx queues (all other queues), no super-size command
210 * space is needed.
211 */
212 len = sizeof(struct iwl_cmd);
213 for (i = 0; i <= slots_num; i++) {
214 if (i == slots_num) {
215 if (txq_id == IWL_CMD_QUEUE_NUM)
216 len += IWL_MAX_SCAN_SIZE;
217 else
218 continue;
219 }
220
221 txq->cmd[i] = kmalloc(len, GFP_KERNEL);
222 if (!txq->cmd[i])
223 goto err;
224 }
225
226 /* Alloc driver data array and TFD circular buffer */
227 rc = iwl3945_tx_queue_alloc(priv, txq, txq_id);
228 if (rc)
229 goto err;
230
231 txq->need_update = 0;
232
233 /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
234 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
235 BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
236
237 /* Initialize queue high/low-water, head/tail indexes */
238 iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
239
240 /* Tell device where to find queue, enable DMA channel. */
241 iwl3945_hw_tx_queue_init(priv, txq);
242
243 return 0;
244err:
245 for (i = 0; i < slots_num; i++) {
246 kfree(txq->cmd[i]);
247 txq->cmd[i] = NULL;
248 }
249
250 if (txq_id == IWL_CMD_QUEUE_NUM) {
251 kfree(txq->cmd[slots_num]);
252 txq->cmd[slots_num] = NULL;
253 }
254 return -ENOMEM;
255}
256
257/**
258 * iwl3945_tx_queue_free - Deallocate DMA queue.
259 * @txq: Transmit queue to deallocate.
260 *
261 * Empty queue by removing and destroying all BD's.
262 * Free all buffers.
263 * 0-fill, but do not free "txq" descriptor structure.
264 */
265void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
266{
267 struct iwl_queue *q = &txq->q;
268 struct pci_dev *dev = priv->pci_dev;
269 int len, i;
270
271 if (q->n_bd == 0)
272 return;
273
274 /* first, empty all BD's */
275 for (; q->write_ptr != q->read_ptr;
276 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
277 priv->cfg->ops->lib->txq_free_tfd(priv, txq);
278
279 len = sizeof(struct iwl_cmd) * q->n_window;
280 if (q->id == IWL_CMD_QUEUE_NUM)
281 len += IWL_MAX_SCAN_SIZE;
282
283 /* De-alloc array of command/tx buffers */
284 for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
285 kfree(txq->cmd[i]);
286
287 /* De-alloc circular buffer of TFDs */
288 if (txq->q.n_bd)
289 pci_free_consistent(dev, sizeof(struct iwl3945_tfd) *
290 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
291
292 /* De-alloc array of per-TFD driver data */
293 kfree(txq->txb);
294 txq->txb = NULL;
295
296 /* 0-fill queue descriptor structure */
297 memset(txq, 0, sizeof(*txq));
298}
299
300/*************** STATION TABLE MANAGEMENT **** 96/*************** STATION TABLE MANAGEMENT ****
301 * mac80211 should be examined to determine if sta_info is duplicating 97 * mac80211 should be examined to determine if sta_info is duplicating
302 * the functionality provided here 98 * the functionality provided here