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>
This commit is contained in:
Samuel Ortiz
2009-01-23 13:45:14 -08:00
committed by John W. Linville
parent 59606ffa91
commit a8e74e2774
8 changed files with 60 additions and 246 deletions

View File

@@ -93,210 +93,6 @@ struct iwl_mod_params iwl3945_mod_params = {
/* 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 ****
* mac80211 should be examined to determine if sta_info is duplicating
* the functionality provided here