iwlwifi: only add broadcast station once
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-3945.c
index 269b988..7f95f90 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>
@@ -44,8 +45,8 @@
 #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"
 
@@ -241,7 +242,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;
@@ -358,7 +359,7 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                     (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));
+       memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
 }
 
 /******************************************************************************
@@ -548,6 +549,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
        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 >
@@ -563,7 +565,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                return;
        }
 
-       skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
+       skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
        if (!skb) {
                IWL_ERR(priv, "alloc_skb failed\n");
                return;
@@ -574,15 +576,16 @@ 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(hdr->frame_control) ||
-           ieee80211_has_protected(hdr->frame_control) ||
-           ieee80211_has_morefrags(hdr->frame_control) ||
+       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
@@ -594,11 +597,15 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                goto out;
        }
 
-       iwl_update_stats(priv, false, hdr->frame_control, len);
+       /*
+        * 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);
 
+       ieee80211_rx(priv->hw, skb);
  out:
        priv->alloc_rxb_page--;
        rxb->page = NULL;
@@ -674,19 +681,13 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
                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,
+       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);
 
        header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
@@ -704,9 +705,10 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
        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->_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;
                priv->last_rx_noise = rx_status.noise;
        }
 
@@ -955,7 +957,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 |
@@ -1605,7 +1607,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;
@@ -1731,7 +1733,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;
@@ -1828,8 +1830,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
                rc = -EIO;
        }
 
-       priv->alloc_rxb_page--;
-       free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
+       iwl_free_pages(priv, cmd.reply_page);
 
        return rc;
 }
@@ -1910,6 +1911,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"
@@ -1940,7 +1943,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 */
@@ -1950,13 +1956,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) &&
@@ -1977,12 +1976,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.
  *
@@ -2007,13 +2000,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;
@@ -2149,7 +2142,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);
@@ -2233,7 +2226,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 */
@@ -2341,7 +2334,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);
 
@@ -2441,7 +2434,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;
@@ -2480,12 +2473,11 @@ 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;
@@ -2548,13 +2540,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 */
@@ -2802,6 +2794,7 @@ 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,
 };
 
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
@@ -2810,7 +2803,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
        .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
 };
 
-static struct iwl_ops iwl3945_ops = {
+static const struct iwl_ops iwl3945_ops = {
        .ucode = &iwl3945_ucode,
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
@@ -2835,6 +2828,8 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .use_isr_legacy = true,
        .ht_greenfield_support = false,
        .led_compensation = 64,
+       .broken_powersave = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2851,9 +2846,11 @@ 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,
 };
 
-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)},