|
@@ -93,210 +93,6 @@ struct iwl_mod_params iwl3945_mod_params = {
|
|
/* the rest are 0 by default */
|
|
/* the rest are 0 by default */
|
|
};
|
|
};
|
|
|
|
|
|
-/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
|
|
|
|
- * DMA services
|
|
|
|
- *
|
|
|
|
- * Theory of operation
|
|
|
|
- *
|
|
|
|
- * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
|
|
|
|
- * of buffer descriptors, each of which points to one or more data buffers for
|
|
|
|
- * the device to read from or fill. Driver and device exchange status of each
|
|
|
|
- * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty
|
|
|
|
- * entries in each circular buffer, to protect against confusing empty and full
|
|
|
|
- * queue states.
|
|
|
|
- *
|
|
|
|
- * The device reads or writes the data in the queues via the device's several
|
|
|
|
- * DMA/FIFO channels. Each queue is mapped to a single DMA channel.
|
|
|
|
- *
|
|
|
|
- * For Tx queue, there are low mark and high mark limits. If, after queuing
|
|
|
|
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
|
|
|
|
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
|
|
|
|
- * Tx queue resumed.
|
|
|
|
- *
|
|
|
|
- * The 3945 operates with six queues: One receive queue, one transmit queue
|
|
|
|
- * (#4) for sending commands to the device firmware, and four transmit queues
|
|
|
|
- * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused.
|
|
|
|
- ***************************************************/
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes
|
|
|
|
- */
|
|
|
|
-static int iwl3945_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
|
|
|
|
- int count, int slots_num, u32 id)
|
|
|
|
-{
|
|
|
|
- q->n_bd = count;
|
|
|
|
- q->n_window = slots_num;
|
|
|
|
- q->id = id;
|
|
|
|
-
|
|
|
|
- /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
|
|
|
|
- * and iwl_queue_dec_wrap are broken. */
|
|
|
|
- BUG_ON(!is_power_of_2(count));
|
|
|
|
-
|
|
|
|
- /* slots_num must be power-of-two size, otherwise
|
|
|
|
- * get_cmd_index is broken. */
|
|
|
|
- BUG_ON(!is_power_of_2(slots_num));
|
|
|
|
-
|
|
|
|
- q->low_mark = q->n_window / 4;
|
|
|
|
- if (q->low_mark < 4)
|
|
|
|
- q->low_mark = 4;
|
|
|
|
-
|
|
|
|
- q->high_mark = q->n_window / 8;
|
|
|
|
- if (q->high_mark < 2)
|
|
|
|
- q->high_mark = 2;
|
|
|
|
-
|
|
|
|
- q->write_ptr = q->read_ptr = 0;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
|
|
|
|
- */
|
|
|
|
-static int iwl3945_tx_queue_alloc(struct iwl_priv *priv,
|
|
|
|
- struct iwl_tx_queue *txq, u32 id)
|
|
|
|
-{
|
|
|
|
- struct pci_dev *dev = priv->pci_dev;
|
|
|
|
-
|
|
|
|
- /* Driver private data, only for Tx (not command) queues,
|
|
|
|
- * not shared with device. */
|
|
|
|
- if (id != IWL_CMD_QUEUE_NUM) {
|
|
|
|
- txq->txb = kmalloc(sizeof(txq->txb[0]) *
|
|
|
|
- TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
|
|
|
|
- if (!txq->txb) {
|
|
|
|
- IWL_ERR(priv, "kmalloc for auxiliary BD "
|
|
|
|
- "structures failed\n");
|
|
|
|
- goto error;
|
|
|
|
- }
|
|
|
|
- } else
|
|
|
|
- txq->txb = NULL;
|
|
|
|
-
|
|
|
|
- /* Circular buffer of transmit frame descriptors (TFDs),
|
|
|
|
- * shared with device */
|
|
|
|
- txq->tfds = pci_alloc_consistent(dev,
|
|
|
|
- sizeof(struct iwl3945_tfd) * TFD_QUEUE_SIZE_MAX,
|
|
|
|
- &txq->q.dma_addr);
|
|
|
|
-
|
|
|
|
- if (!txq->tfds) {
|
|
|
|
- IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n",
|
|
|
|
- sizeof(struct iwl3945_tfd) * TFD_QUEUE_SIZE_MAX);
|
|
|
|
- goto error;
|
|
|
|
- }
|
|
|
|
- txq->q.id = id;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- error:
|
|
|
|
- kfree(txq->txb);
|
|
|
|
- txq->txb = NULL;
|
|
|
|
-
|
|
|
|
- return -ENOMEM;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue
|
|
|
|
- */
|
|
|
|
-int iwl3945_tx_queue_init(struct iwl_priv *priv,
|
|
|
|
- struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
|
|
|
|
-{
|
|
|
|
- int len, i;
|
|
|
|
- int rc = 0;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Alloc buffer array for commands (Tx or other types of commands).
|
|
|
|
- * For the command queue (#4), allocate command space + one big
|
|
|
|
- * command for scan, since scan command is very huge; the system will
|
|
|
|
- * not have two scans at the same time, so only one is needed.
|
|
|
|
- * For data Tx queues (all other queues), no super-size command
|
|
|
|
- * space is needed.
|
|
|
|
- */
|
|
|
|
- len = sizeof(struct iwl_cmd);
|
|
|
|
- for (i = 0; i <= slots_num; i++) {
|
|
|
|
- if (i == slots_num) {
|
|
|
|
- if (txq_id == IWL_CMD_QUEUE_NUM)
|
|
|
|
- len += IWL_MAX_SCAN_SIZE;
|
|
|
|
- else
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- txq->cmd[i] = kmalloc(len, GFP_KERNEL);
|
|
|
|
- if (!txq->cmd[i])
|
|
|
|
- goto err;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Alloc driver data array and TFD circular buffer */
|
|
|
|
- rc = iwl3945_tx_queue_alloc(priv, txq, txq_id);
|
|
|
|
- if (rc)
|
|
|
|
- goto err;
|
|
|
|
-
|
|
|
|
- txq->need_update = 0;
|
|
|
|
-
|
|
|
|
- /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
|
|
|
|
- * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
|
|
|
|
- BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
|
|
|
|
-
|
|
|
|
- /* Initialize queue high/low-water, head/tail indexes */
|
|
|
|
- iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
|
|
|
|
-
|
|
|
|
- /* Tell device where to find queue, enable DMA channel. */
|
|
|
|
- iwl3945_hw_tx_queue_init(priv, txq);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-err:
|
|
|
|
- for (i = 0; i < slots_num; i++) {
|
|
|
|
- kfree(txq->cmd[i]);
|
|
|
|
- txq->cmd[i] = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (txq_id == IWL_CMD_QUEUE_NUM) {
|
|
|
|
- kfree(txq->cmd[slots_num]);
|
|
|
|
- txq->cmd[slots_num] = NULL;
|
|
|
|
- }
|
|
|
|
- return -ENOMEM;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * iwl3945_tx_queue_free - Deallocate DMA queue.
|
|
|
|
- * @txq: Transmit queue to deallocate.
|
|
|
|
- *
|
|
|
|
- * Empty queue by removing and destroying all BD's.
|
|
|
|
- * Free all buffers.
|
|
|
|
- * 0-fill, but do not free "txq" descriptor structure.
|
|
|
|
- */
|
|
|
|
-void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
|
|
|
|
-{
|
|
|
|
- struct iwl_queue *q = &txq->q;
|
|
|
|
- struct pci_dev *dev = priv->pci_dev;
|
|
|
|
- int len, i;
|
|
|
|
-
|
|
|
|
- if (q->n_bd == 0)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- /* first, empty all BD's */
|
|
|
|
- for (; q->write_ptr != q->read_ptr;
|
|
|
|
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
|
|
|
|
- priv->cfg->ops->lib->txq_free_tfd(priv, txq);
|
|
|
|
-
|
|
|
|
- len = sizeof(struct iwl_cmd) * q->n_window;
|
|
|
|
- if (q->id == IWL_CMD_QUEUE_NUM)
|
|
|
|
- len += IWL_MAX_SCAN_SIZE;
|
|
|
|
-
|
|
|
|
- /* De-alloc array of command/tx buffers */
|
|
|
|
- for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
|
|
|
|
- kfree(txq->cmd[i]);
|
|
|
|
-
|
|
|
|
- /* De-alloc circular buffer of TFDs */
|
|
|
|
- if (txq->q.n_bd)
|
|
|
|
- pci_free_consistent(dev, sizeof(struct iwl3945_tfd) *
|
|
|
|
- txq->q.n_bd, txq->tfds, txq->q.dma_addr);
|
|
|
|
-
|
|
|
|
- /* De-alloc array of per-TFD driver data */
|
|
|
|
- kfree(txq->txb);
|
|
|
|
- txq->txb = NULL;
|
|
|
|
-
|
|
|
|
- /* 0-fill queue descriptor structure */
|
|
|
|
- memset(txq, 0, sizeof(*txq));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*************** STATION TABLE MANAGEMENT ****
|
|
/*************** STATION TABLE MANAGEMENT ****
|
|
* mac80211 should be examined to determine if sta_info is duplicating
|
|
* mac80211 should be examined to determine if sta_info is duplicating
|
|
* the functionality provided here
|
|
* the functionality provided here
|