iwlwifi: allocated rx page accounting cleanup
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-3945.c
index f8ce96c..4609323 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
@@ -293,7 +294,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,16 +354,12 @@ 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);
 
        memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
-
-       iwl_leds_background(priv);
-
-       priv->last_statistics_time = jiffies;
 }
 
 /******************************************************************************
@@ -545,14 +542,18 @@ 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;
+       __le16 fc = hdr->frame_control;
 
        /* 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,20 +565,50 @@ 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 * 2, 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);
 
-       iwl_update_stats(priv, false, hdr->frame_control, len);
+       skb_reserve(skb, IWL_LINK_HDR_MAX);
+       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(fc) ||
+           ieee80211_has_protected(fc) ||
+           ieee80211_has_morefrags(fc) ||
+           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;
+       }
+
+       /*
+        * XXX: We cannot touch the page and its virtual memory (pkt) after
+        * here. It might have already been freed by the above skb change.
+        */
 
-       memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
-       ieee80211_rx_irqsafe(priv->hw, rxb->skb);
-       rxb->skb = NULL;
+       iwl_update_stats(priv, false, fc, len);
+       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)
@@ -587,7 +618,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);
@@ -787,29 +818,31 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
        u8 data_retry_limit;
        __le32 tx_flags;
        __le16 fc = hdr->frame_control;
-       struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
+       struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
 
        rate = iwl3945_rates[rate_index].plcp;
-       tx_flags = tx->tx_flags;
+       tx_flags = tx_cmd->tx_flags;
 
        /* We need to figure out how to get the sta->supp_rates while
         * in this running context */
        rate_mask = IWL_RATES_MASK;
 
+
+       /* Set retry limit on DATA packets and Probe Responses*/
+       if (ieee80211_is_probe_resp(fc))
+               data_retry_limit = 3;
+       else
+               data_retry_limit = IWL_DEFAULT_TX_RETRY;
+       tx_cmd->data_retry_limit = data_retry_limit;
+
        if (tx_id >= IWL_CMD_QUEUE_NUM)
                rts_retry_limit = 3;
        else
                rts_retry_limit = 7;
 
-       if (ieee80211_is_probe_resp(fc)) {
-               data_retry_limit = 3;
-               if (data_retry_limit < rts_retry_limit)
-                       rts_retry_limit = data_retry_limit;
-       } else
-               data_retry_limit = IWL_DEFAULT_TX_RETRY;
-
-       if (priv->data_retry_limit != -1)
-               data_retry_limit = priv->data_retry_limit;
+       if (data_retry_limit < rts_retry_limit)
+               rts_retry_limit = data_retry_limit;
+       tx_cmd->rts_retry_limit = rts_retry_limit;
 
        if (ieee80211_is_mgmt(fc)) {
                switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
@@ -827,22 +860,20 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                }
        }
 
-       tx->rts_retry_limit = rts_retry_limit;
-       tx->data_retry_limit = data_retry_limit;
-       tx->rate = rate;
-       tx->tx_flags = tx_flags;
+       tx_cmd->rate = rate;
+       tx_cmd->tx_flags = tx_flags;
 
        /* OFDM */
-       tx->supp_rates[0] =
+       tx_cmd->supp_rates[0] =
           ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF;
 
        /* CCK */
-       tx->supp_rates[1] = (rate_mask & 0xF);
+       tx_cmd->supp_rates[1] = (rate_mask & 0xF);
 
        IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
                       "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
-                      tx->rate, le32_to_cpu(tx->tx_flags),
-                      tx->supp_rates[1], tx->supp_rates[0]);
+                      tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags),
+                      tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
 }
 
 u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
@@ -958,6 +989,11 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
 
        iwl3945_hw_txq_ctx_free(priv);
 
+       /* allocate tx queue structure */
+       rc = iwl_alloc_txq_mem(priv);
+       if (rc)
+               return rc;
+
        /* Tx CMD queue */
        rc = iwl3945_tx_reset(priv);
        if (rc)
@@ -982,57 +1018,15 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
        return rc;
 }
 
