Search Linux Wireless

Re: kernel BUG at drivers/net/wireless/iwlwifi/iwl3945-base.c:3127!

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Jason,

During our internal validation we found that the patch I sent to you
broke fragmentation on 5100 hardware. It took me a while to figure out
the problem and I was able to create a new patch last week. This patch
has just passed our internal validation so I will send it upstream asap.

Reinette

On Mon, 2009-04-20 at 18:41 -0700, Jason Andryuk wrote:
> Reinette,
> 
> This patch never made it to wireless-testing.
> 
> Jason
> 
> On Tue, Mar 31, 2009 at 6:22 PM, reinette chatre
> <reinette.chatre@xxxxxxxxx> wrote:
> > I addressed these issues as well as a few more that I uncovered while
> > digging into this.
> >
> > Could you please try this patch?
> >
> >
> > >From c152258435c047dfd7423e0279781c3fcb2f4e71 Mon Sep 17 00:00:00 2001
> > From: Reinette Chatre <reinette.chatre@xxxxxxxxx>
> > Date: Tue, 31 Mar 2009 14:16:05 -0700
> > Subject: [PATCH] iwlwifi: DMA fixes
> >
> > A few issues wrt DMA were uncovered when using the driver with swiotlb.
> > - driver should not use memory after it has been mapped
> > - iwl3945's RX queue management cannot use all of iwlagn because
> >  the size of the RX buffer is different. Revert back to using
> >  iwl3945 specific routines that map/unmap memory.
> > - no need to "dma_syn_single_range_for_cpu" followed by pci_unmap_single,
> >  we can just call pci_unmap_single initially
> > - only map the memory area that will be used by device. this is especially
> >  relevant to the mapping of iwl_cmd. we should not map the entire
> >  structure because the meta data at the beginning of structure contains
> >  the address to be used later for unmapping. If the address to be used for
> >  unmapping is stored in mapped data it creates a problem.
> > - ensure that _if_ memory needs to be modified after it is mapped that we
> >  call _sync_single_for_cpu first, and then release it back to device with
> >  _sync_single_for_device
> > - we mapped the wrong length of data for host commands, with mapped length
> >  differing with length provided to device, fix that.
> >
> > Thanks to Jason Andryuk <jandryuk@xxxxxxxxx> for significant bisecting
> > help to find these issues.
> >
> > Signed-off-by: Reinette Chatre <reinette.chatre@xxxxxxxxx>
> > CC: Jason Andryuk <jandryuk@xxxxxxxxx>
> > ---
> >  drivers/net/wireless/iwlwifi/iwl-3945.c     |    2 +-
> >  drivers/net/wireless/iwlwifi/iwl-3945.h     |    1 +
> >  drivers/net/wireless/iwlwifi/iwl-agn.c      |   11 +--
> >  drivers/net/wireless/iwlwifi/iwl-dev.h      |    4 +
> >  drivers/net/wireless/iwlwifi/iwl-tx.c       |   93 ++++++++++--------
> >  drivers/net/wireless/iwlwifi/iwl3945-base.c |  144 +++++++++++++++++++--------
> >  6 files changed, 161 insertions(+), 94 deletions(-)
> >
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
> > index d03f553..05cd499 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-3945.c
> > +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
> > @@ -1192,7 +1192,7 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv)
> >                        return -ENOMEM;
> >                }
> >        } else
> > -               iwl_rx_queue_reset(priv, rxq);
> > +               iwl3945_rx_queue_reset(priv, rxq);
> >
> >        iwl3945_rx_replenish(priv);
> >
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
> > index 29bc0d2..3213a63 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-3945.h
> > +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
> > @@ -214,6 +214,7 @@ extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
> >  extern int iwl3945_tx_queue_init(struct iwl_priv *priv,
> >                             struct iwl_tx_queue *txq, int count, u32 id);
> >  extern void iwl3945_rx_replenish(void *data);
> > +extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
> >  extern void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
> >  extern int iwl3945_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
> >                            const void *data);
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
> > index 51f6a01..ea859f6 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-agn.c
> > +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
> > @@ -976,11 +976,9 @@ void iwl_rx_handle(struct iwl_priv *priv)
> >
> >                rxq->queue[i] = NULL;
> >
> > -               dma_sync_single_range_for_cpu(
> > -                               &priv->pci_dev->dev, rxb->real_dma_addr,
> > -                               rxb->aligned_dma_addr - rxb->real_dma_addr,
> > -                               priv->hw_params.rx_buf_size,
> > -                               PCI_DMA_FROMDEVICE);
> > +               pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
> > +                                priv->hw_params.rx_buf_size + 256,
> > +                                PCI_DMA_FROMDEVICE);
> >                pkt = (struct iwl_rx_packet *)rxb->skb->data;
> >
> >                /* Reclaim a command buffer only if this packet is a response
> > @@ -1031,9 +1029,6 @@ void iwl_rx_handle(struct iwl_priv *priv)
> >                        rxb->skb = NULL;
> >                }
> >
> > -               pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
> > -                                priv->hw_params.rx_buf_size + 256,
> > -                                PCI_DMA_FROMDEVICE);
> >                spin_lock_irqsave(&rxq->lock, flags);
> >                list_add_tail(&rxb->list, &priv->rxq.rx_used);
> >                spin_unlock_irqrestore(&rxq->lock, flags);
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
> > index 0baae80..721c80f 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-dev.h
> > +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
> > @@ -360,12 +360,16 @@ struct iwl_host_cmd {
> >
> >  /**
> >  * struct iwl_rx_queue - Rx queue
> > + * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
> > + * @dma_addr: bus address of buffer of receive buffer descriptors (rbd)
> >  * @read: Shared index to newest available Rx buffer
> >  * @write: Shared index to oldest written Rx packet
> >  * @free_count: Number of pre-allocated buffers in rx_free
> >  * @rx_free: list of free SKBs for use
> >  * @rx_used: List of Rx buffers with no SKB
> >  * @need_update: flag to indicate we need to update read/write index
> > + * @rb_stts: driver's pointer to receive buffer status
> > + * @rb_stts_dma: bus address of receive buffer status
> >  *
> >  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
> >  */
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
> > index 57ea320..f85b47f 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-tx.c
> > +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
> > @@ -797,6 +797,22 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
> >        /* Copy MAC header from skb into command buffer */
> >        memcpy(tx_cmd->hdr, hdr, hdr_len);
> >
> > +
> > +       /* Total # bytes to be transmitted */
> > +       len = (u16)skb->len;
> > +       tx_cmd->len = cpu_to_le16(len);
> > +
> > +       if (info->control.hw_key)
> > +               iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
> > +
> > +       /* TODO need this for burst mode later on */
> > +       iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
> > +
> > +       /* set is_hcca to 0; it probably will never be implemented */
> > +       iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
> > +
> > +       iwl_update_tx_stats(priv, le16_to_cpu(fc), len);
> > +
> >        /*
> >         * Use the first empty entry in this queue's command buffer array
> >         * to contain the Tx command and MAC header concatenated together
> > @@ -817,21 +833,30 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
> >        else
> >                len_org = 0;
> >
> > +       /* Tell NIC about any 2-byte padding after MAC header */
> > +       if (len_org)
> > +               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
> > +
> >        /* Physical address of this Tx command's header (not MAC header!),
> >         * within command buffer array. */
> >        txcmd_phys = pci_map_single(priv->pci_dev,
> > -                                   out_cmd, sizeof(struct iwl_cmd),
> > +                                   &out_cmd->hdr, len,
> >                                    PCI_DMA_BIDIRECTIONAL);
> >        pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
> > -       pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd));
> > +       pci_unmap_len_set(&out_cmd->meta, len, len);
> >        /* Add buffer containing Tx command and MAC(!) header to TFD's
> >         * first entry */
> > -       txcmd_phys += offsetof(struct iwl_cmd, hdr);
> >        priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
> >                                                   txcmd_phys, len, 1, 0);
> >
> > -       if (info->control.hw_key)
> > -               iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
> > +       if (!ieee80211_has_morefrags(hdr->frame_control)) {
> > +               txq->need_update = 1;
> > +               if (qc)
> > +                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
> > +       } else {
> > +               wait_write_ptr = 1;
> > +               txq->need_update = 0;
> > +       }
> >
> >        /* Set up TFD's 2nd entry to point directly to remainder of skb,
> >         * if any (802.11 null frames have no payload). */
> > @@ -844,42 +869,26 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
> >                                                           0, 0);
> >        }
> >
> > -       /* Tell NIC about any 2-byte padding after MAC header */
> > -       if (len_org)
> > -               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
> > -
> > -       /* Total # bytes to be transmitted */
> > -       len = (u16)skb->len;
> > -       tx_cmd->len = cpu_to_le16(len);
> > -       /* TODO need this for burst mode later on */
> > -       iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
> > -
> > -       /* set is_hcca to 0; it probably will never be implemented */
> > -       iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
> > -
> > -       iwl_update_tx_stats(priv, le16_to_cpu(fc), len);
> > -
> >        scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
> > -               offsetof(struct iwl_tx_cmd, scratch);
> > +                               offsetof(struct iwl_tx_cmd, scratch);
> > +
> > +       len = sizeof(struct iwl_tx_cmd) +
> > +               sizeof(struct iwl_cmd_header) + hdr_len;
> > +       /* take back ownership of DMA buffer to enable update */
> > +       pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys,
> > +                                   len, PCI_DMA_BIDIRECTIONAL);
> >        tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
> >        tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
> >
> > -       if (!ieee80211_has_morefrags(hdr->frame_control)) {
> > -               txq->need_update = 1;
> > -               if (qc)
> > -                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
> > -       } else {
> > -               wait_write_ptr = 1;
> > -               txq->need_update = 0;
> > -       }
> > -
> >        iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
> > -
> >        iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
> >
> >        /* Set up entry for this TFD in Tx byte-count array */
> >        priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
> >
> > +       pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
> > +                                      len, PCI_DMA_BIDIRECTIONAL);
> > +
> >        /* Tell device the write index *just past* this latest filled TFD */
> >        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
> >        ret = iwl_txq_update_write_ptr(priv, txq);
> > @@ -966,18 +975,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
> >                        INDEX_TO_SEQ(q->write_ptr));
> >        if (out_cmd->meta.flags & CMD_SIZE_HUGE)
> >                out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
> > -       len = (idx == TFD_CMD_SLOTS) ?
> > -                       IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd);
> > -
> > -       phys_addr = pci_map_single(priv->pci_dev, out_cmd,
> > -                                  len, PCI_DMA_BIDIRECTIONAL);
> > -       pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
> > -       pci_unmap_len_set(&out_cmd->meta, len, len);
> > -       phys_addr += offsetof(struct iwl_cmd, hdr);
> > +       len = sizeof(struct iwl_cmd) - sizeof(struct iwl_cmd_meta);
> > +       len += (idx == TFD_CMD_SLOTS) ?  IWL_MAX_SCAN_SIZE : 0;
> >
> > -       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
> > -                                                  phys_addr, fix_size, 1,
> > -                                                  U32_PAD(cmd->len));
> >
> >  #ifdef CONFIG_IWLWIFI_DEBUG
> >        switch (out_cmd->hdr.cmd) {
> > @@ -1005,6 +1005,15 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
> >                /* Set up entry in queue's byte count circular buffer */
> >                priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
> >
> > +       phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
> > +                                  fix_size, PCI_DMA_BIDIRECTIONAL);
> > +       pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
> > +       pci_unmap_len_set(&out_cmd->meta, len, fix_size);
> > +
> > +       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
> > +                                                  phys_addr, fix_size, 1,
> > +                                                  U32_PAD(cmd->len));
> > +
> >        /* Increment and update queue's write index */
> >        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
> >        ret = iwl_txq_update_write_ptr(priv, txq);
> > diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
> > index c29189b..c4c8943 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
> > +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
> > @@ -972,7 +972,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
> >        dma_addr_t phys_addr;
> >        dma_addr_t txcmd_phys;
> >        int txq_id = skb_get_queue_mapping(skb);
> > -       u16 len, idx, len_org, hdr_len;
> > +       u16 len, idx, len_org, hdr_len; /* TODO: len_org is not used */
> >        u8 id;
> >        u8 unicast;
> >        u8 sta_id;
> > @@ -1074,6 +1074,38 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
> >        /* Copy MAC header from skb into command buffer */
> >        memcpy(tx->hdr, hdr, hdr_len);
> >
> > +
> > +       if (info->control.hw_key)
> > +               iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, sta_id);
> > +
> > +       /* TODO need this for burst mode later on */
> > +       iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, sta_id);
> > +
> > +       /* set is_hcca to 0; it probably will never be implemented */
> > +       iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0);
> > +
> > +       /* Total # bytes to be transmitted */
> > +       len = (u16)skb->len;
> > +       tx->len = cpu_to_le16(len);
> > +
> > +
> > +       tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
> > +       tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
> > +
> > +       if (!ieee80211_has_morefrags(hdr->frame_control)) {
> > +               txq->need_update = 1;
> > +               if (qc)
> > +                       priv->stations_39[sta_id].tid[tid].seq_number = seq_number;
> > +       } else {
> > +               wait_write_ptr = 1;
> > +               txq->need_update = 0;
> > +       }
> > +
> > +       iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
> > +
> > +       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
> > +                          ieee80211_hdrlen(fc));
> > +
> >        /*
> >         * Use the first empty entry in this queue's command buffer array
> >         * to contain the Tx command and MAC header concatenated together
> > @@ -1096,22 +1128,18 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
> >
> >        /* Physical address of this Tx command's header (not MAC header!),
> >         * within command buffer array. */
> > -       txcmd_phys = pci_map_single(priv->pci_dev,
> > -                                   out_cmd, sizeof(struct iwl_cmd),
> > -                                   PCI_DMA_TODEVICE);
> > +       txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr,
> > +                                   len, PCI_DMA_TODEVICE);
> > +       /* we do not map meta data ... so we can safely access address to
> > +        * provide to unmap command*/
> >        pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
> > -       pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd));
> > -       /* Add buffer containing Tx command and MAC(!) header to TFD's
> > -        * first entry */
> > -       txcmd_phys += offsetof(struct iwl_cmd, hdr);
> > +       pci_unmap_len_set(&out_cmd->meta, len, len);
> >
> >        /* Add buffer containing Tx command and MAC(!) header to TFD's
> >         * first entry */
> >        priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
> >                                                   txcmd_phys, len, 1, 0);
> >
> > -       if (info->control.hw_key)
> > -               iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, sta_id);
> >
> >        /* Set up TFD's 2nd entry to point directly to remainder of skb,
> >         * if any (802.11 null frames have no payload). */
> > @@ -1124,32 +1152,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
> >                                                           0, U32_PAD(len));
> >        }
> >
> > -       /* Total # bytes to be transmitted */
> > -       len = (u16)skb->len;
> > -       tx->len = cpu_to_le16(len);
> > -
> > -       /* TODO need this for burst mode later on */
> > -       iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, sta_id);
> > -
> > -       /* set is_hcca to 0; it probably will never be implemented */
> > -       iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0);
> > -
> > -       tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
> > -       tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
> > -
> > -       if (!ieee80211_has_morefrags(hdr->frame_control)) {
> > -               txq->need_update = 1;
> > -               if (qc)
> > -                       priv->stations_39[sta_id].tid[tid].seq_number = seq_number;
> > -       } else {
> > -               wait_write_ptr = 1;
> > -               txq->need_update = 0;
> > -       }
> > -
> > -       iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
> > -
> > -       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
> > -                          ieee80211_hdrlen(fc));
> >
> >        /* Tell device the write index *just past* this latest filled TFD */
> >        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
> > @@ -1661,6 +1663,37 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv)
> >        spin_unlock_irqrestore(&rxq->lock, flags);
> >  }
> >
> > +void iwl3945_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].real_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(iwl3945_rx_queue_reset);
> > +
> >  /*
> >  * this should be called while priv->lock is locked
> >  */
> > @@ -1685,6 +1718,34 @@ void iwl3945_rx_replenish(void *data)
> >        spin_unlock_irqrestore(&priv->lock, flags);
> >  }
> >
> > +/* 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 iwl3945_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].real_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);
> > +       pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
> > +                           rxq->rb_stts, rxq->rb_stts_dma);
> > +       rxq->bd = NULL;
> > +       rxq->rb_stts  = NULL;
> > +}
> > +EXPORT_SYMBOL(iwl3945_rx_queue_free);
> > +
> > +
> >  /* Convert linear signal-to-noise ratio into dB */
> >  static u8 ratio2dB[100] = {
> >  /*      0   1   2   3   4   5   6   7   8   9 */
> > @@ -1802,9 +1863,9 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
> >
> >                rxq->queue[i] = NULL;
> >
> > -               pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->real_dma_addr,
> > -                                           priv->hw_params.rx_buf_size,
> > -                                           PCI_DMA_FROMDEVICE);
> > +               pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
> > +                               priv->hw_params.rx_buf_size,
> > +                               PCI_DMA_FROMDEVICE);
> >                pkt = (struct iwl_rx_packet *)rxb->skb->data;
> >
> >                /* Reclaim a command buffer only if this packet is a response
> > @@ -1852,9 +1913,6 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
> >                        rxb->skb = NULL;
> >                }
> >
> > -               pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
> > -                               priv->hw_params.rx_buf_size,
> > -                               PCI_DMA_FROMDEVICE);
> >                spin_lock_irqsave(&rxq->lock, flags);
> >                list_add_tail(&rxb->list, &priv->rxq.rx_used);
> >                spin_unlock_irqrestore(&rxq->lock, flags);
> > @@ -5144,7 +5202,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
> >        iwl3945_dealloc_ucode_pci(priv);
> >
> >        if (priv->rxq.bd)
> > -               iwl_rx_queue_free(priv, &priv->rxq);
> > +               iwl3945_rx_queue_free(priv, &priv->rxq);
> >        iwl3945_hw_txq_ctx_free(priv);
> >
> >        iwl3945_unset_hw_params(priv);
> > --
> > 1.5.6.3
> >
> >
> >
> >

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux