Search Linux Wireless

Re: [PATCH V3] iwlwifi: use paged Rx

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

 



Hi,

you are using ieee80211_rx() in
* drivers/net/wireless/iwlwifi/iwl-3945.c
* drivers/net/wireless/iwlwifi/iwl-rx.c
files.
Kalle posted "mac80211: add ieee80211_rx_ni()" patch [1] and I applied
on top of master 2009-10-13.
wl1251 driver uses ieee80211_rx_ni() [2].
My question:
Is iwlagn/iwl3945 using workqueues - means shall/can it use
ieee80211_rx_ni() instead?
Out of curiosity, I substituted ieee80211_rx() by ieee80211_rx_ni()
and it seems to work.
(Patch attached).

Kind Regards,
- Sedat -

[1] http://patchwork.kernel.org/patch/53466/
[2] http://patchwork.kernel.org/patch/53465/

On Fri, Oct 9, 2009 at 11:19 AM, Zhu Yi <yi.zhu@xxxxxxxxx> wrote:
> This switches the iwlwifi driver to use paged skb from linear skb for Rx
> buffer. So that it relieves some Rx buffer allocation pressure for the
> memory subsystem. Currently iwlwifi (4K for 3945) requests 8K bytes for
> Rx buffer. Due to the trailing skb_shared_info in the skb->data,
> alloc_skb() will do the next order allocation, which is 16K bytes. This
> is suboptimal and more likely to fail when the system is under memory
> usage pressure. Switching to paged Rx skb lets us allocate the RXB
> directly by alloc_pages(), so that only order 1 allocation is required.
>
> It also adjusts the area spin_lock (with IRQ disabled) protected in the
> tasklet because tasklet guarentees to run only on one CPU and the new
> unprotected code can be preempted by the IRQ handler. This saves us from
> spawning another workqueue to make skb_linearize/__pskb_pull_tail happy
> (which cannot be called in hard irq context).
>
> Finally, mac80211 doesn't support paged Rx yet. So we linearize the skb
> for all the management frames and software decryption or defragmentation
> required data frames before handed to mac80211. For all the other frames,
> we __pskb_pull_tail 64 bytes in the linear area of the skb for mac80211
> to handle them properly.
>
> Signed-off-by: Zhu Yi <yi.zhu@xxxxxxxxx>
> ---
> V2: fix 3945 problem and linearize skb for fragemented frames
> V3: fix a 3945 pci_unmap_page bug
>
>  drivers/net/wireless/iwlwifi/iwl-3945.c     |   67 ++++++++++-----
>  drivers/net/wireless/iwlwifi/iwl-4965.c     |    2 +-
>  drivers/net/wireless/iwlwifi/iwl-5000.c     |    4 +-
>  drivers/net/wireless/iwlwifi/iwl-agn.c      |   42 ++++-----
>  drivers/net/wireless/iwlwifi/iwl-commands.h |   10 ++
>  drivers/net/wireless/iwlwifi/iwl-core.c     |   13 ++--
>  drivers/net/wireless/iwlwifi/iwl-core.h     |    2 +-
>  drivers/net/wireless/iwlwifi/iwl-dev.h      |   27 ++++--
>  drivers/net/wireless/iwlwifi/iwl-hcmd.c     |   21 ++----
>  drivers/net/wireless/iwlwifi/iwl-rx.c       |  122 +++++++++++++++++----------
>  drivers/net/wireless/iwlwifi/iwl-scan.c     |   20 ++--
>  drivers/net/wireless/iwlwifi/iwl-spectrum.c |    2 +-
>  drivers/net/wireless/iwlwifi/iwl-sta.c      |   62 +++++--------
>  drivers/net/wireless/iwlwifi/iwl-tx.c       |   10 +-
>  drivers/net/wireless/iwlwifi/iwl3945-base.c |  120 +++++++++++++-------------
>  15 files changed, 284 insertions(+), 240 deletions(-)
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
> index 8012381..b188a02 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-3945.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
> @@ -293,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
>  static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
>                            struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
>        int txq_id = SEQ_TO_QUEUE(sequence);
>        int index = SEQ_TO_INDEX(sequence);
> @@ -353,7 +353,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
>  void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
>                struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
>                     (int)sizeof(struct iwl3945_notif_statistics),
>                     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
> @@ -543,14 +543,17 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
>                                   struct iwl_rx_mem_buffer *rxb,
>                                   struct ieee80211_rx_status *stats)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
>        struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
>        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
> -       short len = le16_to_cpu(rx_hdr->len);
> +       u16 len = le16_to_cpu(rx_hdr->len);
> +       struct sk_buff *skb;
> +       int ret;
>
>        /* We received data from the HW, so stop the watchdog */
> -       if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
> +       if (unlikely(len + IWL39_RX_FRAME_SIZE >
> +                    PAGE_SIZE << priv->hw_params.rx_page_order)) {
>                IWL_DEBUG_DROP(priv, "Corruption detected!\n");
>                return;
>        }
> @@ -562,20 +565,45 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
>                return;
>        }
>
> -       skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
> -       /* Set the size of the skb to the size of the frame */
> -       skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
> +       skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
> +       if (!skb) {
> +               IWL_ERR(priv, "alloc_skb failed\n");
> +               return;
> +       }
>
>        if (!iwl3945_mod_params.sw_crypto)
>                iwl_set_decrypted_flag(priv,
> -                                      (struct ieee80211_hdr *)rxb->skb->data,
> +                                      (struct ieee80211_hdr *)rxb_addr(rxb),
>                                       le32_to_cpu(rx_end->status), stats);
>
> +       skb_add_rx_frag(skb, 0, rxb->page,
> +                       (void *)rx_hdr->payload - (void *)pkt, len);
> +
> +       /* mac80211 currently doesn't support paged SKB. Convert it to
> +        * linear SKB for management frame and data frame requires
> +        * software decryption or software defragementation. */
> +       if (ieee80211_is_mgmt(hdr->frame_control) ||
> +           ieee80211_has_protected(hdr->frame_control) ||
> +           ieee80211_has_morefrags(hdr->frame_control) ||
> +           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
> +               ret = skb_linearize(skb);
> +       else
> +               ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
> +                       0 : -ENOMEM;
> +
> +       if (ret) {
> +               kfree_skb(skb);
> +               goto out;
> +       }
> +
>        iwl_update_stats(priv, false, hdr->frame_control, len);
>
> -       memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
> -       ieee80211_rx_irqsafe(priv->hw, rxb->skb);
> -       rxb->skb = NULL;
> +       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
> +       ieee80211_rx(priv->hw, skb);
> +
> + out:
> +       priv->alloc_rxb_page--;
> +       rxb->page = NULL;
>  }
>
>  #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
> @@ -585,7 +613,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
>  {
>        struct ieee80211_hdr *header;
>        struct ieee80211_rx_status rx_status;
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
>        struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
>        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
> @@ -1811,7 +1839,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
>  static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
>  {
>        int rc = 0;
> -       struct iwl_rx_packet *res = NULL;
> +       struct iwl_rx_packet *pkt;
>        struct iwl3945_rxon_assoc_cmd rxon_assoc;
>        struct iwl_host_cmd cmd = {
>                .id = REPLY_RXON_ASSOC,
> @@ -1840,14 +1868,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
>        if (rc)
>                return rc;
>
> -       res = (struct iwl_rx_packet *)cmd.reply_skb->data;
> -       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
> +       pkt = (struct iwl_rx_packet *)cmd.reply_page;
> +       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
>                IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
>                rc = -EIO;
>        }
>
> -       priv->alloc_rxb_skb--;
> -       dev_kfree_skb_any(cmd.reply_skb);
> +       priv->alloc_rxb_page--;
> +       free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
>
>        return rc;
>  }
> @@ -2513,8 +2541,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
>        priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
>
>        priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
> -       priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
> -       priv->hw_params.max_pkt_size = 2342;
> +       priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K);
>        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
>        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
>        priv->hw_params.max_stations = IWL3945_STATION_COUNT;
> diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
> index 6d77039..1a622aa 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-4965.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
> @@ -1999,7 +1999,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
>  static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
>                                struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
>        int txq_id = SEQ_TO_QUEUE(sequence);
>        int index = SEQ_TO_INDEX(sequence);
> diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
> index ab5b9d8..17555c7 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-5000.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
> @@ -423,7 +423,7 @@ static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
>  static void iwl5000_rx_calib_result(struct iwl_priv *priv,
>                             struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
>        int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
>        int index;
> @@ -1143,7 +1143,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
>  static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
>                                struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
>        int txq_id = SEQ_TO_QUEUE(sequence);
>        int index = SEQ_TO_INDEX(sequence);
> diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
> index 0878b34..fc7a511 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-agn.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
> @@ -524,7 +524,7 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
>  static void iwl_rx_reply_alive(struct iwl_priv *priv,
>                                struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_alive_resp *palive;
>        struct delayed_work *pwork;
>
> @@ -610,7 +610,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
>                                struct iwl_rx_mem_buffer *rxb)
>  {
>  #ifdef CONFIG_IWLWIFI_DEBUG
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl4965_beacon_notif *beacon =
>                (struct iwl4965_beacon_notif *)pkt->u.raw;
>        u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
> @@ -634,7 +634,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
>  static void iwl_rx_card_state_notif(struct iwl_priv *priv,
>                                    struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
>        unsigned long status = priv->status;
>
> @@ -786,10 +786,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
>
>                rxq->queue[i] = NULL;
>
> -               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;
> +               pci_unmap_page(priv->pci_dev, rxb->page_dma,
> +                              PAGE_SIZE << priv->hw_params.rx_page_order,
> +                              PCI_DMA_FROMDEVICE);
> +               pkt = rxb_addr(rxb);
>
>                trace_iwlwifi_dev_rx(priv, pkt,
>                        le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
> @@ -825,10 +825,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
>                }
>
>                if (reclaim) {
> -                       /* Invoke any callbacks, transfer the skb to caller, and
> -                        * fire off the (possibly) blocking iwl_send_cmd()
> +                       /* Invoke any callbacks, transfer the buffer to caller,
> +                        * and fire off the (possibly) blocking iwl_send_cmd()
>                         * as we reclaim the driver command queue */
> -                       if (rxb && rxb->skb)
> +                       if (rxb && rxb->page)
>                                iwl_tx_cmd_complete(priv, rxb);
>                        else
>                                IWL_WARN(priv, "Claim null rxb?\n");
> @@ -837,10 +837,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
>                /* For now we just don't re-use anything.  We can tweak this
>                 * later to try and re-use notification packets and SKBs that
>                 * fail to Rx correctly */
> -               if (rxb->skb != NULL) {
> -                       priv->alloc_rxb_skb--;
> -                       dev_kfree_skb_any(rxb->skb);
> -                       rxb->skb = NULL;
> +               if (rxb->page != NULL) {
> +                       priv->alloc_rxb_page--;
> +                       __free_pages(rxb->page, priv->hw_params.rx_page_order);
> +                       rxb->page = NULL;
>                }
>
>                spin_lock_irqsave(&rxq->lock, flags);
> @@ -907,6 +907,8 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
>        }
>  #endif
>
> +       spin_unlock_irqrestore(&priv->lock, flags);
> +
>        /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
>         * atomic, make sure that inta covers all the interrupts that
>         * we've discovered, even if FH interrupt came in just after
> @@ -928,8 +930,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
>
>                handled |= CSR_INT_BIT_HW_ERR;
>
> -               spin_unlock_irqrestore(&priv->lock, flags);
> -
>                return;
>        }
>
> @@ -1056,7 +1056,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
>                        "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
>        }
>  #endif
> -       spin_unlock_irqrestore(&priv->lock, flags);
>  }
>
>  /* tasklet for iwlagn interrupt */
> @@ -1086,6 +1085,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
>                                inta, inta_mask);
>        }
>  #endif
> +
> +       spin_unlock_irqrestore(&priv->lock, flags);
> +
>        /* saved interrupt in inta variable now we can reset priv->inta */
>        priv->inta = 0;
>
> @@ -1101,8 +1103,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
>
>                handled |= CSR_INT_BIT_HW_ERR;
>
> -               spin_unlock_irqrestore(&priv->lock, flags);
> -
>                return;
>        }
>
> @@ -1242,14 +1242,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
>                         inta & ~priv->inta_mask);
>        }
>
> -
>        /* Re-enable all interrupts */
>        /* only Re-enable if diabled by irq */
>        if (test_bit(STATUS_INT_ENABLED, &priv->status))
>                iwl_enable_interrupts(priv);
> -
> -       spin_unlock_irqrestore(&priv->lock, flags);
> -
>  }
>
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
> index cc4e912..7d4f131 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-commands.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
> @@ -3544,6 +3544,16 @@ struct iwl_wimax_coex_cmd {
>  *****************************************************************************/
>
>  struct iwl_rx_packet {
> +       /*
> +        * The first 4 bytes of the RX frame header contain both the RX frame
> +        * size and some flags.
> +        * Bit fields:
> +        * 31:    flag flush RB request
> +        * 30:    flag ignore TC (terminal counter) request
> +        * 29:    flag fast IRQ request
> +        * 28-14: Reserved
> +        * 13-00: RX frame size
> +        */
>        __le32 len_n_flags;
>        struct iwl_cmd_header hdr;
>        union {
> diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
> index 2ae168a..3e6ce5c 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-core.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-core.c
> @@ -1281,7 +1281,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
>
>  void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
>        struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
>        IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n",
> @@ -1492,10 +1492,9 @@ int iwl_set_hw_params(struct iwl_priv *priv)
>        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
>        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
>        if (priv->cfg->mod_params->amsdu_size_8K)
> -               priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K;
> +               priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
>        else
> -               priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
> -       priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
> +               priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
>
>        priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
>
> @@ -2176,7 +2175,7 @@ void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
>                           struct iwl_rx_mem_buffer *rxb)
>  {
>  #ifdef CONFIG_IWLWIFI_DEBUG
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
>        IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
>                     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
> @@ -2187,7 +2186,7 @@ EXPORT_SYMBOL(iwl_rx_pm_sleep_notif);
>  void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
>                                      struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
>        IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
>                        "notification for %s:\n", len,
> @@ -2199,7 +2198,7 @@ EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
>  void iwl_rx_reply_error(struct iwl_priv *priv,
>                        struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>
>        IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
>                "seq 0x%04X ser 0x%08X\n",
> diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
> index cec673b..b877f88 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-core.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-core.h
> @@ -531,7 +531,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
>                           const void *data,
>                           void (*callback)(struct iwl_priv *priv,
>                                            struct iwl_device_cmd *cmd,
> -                                           struct sk_buff *skb));
> +                                           struct iwl_rx_packet *pkt));
>
>  int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
> index 451aa65..35d5794 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-dev.h
> +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
> @@ -146,12 +146,13 @@ extern void iwl5000_temperature(struct iwl_priv *priv);
>  #define        DEFAULT_LONG_RETRY_LIMIT  4U
>
>  struct iwl_rx_mem_buffer {
> -       dma_addr_t real_dma_addr;
> -       dma_addr_t aligned_dma_addr;
> -       struct sk_buff *skb;
> +       dma_addr_t page_dma;
> +       struct page *page;
>        struct list_head list;
>  };
>
> +#define rxb_addr(r) page_address(r->page)
> +
>  /* defined below */
>  struct iwl_device_cmd;
>
> @@ -167,7 +168,7 @@ struct iwl_cmd_meta {
>         */
>        void (*callback)(struct iwl_priv *priv,
>                         struct iwl_device_cmd *cmd,
> -                        struct sk_buff *skb);
> +                        struct iwl_rx_packet *pkt);
>
>        /* The CMD_SIZE_HUGE flag bit indicates that the command
>         * structure is stored at the end of the shared queue memory. */
> @@ -366,6 +367,13 @@ enum {
>
>  #define IWL_CMD_MAX_PAYLOAD 320
>
> +/*
> + * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header,
> + * SNAP header and alignment. It should also be big enough for 802.11
> + * control frames.
> + */
> +#define IWL_LINK_HDR_MAX 64
> +
>  /**
>  * struct iwl_device_cmd
>  *
> @@ -390,10 +398,10 @@ struct iwl_device_cmd {
>
>  struct iwl_host_cmd {
>        const void *data;
> -       struct sk_buff *reply_skb;
> +       unsigned long reply_page;
>        void (*callback)(struct iwl_priv *priv,
>                         struct iwl_device_cmd *cmd,
> -                        struct sk_buff *skb);
> +                        struct iwl_rx_packet *pkt);
>        u32 flags;
>        u16 len;
>        u8 id;
> @@ -650,7 +658,7 @@ struct iwl_sensitivity_ranges {
>  * @valid_tx/rx_ant: usable antennas
>  * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
>  * @max_rxq_log: Log-base-2 of max_rxq_size
> - * @rx_buf_size: Rx buffer size
> + * @rx_page_order: Rx buffer page order
>  * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
>  * @max_stations:
>  * @bcast_sta_id:
> @@ -673,9 +681,8 @@ struct iwl_hw_params {
>        u8  valid_rx_ant;
>        u16 max_rxq_size;
>        u16 max_rxq_log;
> -       u32 rx_buf_size;
> +       u32 rx_page_order;
>        u32 rx_wrt_ptr_reg;
> -       u32 max_pkt_size;
>        u8  max_stations;
>        u8  bcast_sta_id;
>        u8  ht40_channel;
> @@ -987,7 +994,7 @@ struct iwl_priv {
>        int frames_count;
>
>        enum ieee80211_band band;
> -       int alloc_rxb_skb;
> +       int alloc_rxb_page;
>
>        void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
>                                       struct iwl_rx_mem_buffer *rxb);
> diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
> index 532c8d6..22a21a1 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
> @@ -103,17 +103,8 @@ EXPORT_SYMBOL(get_cmd_string);
>
>  static void iwl_generic_cmd_callback(struct iwl_priv *priv,
>                                     struct iwl_device_cmd *cmd,
> -                                    struct sk_buff *skb)
> +                                    struct iwl_rx_packet *pkt)
>  {
> -       struct iwl_rx_packet *pkt = NULL;
> -
> -       if (!skb) {
> -               IWL_ERR(priv, "Error: Response NULL in %s.\n",
> -                               get_cmd_string(cmd->hdr.cmd));
> -               return;
> -       }
> -
> -       pkt = (struct iwl_rx_packet *)skb->data;
>        if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
>                IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
>                        get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
> @@ -215,7 +206,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
>                ret = -EIO;
>                goto fail;
>        }
> -       if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) {
> +       if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
>                IWL_ERR(priv, "Error: Response NULL in '%s'\n",
>                          get_cmd_string(cmd->id));
>                ret = -EIO;
> @@ -237,9 +228,9 @@ cancel:
>                                                        ~CMD_WANT_SKB;
>        }
>  fail:
> -       if (cmd->reply_skb) {
> -               dev_kfree_skb_any(cmd->reply_skb);
> -               cmd->reply_skb = NULL;
> +       if (cmd->reply_page) {
> +               free_pages(cmd->reply_page, priv->hw_params.rx_page_order);
> +               cmd->reply_page = 0;
>        }
>  out:
>        clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
> @@ -272,7 +263,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
>                           u8 id, u16 len, const void *data,
>                           void (*callback)(struct iwl_priv *priv,
>                                            struct iwl_device_cmd *cmd,
> -                                           struct sk_buff *skb))
> +                                           struct iwl_rx_packet *pkt))
>  {
>        struct iwl_host_cmd cmd = {
>                .id = id,
> diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
> index 7ad327e..0a407f7 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-rx.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
> @@ -200,7 +200,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
>                list_del(element);
>
>                /* Point to Rx buffer via next RBD in circular buffer */
> -               rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->aligned_dma_addr);
> +               rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma);
>                rxq->queue[rxq->write] = rxb;
>                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
>                rxq->free_count--;
> @@ -239,7 +239,7 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>        struct iwl_rx_queue *rxq = &priv->rxq;
>        struct list_head *element;
>        struct iwl_rx_mem_buffer *rxb;
> -       struct sk_buff *skb;
> +       struct page *page;
>        unsigned long flags;
>
>        while (1) {
> @@ -252,29 +252,34 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>
>                if (rxq->free_count > RX_LOW_WATERMARK)
>                        priority |= __GFP_NOWARN;
> -               /* Alloc a new receive buffer */
> -               skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
> -                                               priority);
>
> -               if (!skb) {
> +               if (priv->hw_params.rx_page_order > 0)
> +                       priority |= __GFP_COMP;
> +
> +               /* Alloc a new receive buffer */
> +               page = alloc_pages(priority, priv->hw_params.rx_page_order);
> +               if (!page) {
>                        if (net_ratelimit())
> -                               IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
> +                               IWL_DEBUG_INFO(priv, "alloc_pages failed, "
> +                                              "order: %d\n",
> +                                              priv->hw_params.rx_page_order);
> +
>                        if ((rxq->free_count <= RX_LOW_WATERMARK) &&
>                            net_ratelimit())
> -                               IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
> +                               IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
>                                         priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
>                                         rxq->free_count);
>                        /* 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;
> +                       return;
>                }
>
>                spin_lock_irqsave(&rxq->lock, flags);
>
>                if (list_empty(&rxq->rx_used)) {
>                        spin_unlock_irqrestore(&rxq->lock, flags);
> -                       dev_kfree_skb_any(skb);
> +                       __free_pages(page, priv->hw_params.rx_page_order);
>                        return;
>                }
>                element = rxq->rx_used.next;
> @@ -283,24 +288,21 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>
>                spin_unlock_irqrestore(&rxq->lock, flags);
>
> -               rxb->skb = skb;
> -               /* Get physical address of RB/SKB */
> -               rxb->real_dma_addr = pci_map_single(
> -                                       priv->pci_dev,
> -                                       rxb->skb->data,
> -                                       priv->hw_params.rx_buf_size + 256,
> -                                       PCI_DMA_FROMDEVICE);
> +               rxb->page = page;
> +               /* Get physical address of the RB */
> +               rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
> +                               PAGE_SIZE << priv->hw_params.rx_page_order,
> +                               PCI_DMA_FROMDEVICE);
>                /* dma address must be no more than 36 bits */
> -               BUG_ON(rxb->real_dma_addr & ~DMA_BIT_MASK(36));
> +               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
>                /* and also 256 byte aligned! */
> -               rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
> -               skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
> +               BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
>
>                spin_lock_irqsave(&rxq->lock, flags);
>
>                list_add_tail(&rxb->list, &rxq->rx_free);
>                rxq->free_count++;
> -               priv->alloc_rxb_skb++;
> +               priv->alloc_rxb_page++;
>
>                spin_unlock_irqrestore(&rxq->lock, flags);
>        }
> @@ -336,12 +338,14 @@ 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].real_dma_addr,
> -                                        priv->hw_params.rx_buf_size + 256,
> -                                        PCI_DMA_FROMDEVICE);
> -                       dev_kfree_skb(rxq->pool[i].skb);
> +               if (rxq->pool[i].page != NULL) {
> +                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
> +                               PAGE_SIZE << priv->hw_params.rx_page_order,
> +                               PCI_DMA_FROMDEVICE);
> +                       __free_pages(rxq->pool[i].page,
> +                                    priv->hw_params.rx_page_order);
> +                       rxq->pool[i].page = NULL;
> +                       priv->alloc_rxb_page--;
>                }
>        }
>
> @@ -405,14 +409,14 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
>        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 + 256,
> -                                        PCI_DMA_FROMDEVICE);
> -                       priv->alloc_rxb_skb--;
> -                       dev_kfree_skb(rxq->pool[i].skb);
> -                       rxq->pool[i].skb = NULL;
> +               if (rxq->pool[i].page != NULL) {
> +                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
> +                               PAGE_SIZE << priv->hw_params.rx_page_order,
> +                               PCI_DMA_FROMDEVICE);
> +                       priv->alloc_rxb_page--;
> +                       __free_pages(rxq->pool[i].page,
> +                                    priv->hw_params.rx_page_order);
> +                       rxq->pool[i].page = NULL;
>                }
>                list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
>        }
> @@ -491,7 +495,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
>                                struct iwl_rx_mem_buffer *rxb)
>
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_missed_beacon_notif *missed_beacon;
>
>        missed_beacon = &pkt->u.missed_beacon;
> @@ -592,7 +596,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
>                              struct iwl_rx_mem_buffer *rxb)
>  {
>        int change;
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>
>        IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
>                     (int)sizeof(priv->statistics),
> @@ -919,6 +923,9 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
>                                        struct iwl_rx_mem_buffer *rxb,
>                                        struct ieee80211_rx_status *stats)
>  {
> +       struct sk_buff *skb;
> +       int ret = 0;
> +
>        /* We only process data packets if the interface is open */
>        if (unlikely(!priv->is_open)) {
>                IWL_DEBUG_DROP_LIMIT(priv,
> @@ -931,15 +938,38 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
>            iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
>                return;
>
> -       /* Resize SKB from mac header to end of packet */
> -       skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data);
> -       skb_put(rxb->skb, len);
> +       skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
> +       if (!skb) {
> +               IWL_ERR(priv, "alloc_skb failed\n");
> +               return;
> +       }
> +
> +       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
> +
> +       /* mac80211 currently doesn't support paged SKB. Convert it to
> +        * linear SKB for management frame and data frame requires
> +        * software decryption or software defragementation. */
> +       if (ieee80211_is_mgmt(hdr->frame_control) ||
> +           ieee80211_has_protected(hdr->frame_control) ||
> +           ieee80211_has_morefrags(hdr->frame_control) ||
> +           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
> +               ret = skb_linearize(skb);
> +       else
> +               ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
> +                        0 : -ENOMEM;
> +
> +       if (ret) {
> +               kfree_skb(skb);
> +               goto out;
> +       }
>
>        iwl_update_stats(priv, false, hdr->frame_control, len);
> -       memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
> -       ieee80211_rx_irqsafe(priv->hw, rxb->skb);
> -       priv->alloc_rxb_skb--;
> -       rxb->skb = NULL;
> +       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
> +
> +       ieee80211_rx(priv->hw, skb);
> + out:
> +       priv->alloc_rxb_page--;
> +       rxb->page = NULL;
>  }
>
>  /* This is necessary only for a number of statistics, see the caller. */
> @@ -967,7 +997,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
>  {
>        struct ieee80211_hdr *header;
>        struct ieee80211_rx_status rx_status;
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_rx_phy_res *phy_res;
>        __le32 rx_pkt_status;
>        struct iwl4965_rx_mpdu_res_start *amsdu;
> @@ -1128,7 +1158,7 @@ EXPORT_SYMBOL(iwl_rx_reply_rx);
>  void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
>                                    struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        priv->last_phy_res[0] = 1;
>        memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
>               sizeof(struct iwl_rx_phy_res));
> diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
> index 41f9a06..4fca65a 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-scan.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
> @@ -111,7 +111,7 @@ EXPORT_SYMBOL(iwl_scan_cancel_timeout);
>  static int iwl_send_scan_abort(struct iwl_priv *priv)
>  {
>        int ret = 0;
> -       struct iwl_rx_packet *res;
> +       struct iwl_rx_packet *pkt;
>        struct iwl_host_cmd cmd = {
>                .id = REPLY_SCAN_ABORT_CMD,
>                .flags = CMD_WANT_SKB,
> @@ -131,21 +131,21 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
>                return ret;
>        }
>
> -       res = (struct iwl_rx_packet *)cmd.reply_skb->data;
> -       if (res->u.status != CAN_ABORT_STATUS) {
> +       pkt = (struct iwl_rx_packet *)cmd.reply_page;
> +       if (pkt->u.status != CAN_ABORT_STATUS) {
>                /* The scan abort will return 1 for success or
>                 * 2 for "failure".  A failure condition can be
>                 * due to simply not being in an active scan which
>                 * can occur if we send the scan abort before we
>                 * the microcode has notified us that a scan is
>                 * completed. */
> -               IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", res->u.status);
> +               IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status);
>                clear_bit(STATUS_SCAN_ABORTING, &priv->status);
>                clear_bit(STATUS_SCAN_HW, &priv->status);
>        }
>
> -       priv->alloc_rxb_skb--;
> -       dev_kfree_skb_any(cmd.reply_skb);
> +       priv->alloc_rxb_page--;
> +       free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
>
>        return ret;
>  }
> @@ -155,7 +155,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
>                              struct iwl_rx_mem_buffer *rxb)
>  {
>  #ifdef CONFIG_IWLWIFI_DEBUG
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_scanreq_notification *notif =
>            (struct iwl_scanreq_notification *)pkt->u.raw;
>
> @@ -167,7 +167,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
>  static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
>                                    struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_scanstart_notification *notif =
>            (struct iwl_scanstart_notification *)pkt->u.raw;
>        priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
> @@ -186,7 +186,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
>                                      struct iwl_rx_mem_buffer *rxb)
>  {
>  #ifdef CONFIG_IWLWIFI_DEBUG
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_scanresults_notification *notif =
>            (struct iwl_scanresults_notification *)pkt->u.raw;
>
> @@ -213,7 +213,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
>                                       struct iwl_rx_mem_buffer *rxb)
>  {
>  #ifdef CONFIG_IWLWIFI_DEBUG
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
>
>        IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
> diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
> index 022bcf1..1ea5cd3 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
> @@ -177,7 +177,7 @@ static int iwl_get_measurement(struct iwl_priv *priv,
>  static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
>                                          struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
>
>        if (!report->state) {
> diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
> index c6633fe..dc74c16 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-sta.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
> @@ -99,32 +99,25 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
>
>  static void iwl_add_sta_callback(struct iwl_priv *priv,
>                                 struct iwl_device_cmd *cmd,
> -                                struct sk_buff *skb)
> +                                struct iwl_rx_packet *pkt)
>  {
> -       struct iwl_rx_packet *res = NULL;
>        struct iwl_addsta_cmd *addsta =
>                (struct iwl_addsta_cmd *)cmd->cmd.payload;
>        u8 sta_id = addsta->sta.sta_id;
>
> -       if (!skb) {
> -               IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
> -               return;
> -       }
> -
> -       res = (struct iwl_rx_packet *)skb->data;
> -       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
> +       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
>                IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
> -                         res->hdr.flags);
> +                         pkt->hdr.flags);
>                return;
>        }
>
> -       switch (res->u.add_sta.status) {
> +       switch (pkt->u.add_sta.status) {
>        case ADD_STA_SUCCESS_MSK:
>                iwl_sta_ucode_activate(priv, sta_id);
>                 /* fall through */
>        default:
>                IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
> -                            res->u.add_sta.status);
> +                            pkt->u.add_sta.status);
>                break;
>        }
>  }
> @@ -132,7 +125,7 @@ static void iwl_add_sta_callback(struct iwl_priv *priv,
>  int iwl_send_add_sta(struct iwl_priv *priv,
>                     struct iwl_addsta_cmd *sta, u8 flags)
>  {
> -       struct iwl_rx_packet *res = NULL;
> +       struct iwl_rx_packet *pkt = NULL;
>        int ret = 0;
>        u8 data[sizeof(*sta)];
>        struct iwl_host_cmd cmd = {
> @@ -152,15 +145,15 @@ int iwl_send_add_sta(struct iwl_priv *priv,
>        if (ret || (flags & CMD_ASYNC))
>                return ret;
>
> -       res = (struct iwl_rx_packet *)cmd.reply_skb->data;
> -       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
> +       pkt = (struct iwl_rx_packet *)cmd.reply_page;
> +       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
>                IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
> -                         res->hdr.flags);
> +                         pkt->hdr.flags);
>                ret = -EIO;
>        }
>
>        if (ret == 0) {
> -               switch (res->u.add_sta.status) {
> +               switch (pkt->u.add_sta.status) {
>                case ADD_STA_SUCCESS_MSK:
>                        iwl_sta_ucode_activate(priv, sta->sta.sta_id);
>                        IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
> @@ -172,8 +165,8 @@ int iwl_send_add_sta(struct iwl_priv *priv,
>                }
>        }
>
> -       priv->alloc_rxb_skb--;
> -       dev_kfree_skb_any(cmd.reply_skb);
> +       priv->alloc_rxb_page--;
> +       free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
>
>        return ret;
>  }
> @@ -324,26 +317,19 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
>
>  static void iwl_remove_sta_callback(struct iwl_priv *priv,
>                                    struct iwl_device_cmd *cmd,
> -                                   struct sk_buff *skb)
> +                                   struct iwl_rx_packet *pkt)
>  {
> -       struct iwl_rx_packet *res = NULL;
>        struct iwl_rem_sta_cmd *rm_sta =
> -                (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
> +                       (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
>        const char *addr = rm_sta->addr;
>
> -       if (!skb) {
> -               IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
> -               return;
> -       }
> -
> -       res = (struct iwl_rx_packet *)skb->data;
> -       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
> +       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
>                IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
> -               res->hdr.flags);
> +               pkt->hdr.flags);
>                return;
>        }
>
> -       switch (res->u.rem_sta.status) {
> +       switch (pkt->u.rem_sta.status) {
>        case REM_STA_SUCCESS_MSK:
>                iwl_sta_ucode_deactivate(priv, addr);
>                break;
> @@ -356,7 +342,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv,
>  static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
>                                   u8 flags)
>  {
> -       struct iwl_rx_packet *res = NULL;
> +       struct iwl_rx_packet *pkt;
>        int ret;
>
>        struct iwl_rem_sta_cmd rm_sta_cmd;
> @@ -381,15 +367,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
>        if (ret || (flags & CMD_ASYNC))
>                return ret;
>
> -       res = (struct iwl_rx_packet *)cmd.reply_skb->data;
> -       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
> +       pkt = (struct iwl_rx_packet *)cmd.reply_page;
> +       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
>                IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
> -                         res->hdr.flags);
> +                         pkt->hdr.flags);
>                ret = -EIO;
>        }
>
>        if (!ret) {
> -               switch (res->u.rem_sta.status) {
> +               switch (pkt->u.rem_sta.status) {
>                case REM_STA_SUCCESS_MSK:
>                        iwl_sta_ucode_deactivate(priv, addr);
>                        IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
> @@ -401,8 +387,8 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
>                }
>        }
>
> -       priv->alloc_rxb_skb--;
> -       dev_kfree_skb_any(cmd.reply_skb);
> +       priv->alloc_rxb_page--;
> +       free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
>
>        return ret;
>  }
> diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
> index d0bd7cd..5c43d7c 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-tx.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
> @@ -1153,7 +1153,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
>  */
>  void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
>        int txq_id = SEQ_TO_QUEUE(sequence);
>        int index = SEQ_TO_INDEX(sequence);
> @@ -1180,10 +1180,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
>
>        /* Input error checking is done when commands are added to queue. */
>        if (meta->flags & CMD_WANT_SKB) {
> -               meta->source->reply_skb = rxb->skb;
> -               rxb->skb = NULL;
> +               meta->source->reply_page = (unsigned long)rxb_addr(rxb);
> +               rxb->page = NULL;
>        } else if (meta->callback)
> -               meta->callback(priv, cmd, rxb->skb);
> +               meta->callback(priv, cmd, pkt);
>
>        iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
>
> @@ -1442,7 +1442,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
>  void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
>                                           struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
>        struct iwl_tx_queue *txq = NULL;
>        struct iwl_ht_agg *agg;
> diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
> index 515f29b..5977a57 100644
> --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
> +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
> @@ -745,7 +745,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
>                               u8 type)
>  {
>        struct iwl_spectrum_cmd spectrum;
> -       struct iwl_rx_packet *res;
> +       struct iwl_rx_packet *pkt;
>        struct iwl_host_cmd cmd = {
>                .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
>                .data = (void *)&spectrum,
> @@ -790,18 +790,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
>        if (rc)
>                return rc;
>
> -       res = (struct iwl_rx_packet *)cmd.reply_skb->data;
> -       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
> +       pkt = (struct iwl_rx_packet *)cmd.reply_page;
> +       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
>                IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
>                rc = -EIO;
>        }
>
> -       spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
> +       spectrum_resp_status = le16_to_cpu(pkt->u.spectrum.status);
>        switch (spectrum_resp_status) {
>        case 0:         /* Command will be handled */
> -               if (res->u.spectrum.id != 0xff) {
> +               if (pkt->u.spectrum.id != 0xff) {
>                        IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n",
> -                                               res->u.spectrum.id);
> +                                               pkt->u.spectrum.id);
>                        priv->measurement_status &= ~MEASUREMENT_READY;
>                }
>                priv->measurement_status |= MEASUREMENT_ACTIVE;
> @@ -813,7 +813,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
>                break;
>        }
>
> -       dev_kfree_skb_any(cmd.reply_skb);
> +       free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
>
>        return rc;
>  }
> @@ -822,7 +822,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
>  static void iwl3945_rx_reply_alive(struct iwl_priv *priv,
>                               struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl_alive_resp *palive;
>        struct delayed_work *pwork;
>
> @@ -859,7 +859,7 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv,
>                                 struct iwl_rx_mem_buffer *rxb)
>  {
>  #ifdef CONFIG_IWLWIFI_DEBUG
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>  #endif
>
>        IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
> @@ -895,7 +895,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
>                                struct iwl_rx_mem_buffer *rxb)
>  {
>  #ifdef CONFIG_IWLWIFI_DEBUG
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
>        u8 rate = beacon->beacon_notify_hdr.rate;
>
> @@ -918,7 +918,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
>  static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
>                                    struct iwl_rx_mem_buffer *rxb)
>  {
> -       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
> +       struct iwl_rx_packet *pkt = rxb_addr(rxb);
>        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
>        unsigned long status = priv->status;
>
> @@ -1082,7 +1082,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
>                list_del(element);
>
>                /* Point to Rx buffer via next RBD in circular buffer */
> -               rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->real_dma_addr);
> +               rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->page_dma);
>                rxq->queue[rxq->write] = rxb;
>                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
>                rxq->free_count--;
> @@ -1122,7 +1122,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>        struct iwl_rx_queue *rxq = &priv->rxq;
>        struct list_head *element;
>        struct iwl_rx_mem_buffer *rxb;
> -       struct sk_buff *skb;
> +       struct page *page;
>        unsigned long flags;
>
>        while (1) {
> @@ -1136,9 +1136,13 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>
>                if (rxq->free_count > RX_LOW_WATERMARK)
>                        priority |= __GFP_NOWARN;
> +
> +               if (priv->hw_params.rx_page_order > 0)
> +                       priority |= __GFP_COMP;
> +
>                /* Alloc a new receive buffer */
> -               skb = alloc_skb(priv->hw_params.rx_buf_size, priority);
> -               if (!skb) {
> +               page = alloc_pages(priority, priv->hw_params.rx_page_order);
> +               if (!page) {
>                        if (net_ratelimit())
>                                IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
>                        if ((rxq->free_count <= RX_LOW_WATERMARK) &&
> @@ -1155,7 +1159,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>                spin_lock_irqsave(&rxq->lock, flags);
>                if (list_empty(&rxq->rx_used)) {
>                        spin_unlock_irqrestore(&rxq->lock, flags);
> -                       dev_kfree_skb_any(skb);
> +                       __free_pages(page, priv->hw_params.rx_page_order);
>                        return;
>                }
>                element = rxq->rx_used.next;
> @@ -1163,26 +1167,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>                list_del(element);
>                spin_unlock_irqrestore(&rxq->lock, flags);
>
> -               rxb->skb = skb;
> -
> -               /* If radiotap head is required, reserve some headroom here.
> -                * The physical head count is a variable rx_stats->phy_count.
> -                * We reserve 4 bytes here. Plus these extra bytes, the
> -                * headroom of the physical head should be enough for the
> -                * radiotap head that iwl3945 supported. See iwl3945_rt.
> -                */
> -               skb_reserve(rxb->skb, 4);
> -
> +               rxb->page = page;
>                /* Get physical address of RB/SKB */
> -               rxb->real_dma_addr = pci_map_single(priv->pci_dev,
> -                                               rxb->skb->data,
> -                                               priv->hw_params.rx_buf_size,
> -                                               PCI_DMA_FROMDEVICE);
> +               rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
> +                               PAGE_SIZE << priv->hw_params.rx_page_order,
> +                               PCI_DMA_FROMDEVICE);
>
>                spin_lock_irqsave(&rxq->lock, flags);
> +
>                list_add_tail(&rxb->list, &rxq->rx_free);
> -               priv->alloc_rxb_skb++;
>                rxq->free_count++;
> +               priv->alloc_rxb_page++;
> +
>                spin_unlock_irqrestore(&rxq->lock, flags);
>        }
>  }
> @@ -1198,14 +1194,14 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
>        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;
> +               if (rxq->pool[i].page != NULL) {
> +                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
> +                               PAGE_SIZE << priv->hw_params.rx_page_order,
> +                               PCI_DMA_FROMDEVICE);
> +                       priv->alloc_rxb_page--;
> +                       __free_pages(rxq->pool[i].page,
> +                                    priv->hw_params.rx_page_order);
> +                       rxq->pool[i].page = NULL;
>                }
>                list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
>        }
> @@ -1213,8 +1209,8 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
>        /* 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->write_actual = 0;
> +       rxq->free_count = 0;
>        spin_unlock_irqrestore(&rxq->lock, flags);
>  }
>
> @@ -1247,12 +1243,14 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
>  {
>        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);
> +               if (rxq->pool[i].page != NULL) {
> +                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
> +                               PAGE_SIZE << priv->hw_params.rx_page_order,
> +                               PCI_DMA_FROMDEVICE);
> +                       __free_pages(rxq->pool[i].page,
> +                                    priv->hw_params.rx_page_order);
> +                       rxq->pool[i].page = NULL;
> +                       priv->alloc_rxb_page--;
>                }
>        }
>
> @@ -1388,10 +1386,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
>
>                rxq->queue[i] = NULL;
>
> -               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;
> +               pci_unmap_page(priv->pci_dev, rxb->page_dma,
> +                              PAGE_SIZE << priv->hw_params.rx_page_order,
> +                              PCI_DMA_FROMDEVICE);
> +               pkt = rxb_addr(rxb);
>
>                trace_iwlwifi_dev_rx(priv, pkt,
>                        le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
> @@ -1416,16 +1414,17 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
>                        priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
>                } else {
>                        /* No handling needed */
> -                       IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n",
> +                       IWL_DEBUG_RX(priv,
> +                               "r %d i %d No handler needed for %s, 0x%02x\n",
>                                r, i, get_cmd_string(pkt->hdr.cmd),
>                                pkt->hdr.cmd);
>                }
>
>                if (reclaim) {
> -                       /* Invoke any callbacks, transfer the skb to caller, and
> -                        * fire off the (possibly) blocking iwl_send_cmd()
> +                       /* Invoke any callbacks, transfer the buffer to caller,
> +                        * and fire off the (possibly) blocking iwl_send_cmd()
>                         * as we reclaim the driver command queue */
> -                       if (rxb && rxb->skb)
> +                       if (rxb && rxb->page)
>                                iwl_tx_cmd_complete(priv, rxb);
>                        else
>                                IWL_WARN(priv, "Claim null rxb?\n");
> @@ -1434,10 +1433,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
>                /* For now we just don't re-use anything.  We can tweak this
>                 * later to try and re-use notification packets and SKBs that
>                 * fail to Rx correctly */
> -               if (rxb->skb != NULL) {
> -                       priv->alloc_rxb_skb--;
> -                       dev_kfree_skb_any(rxb->skb);
> -                       rxb->skb = NULL;
> +               if (rxb->page != NULL) {
> +                       priv->alloc_rxb_page--;
> +                       __free_pages(rxb->page, priv->hw_params.rx_page_order);
> +                       rxb->page = NULL;
>                }
>
>                spin_lock_irqsave(&rxq->lock, flags);
> @@ -1678,6 +1677,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
>        }
>  #endif
>
> +       spin_unlock_irqrestore(&priv->lock, flags);
> +
>        /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
>         * atomic, make sure that inta covers all the interrupts that
>         * we've discovered, even if FH interrupt came in just after
> @@ -1699,8 +1700,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
>
>                handled |= CSR_INT_BIT_HW_ERR;
>
> -               spin_unlock_irqrestore(&priv->lock, flags);
> -
>                return;
>        }
>
> @@ -1792,7 +1791,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
>                        "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
>        }
>  #endif
> -       spin_unlock_irqrestore(&priv->lock, flags);
>  }
>
>  static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
> --
> 1.6.0.4
>
> --
> 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
>
From b0ef3780e9562dd00447bb56d1792f05dd1edb66 Mon Sep 17 00:00:00 2001
From: Sedat Dilek <sedat.dilek@xxxxxxxxx>
Date: Wed, 14 Oct 2009 17:12:03 +0200
Subject: [PATCH] iwl3945 and iwlagn: use ieee80211_rx_ni()

---
 drivers/net/wireless/iwlwifi/iwl-3945.c |    2 +-
 drivers/net/wireless/iwlwifi/iwl-rx.c   |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index afe19f2..c365a9d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -600,7 +600,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
 	iwl_update_stats(priv, false, hdr->frame_control, len);
 
 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
-	ieee80211_rx(priv->hw, skb);
+	ieee80211_rx_ni(priv->hw, skb);
 
  out:
 	priv->alloc_rxb_page--;
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 0a407f7..1e12a09 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -966,7 +966,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
 	iwl_update_stats(priv, false, hdr->frame_control, len);
 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
-	ieee80211_rx(priv->hw, skb);
+	ieee80211_rx_ni(priv->hw, skb);
  out:
 	priv->alloc_rxb_page--;
 	rxb->page = NULL;
-- 
1.6.3.1


[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