Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-3945.c
index 0728054..99b876a 100644 (file)
@@ -50,6 +50,7 @@
 #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,   \
@@ -192,12 +193,12 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
 }
 
 #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);
@@ -243,7 +244,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;
@@ -293,7 +294,7 @@ 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 = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -351,18 +352,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 = 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->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
+       memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
 }
 
+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;
+
+       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 +551,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 {
@@ -549,7 +613,6 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
        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 */
@@ -566,9 +629,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                return;
        }
 
-       skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
+       skb = dev_alloc_skb(128);
        if (!skb) {
-               IWL_ERR(priv, "alloc_skb failed\n");
+               IWL_ERR(priv, "dev_alloc_skb failed\n");
                return;
        }
 
@@ -577,37 +640,13 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                                       (struct ieee80211_hdr *)rxb_addr(rxb),
                                       le32_to_cpu(rx_end->status), stats);
 
-       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.
-        */
-
        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;
 }
@@ -623,9 +662,8 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
        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;
@@ -663,53 +701,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);
-       } else {
-               rx_status.noise = priv->last_rx_noise;
-       }
-
-
-       IWL_DEBUG_STATS(priv, "Rssi %d noise %d sig_avg %d noise_diff %d\n",
-                       rx_status.signal, rx_status.noise,
-                       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);
@@ -957,7 +971,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 |
@@ -1049,7 +1063,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,
@@ -1607,7 +1621,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;
@@ -1733,7 +1747,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;
@@ -1911,6 +1925,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"
@@ -1941,7 +1957,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 */
@@ -1951,19 +1970,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                return rc;
        }
 
-       /* Add the broadcast address so we can send broadcast frames */
-       priv->cfg->ops->lib->add_bcast_station(priv);
-
-       /* 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) {
@@ -1998,13 +2004,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;
@@ -2140,7 +2146,7 @@ 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);
@@ -2224,7 +2230,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 */
@@ -2332,7 +2338,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);
 
@@ -2432,7 +2438,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;
@@ -2471,12 +2477,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 = dma_alloc_coherent(&priv->pci_dev->dev,
-                                              sizeof(struct iwl3945_shared),
-                                              &priv->shared_phys, GFP_KERNEL);
-       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;
        }
 
@@ -2537,13 +2543,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 */
@@ -2745,6 +2751,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 = {
@@ -2792,12 +2799,19 @@ static struct iwl_lib_ops iwl3945_lib = {
        .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 const struct iwl_ops iwl3945_ops = {
@@ -2827,6 +2841,8 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .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 = {
@@ -2845,6 +2861,8 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .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,
 };
 
 DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {