1415 lines
50 KiB
Diff
1415 lines
50 KiB
Diff
From 9da755c9ddb534534e760d3e804cb6bcc81a2a9e Mon Sep 17 00:00:00 2001
|
|
From: Zhu Yi <yi.zhu@intel.com>
|
|
Date: Fri, 9 Oct 2009 17:19:45 +0800
|
|
Subject: [PATCH 1/3] iwlwifi: use paged Rx
|
|
|
|
commit 2f301227a1ede57504694e1f64839839f5737cac upstream.
|
|
|
|
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@intel.com>
|
|
Signed-off-by: John W. Linville <linville@tuxdriver.com>
|
|
[bwh: Backport to 2.6.32]
|
|
---
|
|
drivers/net/wireless/iwlwifi/iwl-3945-led.c | 2 +-
|
|
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 +++++++++++++-------------
|
|
16 files changed, 285 insertions(+), 241 deletions(-)
|
|
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
|
|
index 8c29ded..b77f2c8 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
|
|
@@ -81,7 +81,7 @@ static const struct {
|
|
|
|
static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
|
|
struct iwl_device_cmd *cmd,
|
|
- struct sk_buff *skb)
|
|
+ struct iwl_rx_packet *skb)
|
|
{
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
|
|
index 56bfcc3..4dde964 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);
|
|
@@ -545,14 +545,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;
|
|
}
|
|
@@ -564,24 +567,49 @@ 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;
|
|
+ }
|
|
+
|
|
#ifdef CONFIG_IWLWIFI_LEDS
|
|
if (ieee80211_is_data(hdr->frame_control))
|
|
priv->rxtxpackets += len;
|
|
#endif
|
|
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)
|
|
@@ -591,7 +619,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);
|
|
@@ -1858,7 +1886,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,
|
|
@@ -1887,14 +1915,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;
|
|
}
|
|
@@ -2558,8 +2586,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
|
|
priv->hw_params.max_txq_num = IWL39_NUM_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 585b8d4..62460f5 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
|
|
@@ -2085,7 +2085,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 1f423f2..ab76a8f 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
|
|
@@ -494,7 +494,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;
|
|
@@ -1226,7 +1226,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 748f712..3d90530 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
|
@@ -525,7 +525,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;
|
|
|
|
@@ -611,7 +611,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);
|
|
@@ -635,7 +635,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;
|
|
|
|
@@ -787,10 +787,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);
|
|
|
|
/* Reclaim a command buffer only if this packet is a response
|
|
* to a (driver-originated) command.
|
|
@@ -823,10 +823,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");
|
|
@@ -835,10 +835,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);
|
|
@@ -905,6 +905,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
|
|
@@ -926,8 +928,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
|
|
|
|
handled |= CSR_INT_BIT_HW_ERR;
|
|
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
-
|
|
return;
|
|
}
|
|
|
|
@@ -1054,7 +1054,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 */
|
|
@@ -1084,6 +1083,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;
|
|
|
|
@@ -1099,8 +1101,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
|
|
|
|
handled |= CSR_INT_BIT_HW_ERR;
|
|
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
-
|
|
return;
|
|
}
|
|
|
|
@@ -1240,14 +1240,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 4afaf77..dd54bf2 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
|
|
@@ -3495,6 +3495,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 a58e67b..81d3a58 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
|
|
@@ -1173,7 +1173,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",
|
|
@@ -1348,10 +1348,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;
|
|
|
|
@@ -2030,7 +2029,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);
|
|
@@ -2041,7 +2040,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,
|
|
@@ -2053,7 +2052,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 d5000c7..46686c4 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
|
|
@@ -512,7 +512,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 35a7f68..8f98d72 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
|
|
@@ -145,12 +145,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;
|
|
|
|
@@ -166,7 +167,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. */
|
|
@@ -359,6 +360,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
|
|
*
|
|
@@ -383,10 +391,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;
|
|
@@ -619,7 +627,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:
|
|
@@ -642,9 +650,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;
|
|
@@ -956,7 +963,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 a6856da..1bf17d2 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
|
|
@@ -104,17 +104,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);
|
|
@@ -216,7 +207,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;
|
|
@@ -238,9 +229,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);
|
|
@@ -273,7 +264,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 3198a8a..5d10953 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--;
|
|
}
|
|
}
|
|
|
|
@@ -406,14 +410,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);
|
|
}
|
|
@@ -492,7 +496,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;
|
|
@@ -555,7 +559,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),
|
|
@@ -879,6 +883,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,
|
|
@@ -891,15 +898,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. */
|
|
@@ -927,7 +957,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;
|
|
@@ -1088,7 +1118,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 71c0ad4..7e4d6aa 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
|
|
@@ -112,7 +112,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,
|
|
@@ -132,21 +132,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;
|
|
}
|
|
@@ -156,7 +156,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;
|
|
|
|
@@ -168,7 +168,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);
|
|
@@ -187,7 +187,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;
|
|
|
|
@@ -214,7 +214,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 7f15b7e..93ce987 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);
|
|
|
|
@@ -1454,7 +1454,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 95447ca..340e1c7 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
|
|
@@ -761,7 +761,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,
|
|
@@ -806,18 +806,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;
|
|
@@ -829,7 +829,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;
|
|
}
|
|
@@ -838,7 +838,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;
|
|
|
|
@@ -875,7 +875,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);
|
|
@@ -911,7 +911,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;
|
|
|
|
@@ -934,7 +934,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;
|
|
|
|
@@ -1098,7 +1098,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--;
|
|
@@ -1138,7 +1138,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) {
|
|
@@ -1152,9 +1152,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) &&
|
|
@@ -1171,7 +1175,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;
|
|
@@ -1179,26 +1183,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);
|
|
}
|
|
}
|
|
@@ -1214,14 +1210,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);
|
|
}
|
|
@@ -1229,8 +1225,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);
|
|
}
|
|
|
|
@@ -1263,12 +1259,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--;
|
|
}
|
|
}
|
|
|
|
@@ -1404,10 +1402,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);
|
|
|
|
/* Reclaim a command buffer only if this packet is a response
|
|
* to a (driver-originated) command.
|
|
@@ -1429,16 +1427,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");
|
|
@@ -1447,10 +1446,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);
|
|
@@ -1688,6 +1687,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
|
|
@@ -1709,8 +1710,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
|
|
|
handled |= CSR_INT_BIT_HW_ERR;
|
|
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
-
|
|
return;
|
|
}
|
|
|
|
@@ -1802,7 +1801,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.7.1
|
|
|