]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/wireless/iwlwifi/iwl3945-base.c
iwlwifi: manage QoS by mac stack
[net-next-2.6.git] / drivers / net / wireless / iwlwifi / iwl3945-base.c
index f8e4e4b18d02bee66f711e29080c4cc2b8a6366a..24c240d53f5ce90ecc29d434f68132426072e6f9 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
 #include "iwl-commands.h"
 #include "iwl-sta.h"
 #include "iwl-3945.h"
-#include "iwl-helpers.h"
 #include "iwl-core.h"
+#include "iwl-helpers.h"
 #include "iwl-dev.h"
+#include "iwl-spectrum.h"
 
 /*
  * module name, copyright, version, etc.
 #define VD
 #endif
 
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-#define VS "s"
-#else
-#define VS
-#endif
-
-#define DRV_VERSION  IWLWIFI_VERSION VD VS
-#define DRV_COPYRIGHT  "Copyright(c) 2003-2009 Intel Corporation"
+/*
+ * add "s" to indicate spectrum measurement included.
+ * we add it here to be consistent with previous releases in which
+ * this was configurable.
+ */
+#define DRV_VERSION  IWLWIFI_VERSION VD "s"
+#define DRV_COPYRIGHT  "Copyright(c) 2003-2010 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -351,11 +351,11 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
 
 static void iwl3945_unset_hw_params(struct iwl_priv *priv)
 {
-       if (priv->shared_virt)
-               pci_free_consistent(priv->pci_dev,
-                                   sizeof(struct iwl3945_shared),
-                                   priv->shared_virt,
-                                   priv->shared_phys);
+       if (priv->_3945.shared_virt)
+               dma_free_coherent(&priv->pci_dev->dev,
+                                 sizeof(struct iwl3945_shared),
+                                 priv->_3945.shared_virt,
+                                 priv->_3945.shared_phys);
 }
 
 static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
@@ -478,7 +478,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        u8 wait_write_ptr = 0;
        u8 *qc = NULL;
        unsigned long flags;
