iwlwifi: remove stray mutex_unlock()
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-3945.c
index eb874e0..3faa78c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -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>
 #include "iwl-sta.h"
 #include "iwl-3945.h"
 #include "iwl-eeprom.h"
-#include "iwl-helpers.h"
 #include "iwl-core.h"
+#include "iwl-helpers.h"
 #include "iwl-led.h"
 #include "iwl-3945-led.h"
+#include "iwl-3945-debugfs.h"
 
 #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
        [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,   \
@@ -183,19 +185,19 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
 {
        int idx;
 
-       for (idx = 0; idx < IWL_RATE_COUNT; idx++)
+       for (idx = 0; idx < IWL_RATE_COUNT_3945; idx++)
                if (iwl3945_rates[idx].plcp == plcp)
                        return idx;
        return -1;
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x
 
 static const char *iwl3945_get_tx_fail_reason(u32 status)
 {
        switch (status & TX_STATUS_MSK) {
-       case TX_STATUS_SUCCESS:
+       case TX_3945_STATUS_SUCCESS:
                return "SUCCESS";
                TX_STATUS_ENTRY(SHORT_LIMIT);
                TX_STATUS_ENTRY(LONG_LIMIT);
@@ -241,7 +243,7 @@ int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate)
                        next_rate = IWL_RATE_6M_INDEX;
                break;
        case IEEE80211_BAND_2GHZ:
-               if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+               if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
                    iwl_is_associated(priv)) {
                        if (rate == IWL_RATE_11M_INDEX)
                                next_rate = IWL_RATE_5M_INDEX;
@@ -291,9 +293,9 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
  * iwl3945_rx_reply_tx - Handle Tx response
  */
 static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb)
+                               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);
@@ -349,20 +351,81 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
  *  RX handler implementations
  *
  *****************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+/*
+ *  based on the assumption of all statistics counter are in DWORD
+ *  FIXME: This function is for debugging, do not deal with
+ *  the case of counters roll-over.
+ */
+static void iwl3945_accumulative_statistics(struct iwl_priv *priv,
+                                           __le32 *stats)
+{
+       int i;
+       __le32 *prev_stats;
+       u32 *accum_stats;
+       u32 *delta, *max_delta;
+
+       prev_stats = (__le32 *)&priv->_3945.statistics;
+       accum_stats = (u32 *)&priv->_3945.accum_statistics;
+       delta = (u32 *)&priv->_3945.delta_statistics;
+       max_delta = (u32 *)&priv->_3945.max_delta;
+
+       for (i = sizeof(__le32); i < sizeof(struct iwl3945_notif_statistics);
+            i += sizeof(__le32), stats++, prev_stats++, delta++,
+            max_delta++, accum_stats++) {
+               if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+                       *delta = (le32_to_cpu(*stats) -
+                               le32_to_cpu(*prev_stats));
+                       *accum_stats += *delta;
+                       if (*delta > *max_delta)
+                               *max_delta = *delta;
+               }
+       }
+
+       /* reset accumulative statistics for "no-counter" type statistics */
+       priv->_3945.accum_statistics.general.temperature =
+               priv->_3945.statistics.general.temperature;
+       priv->_3945.accum_statistics.general.ttl_timestamp =
+               priv->_3945.statistics.general.ttl_timestamp;
+}
+#endif
 
 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);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
+#endif
+
+       memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
+}
 
-       memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
+void iwl3945_reply_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       __le32 *flag = (__le32 *)&pkt->u.raw;
 
-       iwl_leds_background(priv);
+       if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+               memset(&priv->_3945.accum_statistics, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+               memset(&priv->_3945.delta_statistics, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+               memset(&priv->_3945.max_delta, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+#endif
+               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+       }
+       iwl3945_hw_rx_statistics(priv, rxb);
 }
 
+
 /******************************************************************************
  *
  * Misc. internal state and helper functions
@@ -487,7 +550,7 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
                 *    but you can hack it to show more, if you'd like to. */
                if (dataframe)
                        IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
-                                    "len=%u, rssi=%d, chnl=%d, rate=%d, \n",
+                                    "len=%u, rssi=%d, chnl=%d, rate=%d,\n",
                                     title, le16_to_cpu(fc), header->addr1[5],
                                     length, rssi, channel, rate);
                else {
@@ -543,14 +606,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;
+       __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;
        }
@@ -562,20 +628,26 @@ 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 = dev_alloc_skb(128);
+       if (!skb) {
+               IWL_ERR(priv, "dev_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_add_rx_frag(skb, 0, rxb->page,
+                       (void *)rx_hdr->payload - (void *)pkt, len);
 
-       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);
+       priv->alloc_rxb_page--;
+       rxb->page = NULL;
 }
 
 #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
@@ -585,13 +657,12 @@ 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);
-       int snr;
-       u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
-       u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
+       u16 rx_stats_sig_avg __maybe_unused = le16_to_cpu(rx_stats->sig_avg);
+       u16 rx_stats_noise_diff __maybe_unused = le16_to_cpu(rx_stats->noise_diff);
        u8 network_packet;
 
        rx_status.flag = 0;
@@ -629,59 +700,29 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
        /* Convert 3945's rssi indicator to dBm */
        rx_status.signal = rx_stats->rssi - IWL39_RSSI_OFFSET;
 
-       /* Set default noise value to -127 */
-       if (priv->last_rx_noise == 0)
-               priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-       /* 3945 provides noise info for OFDM frames only.
-        * sig_avg and noise_diff are measured by the 3945's digital signal
-        *   processor (DSP), and indicate linear levels of signal level and
-        *   distortion/noise within the packet preamble after
-        *   automatic gain control (AGC).  sig_avg should stay fairly
-        *   constant if the radio's AGC is working well.
-        * Since these values are linear (not dB or dBm), linear
-        *   signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
-        * Convert linear SNR to dB SNR, then subtract that from rssi dBm
-        *   to obtain noise level in dBm.
-        * Calculate rx_status.signal (quality indicator in %) based on SNR. */
-       if (rx_stats_noise_diff) {
-               snr = rx_stats_sig_avg / rx_stats_noise_diff;
-               rx_status.noise = rx_status.signal -
-                                       iwl3945_calc_db_from_ratio(snr);
-               rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal,
-                                                        rx_status.noise);
-
-       /* If noise info not available, calculate signal quality indicator (%)
-        *   using just the dBm signal level. */
-       } else {
-               rx_status.noise = priv->last_rx_noise;
-               rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0);
-       }
-
-
-       IWL_DEBUG_STATS(priv, "Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
-                       rx_status.signal, rx_status.noise, rx_status.qual,
-                       rx_stats_sig_avg, rx_stats_noise_diff);
+       IWL_DEBUG_STATS(priv, "Rssi %d sig_avg %d noise_diff %d\n",
+                       rx_status.signal, rx_stats_sig_avg,
+                       rx_stats_noise_diff);
 
        header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 
        network_packet = iwl3945_is_network_packet(priv, header);
 
-       IWL_DEBUG_STATS_LIMIT(priv, "[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
+       IWL_DEBUG_STATS_LIMIT(priv, "[%c] %d RSSI:%d Signal:%u, Rate:%u\n",
                              network_packet ? '*' : ' ',
                              le16_to_cpu(rx_hdr->channel),
                              rx_status.signal, rx_status.signal,
-                             rx_status.noise, rx_status.rate_idx);
+                             rx_status.rate_idx);
 
        /* Set "1" to report good data frames in groups of 100 */
        iwl3945_dbg_report_frame(priv, pkt, header, 1);
        iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
 
        if (network_packet) {
-               priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
-               priv->last_tsf = le64_to_cpu(rx_end->timestamp);
-               priv->last_rx_rssi = rx_status.signal;
-               priv->last_rx_noise = rx_status.noise;
+               priv->_3945.last_beacon_time =
+                       le32_to_cpu(rx_end->beacon_timestamp);
+               priv->_3945.last_tsf = le64_to_cpu(rx_end->timestamp);
+               priv->_3945.last_rx_rssi = rx_status.signal;
        }
 
        iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
@@ -778,7 +819,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                                  int sta_id, int tx_id)
 {
        u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
-       u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
+       u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT_3945);
        u16 rate_mask;
        int rate;
        u8 rts_retry_limit;
@@ -794,17 +835,22 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
         * 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 (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)) {
@@ -822,8 +868,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                }
        }
 
-       tx_cmd->rts_retry_limit = rts_retry_limit;
-       tx_cmd->data_retry_limit = data_retry_limit;
        tx_cmd->rate = rate;
        tx_cmd->tx_flags = tx_flags;
 
@@ -926,7 +970,7 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
        iwl_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005);
 
        iwl_write_direct32(priv, FH39_TSSR_CBB_BASE,
-                            priv->shared_phys);
+                            priv->_3945.shared_phys);
 
        iwl_write_direct32(priv, FH39_TSSR_MSG_CONFIG,
                FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
@@ -982,55 +1026,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;
-
-       /* 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);
@@ -1041,11 +1045,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;
 }
 
@@ -1063,7 +1062,7 @@ static void iwl3945_nic_config(struct iwl_priv *priv)
        IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id);
 
        if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
-               IWL_DEBUG_INFO(priv, "RTP type \n");
+               IWL_DEBUG_INFO(priv, "RTP type\n");
        else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
                IWL_DEBUG_INFO(priv, "3945 RADIO-MB type\n");
                iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
@@ -1188,6 +1187,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++) {
@@ -1620,7 +1620,7 @@ static int iwl3945_hw_reg_set_new_power(struct iwl_priv *priv,
        int power;
 
        /* Get this chnlgrp's rate-to-max/clip-powers table */
-       clip_pwrs = priv->clip39_groups[ch_info->group_index].clip_powers;
+       clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers;
 
        /* Get this channel's rate-to-current-power settings table */
        power_info = ch_info->power_info;
@@ -1746,7 +1746,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
                }
 
                /* Get this chnlgrp's rate-to-max/clip-powers table */
-               clip_pwrs = priv->clip39_groups[ch_info->group_index].clip_powers;
+               clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers;
 
                /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
                for (scan_tbl_index = 0;
@@ -1808,7 +1808,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,
@@ -1837,14 +1837,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;
 }
@@ -1925,6 +1924,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                                  "configuration (%d).\n", rc);
                        return rc;
                }
+               iwl_clear_ucode_stations(priv, false);
+               iwl_restore_stations(priv);
        }
 
        IWL_DEBUG_INFO(priv, "Sending RXON\n"
@@ -1955,7 +1956,10 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
 
        memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
 
-       iwl_clear_stations_table(priv);
+       if (!new_assoc) {
+               iwl_clear_ucode_stations(priv, false);
+               iwl_restore_stations(priv);
+       }
 
        /* If we issue a new RXON command which required a tune then we must
         * send a new TXPOWER command or we won't be able to Tx any frames */
@@ -1965,23 +1969,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                return rc;
        }
 
-       /* Add the broadcast address so we can send broadcast frames */
-       if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) ==
-           IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
-               return -EIO;
-       }
-
-       /* If we have set the ASSOC_MSK and we are in BSS mode then
-        * add the IWL_AP_ID to the station rate table */
-       if (iwl_is_associated(priv) &&
-           (priv->iw_mode == NL80211_IFTYPE_STATION))
-               if (iwl_add_station(priv, priv->active_rxon.bssid_addr,
-                               true, CMD_SYNC, NULL) == IWL_INVALID_STATION) {
-                       IWL_ERR(priv, "Error adding AP address for transmit\n");
-                       return -EIO;
-               }
-
        /* Init the hardware's rate fallback order based on the band */
        rc = iwl3945_init_hw_rate_table(priv);
        if (rc) {
@@ -1992,12 +1979,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.
  *
@@ -2022,13 +2003,13 @@ void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
 
  reschedule:
        queue_delayed_work(priv->workqueue,
-                          &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ);
+                          &priv->_3945.thermal_periodic, REG_RECALIB_PERIOD * HZ);
 }
 
 static void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work, struct iwl_priv,
-                                            thermal_periodic.work);
+                                            _3945.thermal_periodic.work);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -2164,14 +2145,14 @@ static void iwl3945_hw_reg_init_channel_groups(struct iwl_priv *priv)
                 *   power peaks, without too much distortion (clipping).
                 */
                /* we'll fill in this array with h/w max power levels */
-               clip_pwrs = (s8 *) priv->clip39_groups[i].clip_powers;
+               clip_pwrs = (s8 *) priv->_3945.clip_groups[i].clip_powers;
 
                /* divide factory saturation power by 2 to find -3dB level */
                satur_pwr = (s8) (group->saturation_power >> 1);
 
                /* fill in channel group's nominal powers for each rate */
                for (rate_index = 0;
-                    rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) {
+                    rate_index < IWL_RATE_COUNT_3945; rate_index++, clip_pwrs++) {
                        switch (rate_index) {
                        case IWL_RATE_36M_INDEX_TABLE:
                                if (i == 0)     /* B/G */
@@ -2248,7 +2229,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
                        iwl3945_hw_reg_get_ch_grp_index(priv, ch_info);
 
                /* Get this chnlgrp's rate->max/clip-powers table */
-               clip_pwrs = priv->clip39_groups[ch_info->group_index].clip_powers;
+               clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers;
 
                /* calculate power index *adjustment* value according to
                 *  diff between current temperature and factory temperature */
@@ -2356,7 +2337,7 @@ int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 {
        int txq_id = txq->q.id;
 
-       struct iwl3945_shared *shared_data = priv->shared_virt;
+       struct iwl3945_shared *shared_data = priv->_3945.shared_virt;
 
        shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
 
@@ -2456,7 +2437,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
                /* If an OFDM rate is used, have it fall back to the
                 * 1M CCK rates */
 
-               if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+               if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
                    iwl_is_associated(priv)) {
 
                        index = IWL_FIRST_CCK_RATE;
@@ -2495,14 +2476,12 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        memset((void *)&priv->hw_params, 0,
               sizeof(struct iwl_hw_params));
 
-       priv->shared_virt =
-           pci_alloc_consistent(priv->pci_dev,
-                                sizeof(struct iwl3945_shared),
-                                &priv->shared_phys);
-
-       if (!priv->shared_virt) {
+       priv->_3945.shared_virt =
+               dma_alloc_coherent(&priv->pci_dev->dev,
+                                  sizeof(struct iwl3945_shared),
+                                  &priv->_3945.shared_phys, GFP_KERNEL);
+       if (!priv->_3945.shared_virt) {
                IWL_ERR(priv, "failed to allocate pci memory\n");
-               mutex_unlock(&priv->mutex);
                return -ENOMEM;
        }
 
@@ -2510,8 +2489,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;
@@ -2564,13 +2542,13 @@ void iwl3945_hw_rx_handler_setup(struct iwl_priv *priv)
 
 void iwl3945_hw_setup_deferred_work(struct iwl_priv *priv)
 {
-       INIT_DELAYED_WORK(&priv->thermal_periodic,
+       INIT_DELAYED_WORK(&priv->_3945.thermal_periodic,
                          iwl3945_bg_reg_txpower_periodic);
 }
 
 void iwl3945_hw_cancel_deferred_work(struct iwl_priv *priv)
 {
-       cancel_delayed_work(&priv->thermal_periodic);
+       cancel_delayed_work(&priv->_3945.thermal_periodic);
 }
 
 /* check contents of special bootstrap uCode SRAM */
@@ -2772,6 +2750,7 @@ IWL3945_UCODE_GET(boot_size);
 static struct iwl_hcmd_ops iwl3945_hcmd = {
        .rxon_assoc = iwl3945_send_rxon_assoc,
        .commit_rxon = iwl3945_commit_rxon,
+       .send_bt_config = iwl_send_bt_config,
 };
 
 static struct iwl_ucode_ops iwl3945_ucode = {
@@ -2818,15 +2797,23 @@ static struct iwl_lib_ops iwl3945_lib = {
        .post_associate = iwl3945_post_associate,
        .isr = iwl_isr_legacy,
        .config_ap = iwl3945_config_ap,
+       .add_bcast_station = iwl3945_add_bcast_station,
+
+       .debugfs_ops = {
+               .rx_stats_read = iwl3945_ucode_rx_stats_read,
+               .tx_stats_read = iwl3945_ucode_tx_stats_read,
+               .general_stats_read = iwl3945_ucode_general_stats_read,
+       },
 };
 
 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,
+       .request_scan = iwl3945_request_scan,
 };
 
-static struct iwl_ops iwl3945_ops = {
+static const struct iwl_ops iwl3945_ops = {
        .ucode = &iwl3945_ucode,
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
@@ -2845,9 +2832,16 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .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,
+       .broken_powersave = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2864,9 +2858,13 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .use_isr_legacy = true,
        .ht_greenfield_support = false,
        .led_compensation = 64,
+       .broken_powersave = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
-struct pci_device_id iwl3945_hw_card_ids[] = {
+DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)},
        {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)},
        {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)},