提交 a55360e4 编写于 作者: T Tomas Winkler 提交者: John W. Linville

iwlwifi: move RX code to iwl-rx.c

This patch moves partialy rx code into iwl-rx.c as part of iwlcore.
The second part of the code can be merged only with moving of tx
code as well.
Signed-off-by: NTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 0d0b2c1c
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-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
......
......@@ -372,7 +372,7 @@ 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 iwl4965_rx_queue *rxq)
static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int ret;
unsigned long flags;
......@@ -625,7 +625,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
int iwl4965_hw_nic_init(struct iwl_priv *priv)
{
unsigned long flags;
struct iwl4965_rx_queue *rxq = &priv->rxq;
struct iwl_rx_queue *rxq = &priv->rxq;
int ret;
/* nic_init */
......@@ -645,22 +645,22 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv)
/* Allocate the RX queue, or reset if it is already allocated */
if (!rxq->bd) {
ret = iwl4965_rx_queue_alloc(priv);
ret = iwl_rx_queue_alloc(priv);
if (ret) {
IWL_ERROR("Unable to initialize Rx queue\n");
return -ENOMEM;
}
} else
iwl4965_rx_queue_reset(priv, rxq);
iwl_rx_queue_reset(priv, rxq);
iwl4965_rx_replenish(priv);
iwl_rx_replenish(priv);
iwl4965_rx_init(priv, rxq);
spin_lock_irqsave(&priv->lock, flags);
rxq->need_update = 1;
iwl4965_rx_queue_update_write_ptr(priv, rxq);
iwl_rx_queue_update_write_ptr(priv, rxq);
spin_unlock_irqrestore(&priv->lock, flags);
......@@ -2516,7 +2516,8 @@ static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
priv->last_rx_noise);
}
void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
void iwl4965_hw_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
int change;
......@@ -2803,7 +2804,7 @@ static u32 iwl4965_translate_rx_status(u32 decrypt_in)
static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
int include_phy,
struct iwl4965_rx_mem_buffer *rxb,
struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats)
{
struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
......@@ -3109,7 +3110,7 @@ static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv,
/* Called for REPLY_RX (legacy ABG frames), or
* REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb)
struct iwl_rx_mem_buffer *rxb)
{
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
......@@ -3278,7 +3279,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
* This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb)
struct iwl_rx_mem_buffer *rxb)
{
struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
priv->last_phy_res[0] = 1;
......@@ -3286,7 +3287,7 @@ static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
sizeof(struct iwl4965_rx_phy_res));
}
static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb)
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
......@@ -3495,7 +3496,7 @@ static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
* of frames sent via aggregation.
*/
static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb)
struct iwl_rx_mem_buffer *rxb)
{
struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
......
......@@ -173,6 +173,21 @@ int iwl_set_rxon_channel(struct iwl_priv *priv,
void iwlcore_free_geos(struct iwl_priv *priv);
int iwl_setup(struct iwl_priv *priv);
/*****************************************************
* RX
******************************************************/
void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwl_rx_queue_alloc(struct iwl_priv *priv);
void iwl_rx_handle(struct iwl_priv *priv);
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);
/* 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);
/*****************************************************
* S e n d i n g H o s t C o m m a n d s *
*****************************************************/
......@@ -265,4 +280,5 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
return priv->cfg->ops->hcmd->rxon_assoc(priv);
}
#endif /* __iwl_core_h__ */
......@@ -91,7 +91,7 @@ extern struct iwl_cfg iwl5350_agn_cfg;
#define DEFAULT_SHORT_RETRY_LIMIT 7U
#define DEFAULT_LONG_RETRY_LIMIT 4U
struct iwl4965_rx_mem_buffer {
struct iwl_rx_mem_buffer {
dma_addr_t dma_addr;
struct sk_buff *skb;
struct list_head list;
......@@ -358,7 +358,7 @@ struct iwl_host_cmd {
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
/**
* struct iwl4965_rx_queue - Rx queue
* struct iwl_rx_queue - Rx queue
* @processed: Internal index to last handled Rx packet
* @read: Shared index to newest available Rx buffer
* @write: Shared index to oldest written Rx packet
......@@ -367,13 +367,13 @@ struct iwl_host_cmd {
* @rx_used: List of Rx buffers with no SKB
* @need_update: flag to indicate we need to update read/write index
*
* NOTE: rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers
* NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
*/
struct iwl4965_rx_queue {
struct iwl_rx_queue {
__le32 *bd;
dma_addr_t dma_addr;
struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE];
struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
u32 processed;
u32 read;
u32 write;
......@@ -643,26 +643,20 @@ extern int iwl4965_is_network_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header);
extern int iwl4965_power_init_handle(struct iwl_priv *priv);
extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb,
struct iwl_rx_mem_buffer *rxb,
void *data, short len,
struct ieee80211_rx_status *stats,
u16 phy_flags);
extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header);
extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv);
extern void iwl4965_rx_queue_reset(struct iwl_priv *priv,
struct iwl4965_rx_queue *rxq);
extern int iwl4965_calc_db_from_ratio(int sig_ratio);
extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);
extern int iwl4965_tx_queue_init(struct iwl_priv *priv,
struct iwl4965_tx_queue *txq, int count, u32 id);
extern void iwl4965_rx_replenish(void *data);
extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq);
extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
const u8 *dest, int left);
extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl4965_rx_queue *q);
extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
......@@ -722,7 +716,7 @@ extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv);
extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb);
struct iwl_rx_mem_buffer *rxb);
extern void iwl4965_disable_events(struct iwl_priv *priv);
extern int iwl4965_get_temperature(const struct iwl_priv *priv);
......@@ -960,7 +954,7 @@ struct iwl_priv {
bool add_radiotap;
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb);
struct iwl_rx_mem_buffer *rxb);
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
......@@ -1077,7 +1071,7 @@ struct iwl_priv {
int activity_timer_active;
/* Rx and Tx DMA processing queues */
struct iwl4965_rx_queue rxq;
struct iwl_rx_queue rxq;
struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES];
unsigned long txq_ctx_active_msk;
struct iwl4965_kw kw; /* keep warm address */
......
/******************************************************************************
*
* Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* James P. Ketrenos <ipw2100-admin@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
#include <net/mac80211.h>
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
/************************** RX-FUNCTIONS ****************************/
/*
* Rx theory of operation
*
* Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
* each of which point to Receive Buffers to be filled by the NIC. These get
* used not only for Rx frames, but for any command response or notification
* from the NIC. The driver and NIC manage the Rx buffers by means
* of indexes into the circular buffer.
*
* Rx Queue Indexes
* The host/firmware share two index registers for managing the Rx buffers.
*
* The READ index maps to the first position that the firmware may be writing
* to -- the driver can read up to (but not including) this position and get
* good data.
* The READ index is managed by the firmware once the card is enabled.
*
* The WRITE index maps to the last position the driver has read from -- the
* position preceding WRITE is the last slot the firmware can place a packet.
*
* The queue is empty (no good data) if WRITE = READ - 1, and is full if
* WRITE = READ.
*
* During initialization, the host sets up the READ queue position to the first
* INDEX position, and WRITE to the last (READ - 1 wrapped)
*
* When the firmware places a packet in a buffer, it will advance the READ index
* and fire the RX interrupt. The driver can then query the READ index and
* process as many packets as possible, moving the WRITE index forward as it
* resets the Rx queue buffers with new memory.
*
* The management in the driver is as follows:
* + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
* iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
* to replenish the iwl->rxq->rx_free.
* + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
* iwl->rxq is replenished and the READ INDEX is updated (updating the
* 'processed' and 'read' driver indexes as well)
* + A received packet is processed and handed to the kernel network stack,
* detached from the iwl->rxq. The driver 'processed' index is updated.
* + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
* list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
* INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
* were enough free buffers and RX_STALLED is set it is cleared.
*
*
* Driver sequence:
*
* iwl_rx_queue_alloc() Allocates rx_free
* iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
* iwl_rx_queue_restock
* iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
* queue, updates firmware pointers, and updates
* the WRITE index. If insufficient rx_free buffers
* are available, schedules iwl_rx_replenish
*
* -- enable interrupts --
* ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
* READ INDEX, detaching the SKB from the pool.
* Moves the packet buffer from queue to rx_used.
* Calls iwl_rx_queue_restock to refill any empty
* slots.
* ...
*
*/
/**
* iwl_rx_queue_space - Return number of free slots available in queue.
*/
int iwl_rx_queue_space(const struct iwl_rx_queue *q)
{
int s = q->read - q->write;
if (s <= 0)
s += RX_QUEUE_SIZE;
/* keep some buffer to not confuse full and empty queue */
s -= 2;
if (s < 0)
s = 0;
return s;
}
EXPORT_SYMBOL(iwl_rx_queue_space);
/**
* iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
*/
int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
{
u32 reg = 0;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
if (q->need_update == 0)
goto exit_unlock;
/* If power-saving is in use, make sure device is awake */
if (test_bit(STATUS_POWER_PMI, &priv->status)) {
reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
iwl_set_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
goto exit_unlock;
}
ret = iwl_grab_nic_access(priv);
if (ret)
goto exit_unlock;
/* Device expects a multiple of 8 */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
q->write & ~0x7);
iwl_release_nic_access(priv);
/* Else device is assumed to be awake */
} else
/* Device expects a multiple of 8 */
iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
q->need_update = 0;
exit_unlock:
spin_unlock_irqrestore(&q->lock, flags);
return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
/**
* iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
*/
static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
dma_addr_t dma_addr)
{
return cpu_to_le32((u32)(dma_addr >> 8));
}
/**
* iwl_rx_queue_restock - refill RX queue from pre-allocated pool
*
* If there are slots in the RX queue that need to be restocked,
* and we have free pre-allocated buffers, fill the ranks as much
* as we can, pulling from rx_free.
*
* This moves the 'write' index forward to catch up with 'processed', and
* also updates the memory address in the firmware to reference the new
* target buffer.
*/
int iwl_rx_queue_restock(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
int write;
int ret = 0;
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write & ~0x7;
while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
/* Get next free Rx buffer, remove from free list */
element = rxq->rx_free.next;
rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */
rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--;
}
spin_unlock_irqrestore(&rxq->lock, flags);
/* If the pre-allocated buffer pool is dropping low, schedule to
* refill it */
if (rxq->free_count <= RX_LOW_WATERMARK)
queue_work(priv->workqueue, &priv->rx_replenish);
/* If we've added more space for the firmware to place data, tell it.
* Increment device's write pointer in multiples of 8. */
if ((write != (rxq->write & ~0x7))
|| (abs(rxq->write - rxq->read) > 7)) {
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
ret = iwl_rx_queue_update_write_ptr(priv, rxq);
}
return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_restock);
/**
* iwl_rx_replenish - Move all used packet from rx_used to rx_free
*
* When moving to rx_free an SKB is allocated for the slot.
*
* Also restock the Rx queue via iwl_rx_queue_restock.
* This is called as a scheduled work item (except for during initialization)
*/
void iwl_rx_allocate(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
spin_lock_irqsave(&rxq->lock, flags);
while (!list_empty(&rxq->rx_used)) {
element = rxq->rx_used.next;
rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
/* Alloc a new receive buffer */
rxb->skb = alloc_skb(priv->hw_params.rx_buf_size,
__GFP_NOWARN | GFP_ATOMIC);
if (!rxb->skb) {
if (net_ratelimit())
printk(KERN_CRIT DRV_NAME
": Can not allocate SKB buffers\n");
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
break;
}
priv->alloc_rxb_skb++;
list_del(element);
/* Get physical address of RB/SKB */
rxb->dma_addr =
pci_map_single(priv->pci_dev, rxb->skb->data,
priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
}
spin_unlock_irqrestore(&rxq->lock, flags);
}
EXPORT_SYMBOL(iwl_rx_allocate);
void iwl_rx_replenish(struct iwl_priv *priv)
{
unsigned long flags;
iwl_rx_allocate(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_rx_queue_restock(priv);
spin_unlock_irqrestore(&priv->lock, flags);
}
EXPORT_SYMBOL(iwl_rx_replenish);
/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
* If an SKB has been detached, the POOL needs to have its SKB set to NULL
* This free routine walks the list of POOL entries and if SKB is set to
* non NULL it is unmapped and freed
*/
void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxq->pool[i].skb);
}
}
pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
rxq->bd = NULL;
}
EXPORT_SYMBOL(iwl_rx_queue_free);
int iwl_rx_queue_alloc(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct pci_dev *dev = priv->pci_dev;
int i;
spin_lock_init(&rxq->lock);
INIT_LIST_HEAD(&rxq->rx_free);
INIT_LIST_HEAD(&rxq->rx_used);
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
if (!rxq->bd)
return -ENOMEM;
/* Fill the rx_used queue with _all_ of the Rx buffers */
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
rxq->free_count = 0;
rxq->need_update = 0;
return 0;
}
EXPORT_SYMBOL(iwl_rx_queue_alloc);
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
unsigned long flags;
int i;
spin_lock_irqsave(&rxq->lock, flags);
INIT_LIST_HEAD(&rxq->rx_free);
INIT_LIST_HEAD(&rxq->rx_used);
/* Fill the rx_used queue with _all_ of the Rx buffers */
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
priv->alloc_rxb_skb--;
dev_kfree_skb(rxq->pool[i].skb);
rxq->pool[i].skb = NULL;
}
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
}
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
EXPORT_SYMBOL(iwl_rx_queue_reset);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册