-       int rc;
 
        spin_lock_irqsave(&priv->lock, flags);
        if (iwl_is_rfkill(priv)) {
@@ -505,15 +504,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
 #endif
 
-       /* drop all non-injected data frame if we are not associated */
-       if (ieee80211_is_data(fc) &&
-           !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
-           (!iwl_is_associated(priv) ||
-            ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
-               IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n");
-               goto drop_unlock;
-       }
-
        spin_unlock_irqrestore(&priv->lock, flags);
 
        hdr_len = ieee80211_hdrlen(fc);
@@ -663,12 +653,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        /* Tell device the write index *just past* this latest filled TFD */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       rc = iwl_txq_update_write_ptr(priv, txq);
+       iwl_txq_update_write_ptr(priv, txq);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       if (rc)
-               return rc;
-
        if ((iwl_queue_space(q) < q->high_mark)
            && priv->mac80211_registered) {
                if (wait_write_ptr) {
@@ -689,10 +676,6 @@ drop:
        return -1;
 }
 
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-
-#include "iwl-spectrum.h"
-
 #define BEACON_TIME_MASK_LOW   0x00FFFFFF
 #define BEACON_TIME_MASK_HIGH  0xFF000000
 #define TIME_UNIT              1024
@@ -761,7 +744,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        if (iwl_is_associated(priv))
                add_time =
                    iwl3945_usecs_to_beacons(
-                       le64_to_cpu(params->start_time) - priv->last_tsf,
+                       le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
                        le16_to_cpu(priv->rxon_timing.beacon_interval));
 
        memset(&spectrum, 0, sizeof(spectrum));
@@ -775,7 +758,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
 
        if (iwl_is_associated(priv))
                spectrum.start_time =
-                   iwl3945_add_beacon_time(priv->last_beacon_time,
+                   iwl3945_add_beacon_time(priv->_3945.last_beacon_time,
                                add_time,
                                le16_to_cpu(priv->rxon_timing.beacon_interval));
        else
@@ -819,7 +802,6 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
 
        return rc;
 }
-#endif
 
 static void iwl3945_rx_reply_alive(struct iwl_priv *priv,
                               struct iwl_rx_mem_buffer *rxb)
@@ -962,6 +944,8 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta;
        priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
        priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+       priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+                       iwl_rx_spectrum_measure_notif;
        priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
        priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
            iwl_rx_pm_debug_statistics_notif;
@@ -975,7 +959,6 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
 
-       iwl_setup_spectrum_handlers(priv);
        iwl_setup_rx_scan_handlers(priv);
        priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif;
 
@@ -1067,13 +1050,13 @@ static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl_priv *priv,
  * also updates the memory address in the firmware to reference the new
  * target buffer.
  */
-static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
+static void iwl3945_rx_queue_restock(struct iwl_priv *priv)
 {
        struct iwl_rx_queue *rxq = &priv->rxq;
        struct list_head *element;
        struct iwl_rx_mem_buffer *rxb;
        unsigned long flags;
-       int write, rc;
+       int write;
 
        spin_lock_irqsave(&rxq->lock, flags);
        write = rxq->write & ~0x7;
@@ -1103,12 +1086,8 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
                spin_lock_irqsave(&rxq->lock, flags);
                rxq->need_update = 1;
                spin_unlock_irqrestore(&rxq->lock, flags);
-               rc = iwl_rx_queue_update_write_ptr(priv, rxq);
-               if (rc)
-                       return rc;
+               iwl_rx_queue_update_write_ptr(priv, rxq);
        }
-
-       return 0;
 }
 
 /**
@@ -1253,10 +1232,10 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
                }
        }
 
-       pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-                           rxq->dma_addr);
-       pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
-                           rxq->rb_stts, rxq->rb_stts_dma);
+       dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+                         rxq->dma_addr);
+       dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
+                         rxq->rb_stts, rxq->rb_stts_dma);
        rxq->bd = NULL;
        rxq->rb_stts  = NULL;
 }
@@ -1518,8 +1497,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
  * iwl3945_print_event_log - Dump error event log to syslog
  *
  */
-static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
+static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                                 u32 num_events, u32 mode,
+                                 int pos, char **buf, size_t bufsz)
 {
        u32 i;
        u32 base;       /* SRAM byte address of event log header */
@@ -1529,7 +1509,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
        unsigned long reg_flags;
 
        if (num_events == 0)
-               return;
+               return pos;
 
        base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
 
@@ -1555,26 +1535,43 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
                time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
                        /* data, ev */
-                       IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "0x%08x:%04u\n",
+                                               time, ev);
+                       } else {
+                               IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, 0,
+                                                             time, ev);
+                       }
                } else {
                        data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-                       IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "%010u:0x%08x:%04u\n",
+                                                time, data, ev);
+                       } else {
+                               IWL_ERR(priv, "%010u\t0x%08x\t%04u\n",
+                                       time, data, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, time,
+                                                             data, ev);
+                       }
                }
        }
 
        /* Allow device to power down */
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+       return pos;
 }
 
 /**
  * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog
  */
-static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
                                      u32 num_wraps, u32 next_entry,
-                                     u32 size, u32 mode)
+                                     u32 size, u32 mode,
+                                     int pos, char **buf, size_t bufsz)
 {
        /*
         * display the newest DEFAULT_LOG_ENTRIES entries
@@ -1582,21 +1579,28 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
         */
        if (num_wraps) {
                if (next_entry < size) {
-                       iwl3945_print_event_log(priv,
-                                       capacity - (size - next_entry),
-                                       size - next_entry, mode);
-                       iwl3945_print_event_log(priv, 0,
-                                   next_entry, mode);
+                       pos = iwl3945_print_event_log(priv,
+                                            capacity - (size - next_entry),
+                                            size - next_entry, mode,
+                                            pos, buf, bufsz);
+                       pos = iwl3945_print_event_log(priv, 0,
+                                                     next_entry, mode,
+                                                     pos, buf, bufsz);
                } else
-                       iwl3945_print_event_log(priv, next_entry - size,
-                                   size, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry - size,
+                                                     size, mode,
+                                                     pos, buf, bufsz);
        } else {
                if (next_entry < size)
-                       iwl3945_print_event_log(priv, 0, next_entry, mode);
+                       pos = iwl3945_print_event_log(priv, 0,
+                                                     next_entry, mode,
+                                                     pos, buf, bufsz);
                else
-                       iwl3945_print_event_log(priv, next_entry - size,
-                                           size, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry - size,
+                                                     size, mode,
+                                                     pos, buf, bufsz);
        }
+       return pos;
 }
 
 /* For sanity check only.  Actual size is determined by uCode, typ. 512 */
@@ -1604,7 +1608,8 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
 
 #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
 
-void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
+int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1612,11 +1617,13 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        u32 num_wraps;  /* # times uCode wrapped to top of log */
        u32 next_entry; /* index of next entry to be written by uCode */
        u32 size;       /* # entries that we'll print */
+       int pos = 0;
+       size_t bufsz = 0;
 
        base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
        if (!iwl3945_hw_valid_rtc_data_addr(base)) {
                IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
-               return;
+               return  -EINVAL;
        }
 
        /* event log header */
@@ -1642,7 +1649,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        /* bail out if nothing in log */
        if (size == 0) {
                IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-               return;
+               return pos;
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1658,25 +1665,38 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                  size);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               if (full_log)
+                       bufsz = capacity * 48;
+               else
+                       bufsz = size * 48;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return -ENOMEM;
+       }
        if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
                /* if uCode has wrapped back to top of log,
                 * start at the oldest entry,
                 * i.e the next one that uCode would fill.
                 */
                if (num_wraps)
-                       iwl3945_print_event_log(priv, next_entry,
-                                   capacity - next_entry, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry,
+                                               capacity - next_entry, mode,
+                                               pos, buf, bufsz);
 
                /* (then/else) start at top of log */
-               iwl3945_print_event_log(priv, 0, next_entry, mode);
+               pos = iwl3945_print_event_log(priv, 0, next_entry, mode,
+                                             pos, buf, bufsz);
        } else
-               iwl3945_print_last_event_logs(priv, capacity, num_wraps,
-                                       next_entry, size, mode);
+               pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                                                   next_entry, size, mode,
+                                                   pos, buf, bufsz);
 #else
-       iwl3945_print_last_event_logs(priv, capacity, num_wraps,
-                               next_entry, size, mode);
+       pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                                           next_entry, size, mode,
+                                           pos, buf, bufsz);
 #endif
-
+       return pos;
 }
 
 static void iwl3945_irq_tasklet(struct iwl_priv *priv)
@@ -2460,8 +2480,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       iwl_clear_stations_table(priv);
-
        rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
        IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill);
 
@@ -2483,13 +2501,19 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        /* After the ALIVE response, we can send commands to 3945 uCode */
        set_bit(STATUS_ALIVE, &priv->status);
 
+       if (priv->cfg->ops->lib->recover_from_tx_stall) {
+               /* Enable timer to monitor the driver queues */
+               mod_timer(&priv->monitor_recover,
+                       jiffies +
+                       msecs_to_jiffies(priv->cfg->monitor_recover_period));
+       }
+
        if (iwl_is_rfkill(priv))
                return;
 
        ieee80211_wake_queues(priv->hw);
 
-       priv->active_rate = priv->rates_mask;
-       priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+       priv->active_rate = IWL_RATES_MASK;
 
        iwl_power_update_mode(priv, true);
 
@@ -2518,17 +2542,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        set_bit(STATUS_READY, &priv->status);
        wake_up_interruptible(&priv->wait_command_queue);
 
-       /* reassociate for ADHOC mode */
-       if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
-               struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
-                                                               priv->vif);
-               if (beacon)
-                       iwl_mac_beacon_update(priv->hw, beacon);
-       }
-
-       if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status))
-               iwl_set_mode(priv, priv->iw_mode);
-
        return;
 
  restart:
@@ -2550,7 +2563,8 @@ static void __iwl3945_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       iwl_clear_stations_table(priv);
+       /* Station information will now be cleared in device */
+       iwl_clear_ucode_stations(priv, true);
 
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2684,12 +2698,10 @@ static int __iwl3945_up(struct iwl_priv *priv)
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
-               iwl_clear_stations_table(priv);
-
                /* load bootstrap state machine,
                 * load bootstrap program into processor's memory,
                 * prepare to load the "initialize" uCode */
-               priv->cfg->ops->lib->load_ucode(priv);
+               rc = priv->cfg->ops->lib->load_ucode(priv);
 
                if (rc) {
                        IWL_ERR(priv,
@@ -2757,7 +2769,7 @@ static void iwl3945_bg_alive_start(struct work_struct *data)
 static void iwl3945_rfkill_poll(struct work_struct *data)
 {
        struct iwl_priv *priv =
-           container_of(data, struct iwl_priv, rfkill_poll.work);
+           container_of(data, struct iwl_priv, _3945.rfkill_poll.work);
        bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status);
        bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL)
                        & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
@@ -2776,7 +2788,7 @@ static void iwl3945_rfkill_poll(struct work_struct *data)
 
        /* Keep this running, even if radio now enabled.  This will be
         * cancelled in mac_start() if system decides to start again */
-       queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
+       queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll,
                           round_jiffies_relative(2 * HZ));
 
 }
@@ -2791,7 +2803,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                .len = sizeof(struct iwl3945_scan_cmd),
                .flags = CMD_SIZE_HUGE,
        };
-       int rc = 0;
        struct iwl3945_scan_cmd *scan;
        struct ieee80211_conf *conf = NULL;
        u8 n_probes = 0;
@@ -2819,7 +2830,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
        if (test_bit(STATUS_SCAN_HW, &priv->status)) {
                IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests  "
                                "Ignoring second request.\n");
-               rc = -EIO;
                goto done;
        }
 
@@ -2854,7 +2864,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                priv->scan = kmalloc(sizeof(struct iwl3945_scan_cmd) +
                                     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
                if (!priv->scan) {
-                       rc = -ENOMEM;
+                       IWL_DEBUG_SCAN(priv, "Fail to allocate scan memory\n");
                        goto done;
                }
        }
@@ -2897,7 +2907,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                               scan_suspend_time, interval);
        }
 
-       if (priv->scan_request->n_ssids) {
+       if (priv->is_internal_short_scan) {
+               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+       } else if (priv->scan_request->n_ssids) {
                int i, p = 0;
                IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
                for (i = 0; i < priv->scan_request->n_ssids; i++) {
@@ -2944,13 +2956,20 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                goto done;
        }
 
-       scan->tx_cmd.len = cpu_to_le16(
+       if (!priv->is_internal_short_scan) {
+               scan->tx_cmd.len = cpu_to_le16(
                        iwl_fill_probe_req(priv,
                                (struct ieee80211_mgmt *)scan->data,
                                priv->scan_request->ie,
                                priv->scan_request->ie_len,
                                IWL_MAX_SCAN_SIZE - sizeof(*scan)));
-
+       } else {
+               scan->tx_cmd.len = cpu_to_le16(
+                       iwl_fill_probe_req(priv,
+                               (struct ieee80211_mgmt *)scan->data,
+                               NULL, 0,
+                               IWL_MAX_SCAN_SIZE - sizeof(*scan)));
+       }
        /* select Rx antennas */
        scan->flags |= iwl3945_get_antenna_flags(priv);
 
@@ -2972,8 +2991,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
        scan->len = cpu_to_le16(cmd.len);
 
        set_bit(STATUS_SCAN_HW, &priv->status);
-       rc = iwl_send_cmd_sync(priv, &cmd);
-       if (rc)
+       if (iwl_send_cmd_sync(priv, &cmd))
                goto done;
 
        queue_delayed_work(priv->workqueue, &priv->scan_check,
@@ -2996,18 +3014,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
        mutex_unlock(&priv->mutex);
 }
 
-static void iwl3945_bg_up(struct work_struct *data)
-{
-       struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       mutex_lock(&priv->mutex);
-       __iwl3945_up(priv);
-       mutex_unlock(&priv->mutex);
-}
-
 static void iwl3945_bg_restart(struct work_struct *data)
 {
        struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
@@ -3024,7 +3030,13 @@ static void iwl3945_bg_restart(struct work_struct *data)
                ieee80211_restart_hw(priv->hw);
        } else {
                iwl3945_down(priv);
-               queue_work(priv->workqueue, &priv->up);
+
+               if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+                       return;
+
+               mutex_lock(&priv->mutex);
+               __iwl3945_up(priv);
+               mutex_unlock(&priv->mutex);
        }
 }
 
@@ -3111,12 +3123,13 @@ void iwl3945_post_associate(struct iwl_priv *priv)
        case NL80211_IFTYPE_ADHOC:
 
                priv->assoc_id = 1;
-               iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL);
+               iwl_add_local_station(priv, priv->bssid, false);
                iwl3945_sync_sta(priv, IWL_STA_ID,
-                                (priv->band == IEEE80211_BAND_5GHZ) ?
-                                IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
+                               (priv->band == IEEE80211_BAND_5GHZ) ?
+                               IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
                                 CMD_ASYNC);
                iwl3945_rate_scale_init(priv->hw, IWL_STA_ID);
+
                iwl3945_send_beacon_cmd(priv);
 
                break;
@@ -3127,8 +3140,6 @@ void iwl3945_post_associate(struct iwl_priv *priv)
                break;
        }
 
