aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-3945.c
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2009-10-09 05:19:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-27 16:48:06 -0400
commit2f301227a1ede57504694e1f64839839f5737cac (patch)
treec148ca6c3409f5f8fed4455fba3a78fe31469135 /drivers/net/wireless/iwlwifi/iwl-3945.c
parentae751bab9f55c3152ebf713c89a4fb6f439c2575 (diff)
iwlwifi: use paged Rx
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>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-3945.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 8012381d3717..b188a026637a 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,
293static void iwl3945_rx_reply_tx(struct iwl_priv *priv, 293static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
294 struct iwl_rx_mem_buffer *rxb) 294 struct iwl_rx_mem_buffer *rxb)
295{ 295{
296 struct iwl_rx_packet *pkt = (void *)rxb->skb->data; 296 struct iwl_rx_packet *pkt = rxb_addr(rxb);
297 u16 sequence = le16_to_cpu(pkt->hdr.sequence); 297 u16 sequence = le16_to_cpu(pkt->hdr.sequence);
298 int txq_id = SEQ_TO_QUEUE(sequence); 298 int txq_id = SEQ_TO_QUEUE(sequence);
299 int index = SEQ_TO_INDEX(sequence); 299 int index = SEQ_TO_INDEX(sequence);
@@ -353,7 +353,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
353void iwl3945_hw_rx_statistics(struct iwl_priv *priv, 353void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
354 struct iwl_rx_mem_buffer *rxb) 354 struct iwl_rx_mem_buffer *rxb)
355{ 355{
356 struct iwl_rx_packet *pkt = (void *)rxb->skb->data; 356 struct iwl_rx_packet *pkt = rxb_addr(rxb);
357 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", 357 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
358 (int)sizeof(struct iwl3945_notif_statistics), 358 (int)sizeof(struct iwl3945_notif_statistics),
359 le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); 359 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,
543 struct iwl_rx_mem_buffer *rxb, 543 struct iwl_rx_mem_buffer *rxb,
544 struct ieee80211_rx_status *stats) 544 struct ieee80211_rx_status *stats)
545{ 545{
546 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 546 struct iwl_rx_packet *pkt = rxb_addr(rxb);
547 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); 547 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
548 struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); 548 struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
549 struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); 549 struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
550 short len = le16_to_cpu(rx_hdr->len); 550 u16 len = le16_to_cpu(rx_hdr->len);
551 struct sk_buff *skb;
552 int ret;
551 553
552 /* We received data from the HW, so stop the watchdog */ 554 /* We received data from the HW, so stop the watchdog */
553 if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { 555 if (unlikely(len + IWL39_RX_FRAME_SIZE >
556 PAGE_SIZE << priv->hw_params.rx_page_order)) {
554 IWL_DEBUG_DROP(priv, "Corruption detected!\n"); 557 IWL_DEBUG_DROP(priv, "Corruption detected!\n");
555 return; 558 return;
556 } 559 }
@@ -562,20 +565,45 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
562 return; 565 return;
563 } 566 }
564 567
565 skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); 568 skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
566 /* Set the size of the skb to the size of the frame */ 569 if (!skb) {
567 skb_put(rxb->skb, le16_to_cpu(rx_hdr->len)); 570 IWL_ERR(priv, "alloc_skb failed\n");
571 return;
572 }
568 573
569 if (!iwl3945_mod_params.sw_crypto) 574 if (!iwl3945_mod_params.sw_crypto)
570 iwl_set_decrypted_flag(priv, 575 iwl_set_decrypted_flag(priv,
571 (struct ieee80211_hdr *)rxb->skb->data, 576 (struct ieee80211_hdr *)rxb_addr(rxb),
572 le32_to_cpu(rx_end->status), stats); 577 le32_to_cpu(rx_end->status), stats);
573 578
579 skb_add_rx_frag(skb, 0, rxb->page,
580 (void *)rx_hdr->payload - (void *)pkt, len);
581
582 /* mac80211 currently doesn't support paged SKB. Convert it to
583 * linear SKB for management frame and data frame requires
584 * software decryption or software defragementation. */
585 if (ieee80211_is_mgmt(hdr->frame_control) ||
586 ieee80211_has_protected(hdr->frame_control) ||
587 ieee80211_has_morefrags(hdr->frame_control) ||
588 le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
589 ret = skb_linearize(skb);
590 else
591 ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
592 0 : -ENOMEM;
593
594 if (ret) {
595 kfree_skb(skb);
596 goto out;
597 }
598
574 iwl_update_stats(priv, false, hdr->frame_control, len); 599 iwl_update_stats(priv, false, hdr->frame_control, len);
575 600
576 memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); 601 memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
577 ieee80211_rx_irqsafe(priv->hw, rxb->skb); 602 ieee80211_rx(priv->hw, skb);
578 rxb->skb = NULL; 603
604 out:
605 priv->alloc_rxb_page--;
606 rxb->page = NULL;
579} 607}
580 608
581#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) 609#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
@@ -585,7 +613,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
585{ 613{
586 struct ieee80211_hdr *header; 614 struct ieee80211_hdr *header;
587 struct ieee80211_rx_status rx_status; 615 struct ieee80211_rx_status rx_status;
588 struct iwl_rx_packet *pkt = (void *)rxb->skb->data; 616 struct iwl_rx_packet *pkt = rxb_addr(rxb);
589 struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); 617 struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
590 struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); 618 struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
591 struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); 619 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)
1811static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) 1839static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
1812{ 1840{
1813 int rc = 0; 1841 int rc = 0;
1814 struct iwl_rx_packet *res = NULL; 1842 struct iwl_rx_packet *pkt;
1815 struct iwl3945_rxon_assoc_cmd rxon_assoc; 1843 struct iwl3945_rxon_assoc_cmd rxon_assoc;
1816 struct iwl_host_cmd cmd = { 1844 struct iwl_host_cmd cmd = {
1817 .id = REPLY_RXON_ASSOC, 1845 .id = REPLY_RXON_ASSOC,
@@ -1840,14 +1868,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
1840 if (rc) 1868 if (rc)
1841 return rc; 1869 return rc;
1842 1870
1843 res = (struct iwl_rx_packet *)cmd.reply_skb->data; 1871 pkt = (struct iwl_rx_packet *)cmd.reply_page;
1844 if (res->hdr.flags & IWL_CMD_FAILED_MSK) { 1872 if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
1845 IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); 1873 IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
1846 rc = -EIO; 1874 rc = -EIO;
1847 } 1875 }
1848 1876
1849 priv->alloc_rxb_skb--; 1877 priv->alloc_rxb_page--;
1850 dev_kfree_skb_any(cmd.reply_skb); 1878 free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
1851 1879
1852 return rc; 1880 return rc;
1853} 1881}
@@ -2513,8 +2541,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
2513 priv->hw_params.max_txq_num = priv->cfg->num_of_queues; 2541 priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
2514 2542
2515 priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); 2543 priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
2516 priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; 2544 priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K);
2517 priv->hw_params.max_pkt_size = 2342;
2518 priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; 2545 priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
2519 priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; 2546 priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
2520 priv->hw_params.max_stations = IWL3945_STATION_COUNT; 2547 priv->hw_params.max_stations = IWL3945_STATION_COUNT;