+
 /*
- * Start up NIC's basic functionality after it has been reset
- * (e.g. after platform boot, or shutdown via iwl3945_apm_stop())
+ * Start up 3945's basic functionality after it has been reset
+ * (e.g. after platform boot, or shutdown via iwl_apm_stop())
  * NOTE:  This does not load uCode nor start the embedded processor
  */
 static int iwl3945_apm_init(struct iwl_priv *priv)
 {
-       int ret;
-
-       iwl_power_initialize(priv);
-
-       /* Configure chip clock phase-lock-loop */
-       iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL);
-
-       /*
-        * Disable L0S exit timer (platform NMI Work/Around)
-        * (does this do anything on 3945, or just 4965 and beyond?)
-        */
-       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-                         CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
-       /* Disable L0s without affecting L1; don't wait for ICH (L0s bug W/A) */
-       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-                         CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
-       /* Set FH wait threshold to maximum (HW error during stress W/A) */
-       iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
-
-       /*
-        * Set "initialization complete" bit to move adapter from
-        * D0U* --> D0A* (powered-up active) state.
-        */
-       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
-       /*
-        * Wait for clock stabilization; once stabilized, access to
-        * device-internal resources is supported, e.g. iwl_write_prph()
-        * and accesses to uCode SRAM.
-        */
-       ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
-                       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-                       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-       if (ret < 0) {
-               IWL_DEBUG_INFO(priv, "Failed to init the card\n");
-               goto out;
-       }
-
-       /* Enable DMA and BSM clocks, wait for them to stabilize */
-       iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
-                                               APMG_CLK_VAL_BSM_CLK_RQT);
-       udelay(20);
+       int ret = iwl_apm_init(priv);
 
        /* Clear APMG (NIC's internal power management) interrupts */
        iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
@@ -1043,11 +1037,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv)
        udelay(5);
        iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
 
-       /* Disable L1-Active */
-       iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
-                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-out:
        return ret;
 }
 
@@ -1172,12 +1161,16 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
        int txq_id;
 
        /* Tx queues */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-               if (txq_id == IWL_CMD_QUEUE_NUM)
-                       iwl_cmd_queue_free(priv);
-               else
-                       iwl_tx_queue_free(priv, txq_id);
+       if (priv->txq)
+               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
+                    txq_id++)
+                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                               iwl_cmd_queue_free(priv);
+                       else
+                               iwl_tx_queue_free(priv, txq_id);
 
+       /* free tx queue structure */
+       iwl_free_txq_mem(priv);
 }
 
 void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
@@ -1186,6 +1179,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
 
        /* stop SCD */
        iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
+       iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0);
 
        /* reset TFD queues */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
@@ -1806,7 +1800,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,
@@ -1835,14 +1829,13 @@ 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);
+       iwl_free_pages(priv, cmd.reply_page);
 
        return rc;
 }
@@ -1990,12 +1983,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        return 0;
 }
 
-/* will add 3945 channel switch cmd handling later */
-int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel)
-{
-       return 0;
-}
-
 /**
  * iwl3945_reg_txpower_periodic -  called when time to check our temperature.
  *
@@ -2505,11 +2492,10 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        }
 
        /* Assign number of Usable TX queues */
-       priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
+       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;
@@ -2821,6 +2807,7 @@ static struct iwl_lib_ops iwl3945_lib = {
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
        .get_hcmd_size = iwl3945_get_hcmd_size,
        .build_addsta_hcmd = iwl3945_build_addsta_hcmd,
+       .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
 };
 
 static struct iwl_ops iwl3945_ops = {
@@ -2840,7 +2827,11 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .eeprom_size = IWL3945_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
        .ops = &iwl3945_ops,
+       .num_of_queues = IWL39_NUM_QUEUES,
        .mod_params = &iwl3945_mod_params,
+       .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
+       .set_l0s = false,
+       .use_bsm = true,
        .use_isr_legacy = true,
        .ht_greenfield_support = false,
        .led_compensation = 64,
@@ -2855,6 +2846,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .eeprom_size = IWL3945_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
        .ops = &iwl3945_ops,
+       .num_of_queues = IWL39_NUM_QUEUES,
        .mod_params = &iwl3945_mod_params,
        .use_isr_legacy = true,
        .ht_greenfield_support = false,