-       iwl_activate_qos(priv, 0);
-
        /* we have just associated, don't start scan too early */
        priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 }
@@ -3189,7 +3200,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
 
        /* ucode is running and will send rfkill notifications,
         * no need to poll the killswitch state anymore */
-       cancel_delayed_work(&priv->rfkill_poll);
+       cancel_delayed_work(&priv->_3945.rfkill_poll);
 
        iwl_led_start(priv);
 
@@ -3230,7 +3241,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
        flush_workqueue(priv->workqueue);
 
        /* start polling the killswitch state again */
-       queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
+       queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll,
                           round_jiffies_relative(2 * HZ));
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3301,7 +3312,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
-               iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL);
+               iwl_add_local_station(priv, iwl_bcast_addr, false);
        }
        iwl3945_send_beacon_cmd(priv);
 
@@ -3342,7 +3353,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, 100);
-       mutex_unlock(&priv->mutex);
 
        switch (cmd) {
        case SET_KEY:
@@ -3363,11 +3373,44 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                ret = -EINVAL;
        }
 
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return ret;
 }
 
+static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+       bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION;
+       u8 sta_id;
+
+       IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
+                       sta->addr);
+
+       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
+                                    &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+                       sta->addr, ret);
+               /* Should we return success if return code is EEXIST ? */
+               return ret;
+       }
+
+       /* Initialize rate scaling */
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM \n",
+                      sta->addr);
+       iwl3945_rs_rate_init(priv, sta, sta_id);
+
+       return 0;
+
+
+
+       return ret;
+}
 /*****************************************************************************
  *
  * sysfs attributes
@@ -3528,8 +3571,6 @@ static ssize_t store_filter_flags(struct device *d,
 static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
                   store_filter_flags);
 
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-
 static ssize_t show_measurement(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
@@ -3569,7 +3610,7 @@ static ssize_t store_measurement(struct device *d,
        struct iwl_priv *priv = dev_get_drvdata(d);
        struct ieee80211_measurement_params params = {
                .channel = le16_to_cpu(priv->active_rxon.channel),
-               .start_time = cpu_to_le64(priv->last_tsf),
+               .start_time = cpu_to_le64(priv->_3945.last_tsf),
                .duration = cpu_to_le16(1),
        };
        u8 type = IWL_MEASURE_BASIC;
@@ -3599,7 +3640,6 @@ static ssize_t store_measurement(struct device *d,
 
 static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
                   show_measurement, store_measurement);
-#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */
 
 static ssize_t store_retry_rate(struct device *d,
                                struct device_attribute *attr,
@@ -3640,7 +3680,7 @@ static ssize_t show_statistics(struct device *d,
        struct iwl_priv *priv = dev_get_drvdata(d);
        u32 size = sizeof(struct iwl3945_notif_statistics);
        u32 len = 0, ofs = 0;
-       u8 *data = (u8 *)&priv->statistics_39;
+       u8 *data = (u8 *)&priv->_3945.statistics;
        int rc = 0;
 
        if (!iwl_is_alive(priv))
@@ -3748,13 +3788,12 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
 
        init_waitqueue_head(&priv->wait_command_queue);
 
-       INIT_WORK(&priv->up, iwl3945_bg_up);
        INIT_WORK(&priv->restart, iwl3945_bg_restart);
        INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish);
        INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
-       INIT_DELAYED_WORK(&priv->rfkill_poll, iwl3945_rfkill_poll);
+       INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll);
        INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
        INIT_WORK(&priv->request_scan, iwl3945_bg_request_scan);
        INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
