Commit 1053d35f authored by Ron Rindjunsky's avatar Ron Rindjunsky Committed by John W. Linville
Browse files

iwlwifi: move NIC init and Tx queues init to iwlcore



This patch does the following:

1 - change hw_nic_init from a handler to a function
2 - move hw_nic_init function to iwlcore
3 - open a new file - iwl-tx.c
4 - move all Tx queues initialization (part of NIC init) to iwl-tx.c
5 - move iwl_rx_init, previously as part of the NIC init, to iwl-rx.c
6 - iwl4965_tfd_frame rename to iwl_tfd_frame
Signed-off-by: default avatarRon Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5a676bbe
obj-$(CONFIG_IWLCORE) += iwlcore.o
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
iwlcore-objs += iwl-rx.o
iwlcore-objs += iwl-rx.o iwl-tx.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
......
......@@ -829,7 +829,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
#define IWL49_NUM_QUEUES 16
/**
* struct iwl4965_tfd_frame_data
* struct iwl_tfd_frame_data
*
* Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
* Each buffer must be on dword boundary.
......@@ -848,7 +848,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
* 31-20: Tx buffer 2 length (bytes)
* 19- 0: Tx buffer 2 address bits [35:16]
*/
struct iwl4965_tfd_frame_data {
struct iwl_tfd_frame_data {
__le32 tb1_addr;
__le32 val1;
......@@ -878,7 +878,7 @@ struct iwl4965_tfd_frame_data {
/**
* struct iwl4965_tfd_frame
* struct iwl_tfd_frame
*
* Transmit Frame Descriptor (TFD)
*
......@@ -905,7 +905,7 @@ struct iwl4965_tfd_frame_data {
*
* A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
*/
struct iwl4965_tfd_frame {
struct iwl_tfd_frame {
__le32 val0;
/* __le32 rsvd1:24; */
/* __le32 num_tbs:5; */
......@@ -914,7 +914,7 @@ struct iwl4965_tfd_frame {
#define IWL_num_tbs_SYM val0
/* __le32 rsvd2:1; */
/* __le32 padding:2; */
struct iwl4965_tfd_frame_data pa[10];
struct iwl_tfd_frame_data pa[10];
__le32 reserved;
} __attribute__ ((packed));
......
......@@ -53,8 +53,6 @@ static struct iwl_mod_params iwl4965_mod_params = {
/* the rest are 0 by default */
};
static void iwl4965_hw_card_show_info(struct iwl_priv *priv);
#ifdef CONFIG_IWL4965_HT
static const u16 default_tid_to_tx_fifo[] = {
......@@ -372,104 +370,6 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
return ret;
}
static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int ret;
unsigned long flags;
unsigned int rb_size;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
if (priv->cfg->mod_params->amsdu_size_8K)
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
else
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
/* Stop Rx DMA */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
/* Reset driver's Rx queue write index */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
/* Tell device where to find RBD circular buffer in DRAM */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
rxq->dma_addr >> 8);
/* Tell device where in DRAM to update its Rx status */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
(priv->shared_phys +
offsetof(struct iwl4965_shared, rb_closed)) >> 4);
/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
rb_size |
/* 0x10 << 4 | */
(RX_QUEUE_SIZE_LOG <<
FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
/*
* iwl_write32(priv,CSR_INT_COAL_REG,0);
*/
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
/* Tell 4965 where to find the "keep warm" buffer */
static int iwl4965_kw_init(struct iwl_priv *priv)
{
unsigned long flags;
int rc;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc)
goto out;
iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG,
priv->kw.dma_addr >> 4);
iwl_release_nic_access(priv);
out:
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
static int iwl4965_kw_alloc(struct iwl_priv *priv)
{
struct pci_dev *dev = priv->pci_dev;
struct iwl4965_kw *kw = &priv->kw;
kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */
kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
if (!kw->v_addr)
return -ENOMEM;
return 0;
}
/**
* iwl4965_kw_free - Free the "keep warm" buffer
*/
static void iwl4965_kw_free(struct iwl_priv *priv)
{
struct pci_dev *dev = priv->pci_dev;
struct iwl4965_kw *kw = &priv->kw;
if (kw->v_addr) {
pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
memset(kw, 0, sizeof(*kw));
}
}
static int iwl4965_disable_tx_fifo(struct iwl_priv *priv)
{
unsigned long flags;
......@@ -491,65 +391,6 @@ static int iwl4965_disable_tx_fifo(struct iwl_priv *priv)
return 0;
}
/**
* iwl4965_txq_ctx_reset - Reset TX queue context
* Destroys all DMA structures and initialise them again
*
* @param priv
* @return error code
*/
static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
{
int rc = 0;
int txq_id, slots_num;
iwl4965_kw_free(priv);
/* Free all tx/cmd queues and keep-warm buffer */
iwl4965_hw_txq_ctx_free(priv);
/* Alloc keep-warm buffer */
rc = iwl4965_kw_alloc(priv);
if (rc) {
IWL_ERROR("Keep Warm allocation failed");
goto error_kw;
}
/* Turn off all Tx DMA fifos */
rc = priv->cfg->ops->lib->disable_tx_fifo(priv);
if (unlikely(rc))
goto error_reset;
/* Tell 4965 where to find the keep-warm buffer */
rc = iwl4965_kw_init(priv);
if (rc) {
IWL_ERROR("kw_init failed\n");
goto error_reset;
}
/* Alloc and init all (default 16) Tx queues,
* including the command queue (#4) */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
txq_id);
if (rc) {
IWL_ERROR("Tx %d queue init failed\n", txq_id);
goto error;
}
}
return rc;
error:
iwl4965_hw_txq_ctx_free(priv);
error_reset:
iwl4965_kw_free(priv);
error_kw:
return rc;
}
static int iwl4965_apm_init(struct iwl_priv *priv)
{
unsigned long flags;
......@@ -633,58 +474,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
int iwl4965_hw_nic_init(struct iwl_priv *priv)
{
unsigned long flags;
struct iwl_rx_queue *rxq = &priv->rxq;
int ret;
/* nic_init */
priv->cfg->ops->lib->apm_ops.init(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
spin_unlock_irqrestore(&priv->lock, flags);
ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
priv->cfg->ops->lib->apm_ops.config(priv);
iwl4965_hw_card_show_info(priv);
/* end nic_init */
/* Allocate the RX queue, or reset if it is already allocated */
if (!rxq->bd) {
ret = iwl_rx_queue_alloc(priv);
if (ret) {
IWL_ERROR("Unable to initialize Rx queue\n");
return -ENOMEM;
}
} else
iwl_rx_queue_reset(priv, rxq);
iwl_rx_replenish(priv);
iwl4965_rx_init(priv, rxq);
spin_lock_irqsave(&priv->lock, flags);
rxq->need_update = 1;
iwl_rx_queue_update_write_ptr(priv, rxq);
spin_unlock_irqrestore(&priv->lock, flags);
/* Allocate and init all Tx and Command queues */
ret = iwl4965_txq_ctx_reset(priv);
if (ret)
return ret;
set_bit(STATUS_INIT, &priv->status);
return 0;
}
int iwl4965_hw_nic_stop_master(struct iwl_priv *priv)
{
int rc = 0;
......@@ -745,7 +534,7 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
}
/* Deallocate memory for all Tx queues */
iwl4965_hw_txq_ctx_free(priv);
iwl_hw_txq_ctx_free(priv);
}
int iwl4965_hw_nic_reset(struct iwl_priv *priv)
......@@ -1199,82 +988,6 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
return 0;
}
/**
* iwl4965_hw_txq_ctx_free - Free TXQ Context
*
* Destroy all TX DMA queues and structures
*/
void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv)
{
int txq_id;
/* Tx queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
iwl4965_tx_queue_free(priv, &priv->txq[txq_id]);
/* Keep-warm buffer */
iwl4965_kw_free(priv);
}
/**
* iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
*
* Does NOT advance any TFD circular buffer read/write indexes
* Does NOT free the TFD itself (which is within circular buffer)
*/
int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
{
struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0];
struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
struct pci_dev *dev = priv->pci_dev;
int i;
int counter = 0;
int index, is_odd;
/* Host command buffers stay mapped in memory, nothing to clean */
if (txq->q.id == IWL_CMD_QUEUE_NUM)
return 0;
/* Sanity check on number of chunks */
counter = IWL_GET_BITS(*bd, num_tbs);
if (counter > MAX_NUM_OF_TBS) {
IWL_ERROR("Too many chunks: %i\n", counter);
/* @todo issue fatal error, it is quite serious situation */
return 0;
}
/* Unmap chunks, if any.
* TFD info for odd chunks is different format than for even chunks. */
for (i = 0; i < counter; i++) {
index = i / 2;
is_odd = i & 0x1;
if (is_odd)
pci_unmap_single(
dev,
IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
(IWL_GET_BITS(bd->pa[index],
tb2_addr_hi20) << 16),
IWL_GET_BITS(bd->pa[index], tb2_len),
PCI_DMA_TODEVICE);
else if (i > 0)
pci_unmap_single(dev,
le32_to_cpu(bd->pa[index].tb1_addr),
IWL_GET_BITS(bd->pa[index], tb1_len),
PCI_DMA_TODEVICE);
/* Free SKB, if any, for this chunk */
if (txq->txb[txq->q.read_ptr].skb[i]) {
struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
dev_kfree_skb(skb);
txq->txb[txq->q.read_ptr].skb[i] = NULL;
}
}
return 0;
}
/* set card power command */
static int iwl4965_set_power(struct iwl_priv *priv,
void *cmd)
......@@ -2240,46 +1953,11 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
return (sizeof(*tx_beacon_cmd) + frame_size);
}
/*
* Tell 4965 where to find circular buffer of Tx Frame Descriptors for
* given Tx queue, and enable the DMA channel used for that queue.
*
* 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
* channels supported in hardware.
*/
int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
{
int rc;
unsigned long flags;
int txq_id = txq->q.id;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
/* Circular buffer (TFD queue in DRAM) physical base address */
iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8);
/* Enable DMA channel, using same id as for TFD queue */
iwl_write_direct32(
priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
dma_addr_t addr, u16 len)
{
int index, is_odd;
struct iwl4965_tfd_frame *tfd = ptr;
struct iwl_tfd_frame *tfd = ptr;
u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
/* Each TFD can point to a maximum 20 Tx buffers */
......@@ -2309,18 +1987,6 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
return 0;
}
static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
{
u16 hw_version = iwl_eeprom_query16(priv, EEPROM_4965_BOARD_REVISION);
IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
((hw_version >> 8) & 0x0F),
((hw_version >> 8) >> 4), (hw_version & 0x00FF));
IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
&priv->eeprom[EEPROM_4965_BOARD_PBA]);
}
static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
{
priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
......@@ -4054,7 +3720,6 @@ static struct iwl_lib_ops iwl4965_lib = {
.alloc_shared_mem = iwl4965_alloc_shared_mem,
.free_shared_mem = iwl4965_free_shared_mem,
.txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
.hw_nic_init = iwl4965_hw_nic_init,
.disable_tx_fifo = iwl4965_disable_tx_fifo,
.rx_handler_setup = iwl4965_rx_handler_setup,
.is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
......
......@@ -121,6 +121,101 @@ void iwl_hw_detect(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_hw_detect);
/* Tell nic where to find the "keep warm" buffer */
int iwl_kw_init(struct iwl_priv *priv)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret)
goto out;
iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG,
priv->kw.dma_addr >> 4);
iwl_release_nic_access(priv);
out:
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
int iwl_kw_alloc(struct iwl_priv *priv)
{
struct pci_dev *dev = priv->pci_dev;
struct iwl4965_kw *kw = &priv->kw;
kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */
kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
if (!kw->v_addr)
return -ENOMEM;
return 0;
}
/**
* iwl_kw_free - Free the "keep warm" buffer
*/
void iwl_kw_free(struct iwl_priv *priv)
{
struct pci_dev *dev = priv->pci_dev;
struct iwl4965_kw *kw = &priv->kw;
if (kw->v_addr) {
pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
memset(kw, 0, sizeof(*kw));
}
}
int iwl_hw_nic_init(struct iwl_priv *priv)
{
unsigned long flags;
struct iwl_rx_queue *rxq = &priv->rxq;
int ret;
/* nic_init */
priv->cfg->ops->lib->apm_ops.init(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
spin_unlock_irqrestore(&priv->lock, flags);
ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
priv->cfg->ops->lib->apm_ops.config(priv);
/* Allocate the RX queue, or reset if it is already allocated */
if (!rxq->bd) {
ret = iwl_rx_queue_alloc(priv);
if (ret) {
IWL_ERROR("Unable to initialize Rx queue\n");
return -ENOMEM;
}
} else
iwl_rx_queue_reset(priv, rxq);
iwl_rx_replenish(priv);
iwl_rx_init(priv, rxq);
spin_lock_irqsave(&priv->lock, flags);
rxq->need_update = 1;
iwl_rx_queue_update_write_ptr(priv, rxq);
spin_unlock_irqrestore(&priv->lock, flags);
/* Allocate and init all Tx and Command queues */
ret = iwl_txq_ctx_reset(priv);
if (ret)
return ret;
set_bit(STATUS_INIT, &priv->status);
return 0;
}
EXPORT_SYMBOL(iwl_hw_nic_init);
/**
* iwlcore_clear_stations_table - Clear the driver's station table
*
......
......@@ -108,8 +108,6 @@ struct iwl_lib_ops {
u16 byte_cnt);
/* setup Rx handler */
void (*rx_handler_setup)(struct iwl_priv *priv);
/* nic init */
int (*hw_nic_init)(struct iwl_priv *priv);
/* nic Tx fifo handling */
int (*disable_tx_fifo)(struct iwl_priv *priv);
/* alive notification */
......@@ -178,6 +176,12 @@ int iwl_setup(struct iwl_priv *priv);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
struct ieee80211_ht_info *sta_ht_inf);
int iwl_hw_nic_init(struct iwl_priv *priv);
/* "keep warm" functions */
int iwl_kw_init(struct iwl_priv *priv);
int iwl_kw_alloc(struct iwl_priv *priv);
void iwl_kw_free(struct iwl_priv *priv);
/*****************************************************
* RX
......@@ -189,11 +193,20 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl_rx_queue *q);
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
/* FIXME: remove when TX is moved to iwl core */
int iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv);
/*****************************************************
* TX
******************************************************/
int iwl_txq_ctx_reset(struct iwl_priv *priv);
/* FIXME: remove when free Tx is fully merged into iwlcore */
int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq);
void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
/*****************************************************
* S e n d i n g H o s t C o m m a n d s *
*****************************************************/
......
......@@ -138,7 +138,7 @@ struct iwl4965_tx_info {
*/
struct iwl4965_tx_queue {
struct iwl4965_queue q;
struct iwl4965_tfd_frame *bd;
struct iwl_tfd_frame *bd;
struct iwl_cmd *cmd;
dma_addr_t dma_addr_cmd;
struct iwl4965_tx_info *txb;
......@@ -649,9 +649,6 @@ extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header);
extern int iwl4965_calc_db_from_ratio(int sig_ratio);
extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);