@@ -3762,6 +3801,13 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
 
        iwl3945_hw_setup_deferred_work(priv);
 
+       if (priv->cfg->ops->lib->recover_from_tx_stall) {
+               init_timer(&priv->monitor_recover);
+               priv->monitor_recover.data = (unsigned long)priv;
+               priv->monitor_recover.function =
+                       priv->cfg->ops->lib->recover_from_tx_stall;
+       }
+
        tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                     iwl3945_irq_tasklet, (unsigned long)priv);
 }
@@ -3774,6 +3820,8 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work(&priv->scan_check);
        cancel_delayed_work(&priv->alive_start);
        cancel_work_sync(&priv->beacon_update);
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
 }
 
 static struct attribute *iwl3945_sysfs_entries[] = {
@@ -3782,9 +3830,7 @@ static struct attribute *iwl3945_sysfs_entries[] = {
        &dev_attr_dump_errors.attr,
        &dev_attr_flags.attr,
        &dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
        &dev_attr_measurement.attr,
-#endif
        &dev_attr_retry_rate.attr,
        &dev_attr_statistics.attr,
        &dev_attr_status.attr,
@@ -3810,11 +3856,12 @@ static struct ieee80211_ops iwl3945_hw_ops = {
        .config = iwl_mac_config,
        .configure_filter = iwl_configure_filter,
        .set_key = iwl3945_mac_set_key,
-       .get_tx_stats = iwl_mac_get_tx_stats,
        .conf_tx = iwl_mac_conf_tx,
        .reset_tsf = iwl_mac_reset_tsf,
        .bss_info_changed = iwl_bss_info_changed,
-       .hw_scan = iwl_mac_hw_scan
+       .hw_scan = iwl_mac_hw_scan,
+       .sta_add = iwl3945_mac_sta_add,
+       .sta_remove = iwl_mac_sta_remove,
 };
 
 static int iwl3945_init_drv(struct iwl_priv *priv)
@@ -3831,22 +3878,15 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        INIT_LIST_HEAD(&priv->free_frames);
 
        mutex_init(&priv->mutex);
-
-       /* Clear the driver's (not device's) station table */
-       iwl_clear_stations_table(priv);
+       mutex_init(&priv->sync_cmd_mutex);
 
        priv->ieee_channels = NULL;
        priv->ieee_rates = NULL;
        priv->band = IEEE80211_BAND_2GHZ;
 
        priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
 
-       iwl_reset_qos(priv);
-
-       priv->qos_data.qos_active = 0;
-       priv->qos_data.qos_cap.val = 0;
-
-       priv->rates_mask = IWL_RATES_MASK;
        priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
 
        if (eeprom->version < EEPROM_3945_EEPROM_VERSION) {
@@ -4022,6 +4062,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        spin_lock_init(&priv->reg_lock);
        spin_lock_init(&priv->lock);
 
+       /*
+        * stop and reset the on-board processor just in case it is in a
+        * strange state ... like being left stranded by a primary kernel
+        * and this is now the kdump kernel trying to start up
+        */
+       iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
        /***********************
         * 4. Read EEPROM
         * ********************/
@@ -4104,7 +4151,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
 
        /* Start monitoring the killswitch */
-       queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
+       queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll,
                           2 * HZ);
 
        return 0;
@@ -4178,7 +4225,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
        sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
-       cancel_delayed_work_sync(&priv->rfkill_poll);
+       cancel_delayed_work_sync(&priv->_3945.rfkill_poll);
 
        iwl3945_dealloc_ucode_pci(priv);
 
@@ -4187,7 +4234,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
        iwl3945_hw_txq_ctx_free(priv);
 
        iwl3945_unset_hw_params(priv);
-       iwl_clear_stations_table(priv);
 
        /*netif_stop_queue(dev); */
        flush_workqueue(priv->workqueue);