]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/iwlwifi/iwl4965-base.c
iwlwifi: do not schedule tasklet when rcv unused irq
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / iwlwifi / iwl4965-base.c
index c2366c2d23b769fb356a441e0391c10dfd21791c..131cf5adbd7967c2a564d414cfd45e561c123c20 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 
-#include <net/ieee80211_radiotap.h>
 #include <net/mac80211.h>
 
 #include <asm/div64.h>
@@ -70,6 +69,7 @@ static int iwl4965_param_antenna;  /* def: 0 = both antennas (use diversity) */
 int iwl4965_param_hwcrypto;        /* def: using software encryption */
 static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */
 int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */
+int iwl4965_param_amsdu_size_8K;   /* def: enable 8K amsdu size */
 
 /*
  * module name, copyright, version, etc.
@@ -90,7 +90,7 @@ int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */
 #define VS
 #endif
 
-#define IWLWIFI_VERSION "1.2.22k" VD VS
+#define IWLWIFI_VERSION "1.2.23k" VD VS
 #define DRV_COPYRIGHT  "Copyright(c) 2003-2007 Intel Corporation"
 #define DRV_VERSION     IWLWIFI_VERSION
 
@@ -349,7 +349,7 @@ int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
         * For the command queue (#4), allocate command space + one big
         * command for scan, since scan command is very huge; the system will
         * not have two scans at the same time, so only one is needed.
-        * For data Tx queues (all other queues), no super-size command
+        * For normal Tx queues (all other queues), no super-size command
         * space is needed.
         */
        len = sizeof(struct iwl4965_cmd) * slots_num;
@@ -497,7 +497,8 @@ static void iwl4965_clear_stations_table(struct iwl4965_priv *priv)
 /**
  * iwl4965_add_station_flags - Add station to tables in driver and device
  */
-u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, int is_ap, u8 flags)
+u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr,
+                               int is_ap, u8 flags, void *ht_data)
 {
        int i;
        int index = IWL_INVALID_STATION;
@@ -554,7 +555,8 @@ u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, int is_a
        /* BCAST station and IBSS stations do not work in HT mode */
        if (index != priv->hw_setting.bcast_sta_id &&
            priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
-               iwl4965_set_ht_add_station(priv, index);
+               iwl4965_set_ht_add_station(priv, index,
+                                (struct ieee80211_ht_info *) ht_data);
 #endif /*CONFIG_IWL4965_HT*/
 
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -900,7 +902,19 @@ static int iwl4965_rxon_add_station(struct iwl4965_priv *priv,
        u8 sta_id;
 
        /* Add station to device's station table */
-       sta_id = iwl4965_add_station_flags(priv, addr, is_ap, 0);
+#ifdef CONFIG_IWL4965_HT
+       struct ieee80211_conf *conf = &priv->hw->conf;
+       struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
+
+       if ((is_ap) &&
+           (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+           (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+               sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+                                                  0, cur_ht_config);
+       else
+#endif /* CONFIG_IWL4965_HT */
+               sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+                                                  0, NULL);
 
        /* Set up default rate scaling table in device's station table */
        iwl4965_add_station(priv, addr, is_ap);
@@ -1625,6 +1639,12 @@ static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
        memcpy(mac, priv->eeprom.mac_address, 6);
 }
 
+static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
+{
+       iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+               CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
 /**
  * iwl4965_eeprom_init - read EEPROM contents
  *
@@ -1634,7 +1654,7 @@ static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
  */
 int iwl4965_eeprom_init(struct iwl4965_priv *priv)
 {
-       u16 *e = (u16 *)&priv->eeprom;
+       __le16 *e = (__le16 *)&priv->eeprom;
        u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
        u32 r;
        int sz = sizeof(priv->eeprom);
@@ -1678,7 +1698,7 @@ int iwl4965_eeprom_init(struct iwl4965_priv *priv)
                        rc = -ETIMEDOUT;
                        goto done;
                }
-               e[addr / 2] = le16_to_cpu(r >> 16);
+               e[addr / 2] = cpu_to_le16(r >> 16);
        }
        rc = 0;
 
@@ -2111,7 +2131,7 @@ static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force)
                        QOS_PARAM_FLG_UPDATE_EDCA_MSK;
 
 #ifdef CONFIG_IWL4965_HT
-       if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
+       if (priv->current_ht_config.is_ht)
                priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 #endif /* CONFIG_IWL4965_HT */
 
@@ -2758,6 +2778,10 @@ static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv,
                tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
        }
 
+       if (ieee80211_is_back_request(fc))
+               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
        cmd->cmd.tx.sta_id = std_id;
        if (ieee80211_get_morefrag(hdr))
                tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
@@ -2834,7 +2858,8 @@ static int iwl4965_get_sta_id(struct iwl4965_priv *priv,
                        return sta_id;
 
                /* Create new station table entry */
-               sta_id = iwl4965_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC);
+               sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+                                                  0, CMD_ASYNC, NULL);
 
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
@@ -2865,6 +2890,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
        struct iwl4965_queue *q = NULL;
        dma_addr_t phys_addr;
        dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
        struct iwl4965_cmd *out_cmd = NULL;
        u16 len, idx, len_org;
        u8 id, hdr_len, unicast;
@@ -2882,8 +2908,8 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
                goto drop_unlock;
        }
 
-       if (!priv->interface_id) {
-               IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+       if (!priv->vif) {
+               IWL_DEBUG_DROP("Dropping - !priv->vif\n");
                goto drop_unlock;
        }
 
@@ -3038,8 +3064,18 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
        /* set is_hcca to 0; it probably will never be implemented */
        iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
 
-       iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
-                      hdr, hdr_len, ctl, NULL);
+       scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) +
+               offsetof(struct iwl4965_tx_cmd, scratch);
+       out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+
+#ifdef CONFIG_IWL4965_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+       /* TODO: move this functionality to rate scaling */
+       iwl4965_tl_get_stats(priv, hdr);
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /*CONFIG_IWL4965_HT */
+
 
        if (!ieee80211_get_morefrag(hdr)) {
                txq->need_update = 1;
@@ -3231,93 +3267,6 @@ void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb,
        }
 }
 
-void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
-                                   struct iwl4965_rx_mem_buffer *rxb,
-                                   void *data, short len,
-                                   struct ieee80211_rx_status *stats,
-                                   u16 phy_flags)
-{
-       struct iwl4965_rt_rx_hdr *iwl4965_rt;
-
-       /* First cache any information we need before we overwrite
-        * the information provided in the skb from the hardware */
-       s8 signal = stats->ssi;
-       s8 noise = 0;
-       int rate = stats->rate;
-       u64 tsf = stats->mactime;
-       __le16 phy_flags_hw = cpu_to_le16(phy_flags);
-
-       /* We received data from the HW, so stop the watchdog */
-       if (len > IWL_RX_BUF_SIZE - sizeof(*iwl4965_rt)) {
-               IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
-               return;
-       }
-
-       /* copy the frame data to write after where the radiotap header goes */
-       iwl4965_rt = (void *)rxb->skb->data;
-       memmove(iwl4965_rt->payload, data, len);
-
-       iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-       iwl4965_rt->rt_hdr.it_pad = 0; /* always good to zero */
-
-       /* total header + data */
-       iwl4965_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl4965_rt));
-
-       /* Set the size of the skb to the size of the frame */
-       skb_put(rxb->skb, sizeof(*iwl4965_rt) + len);
-
-       /* Big bitfield of all the fields we provide in radiotap */
-       iwl4965_rt->rt_hdr.it_present =
-           cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-                       (1 << IEEE80211_RADIOTAP_FLAGS) |
-                       (1 << IEEE80211_RADIOTAP_RATE) |
-                       (1 << IEEE80211_RADIOTAP_CHANNEL) |
-                       (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-                       (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-                       (1 << IEEE80211_RADIOTAP_ANTENNA));
-
-       /* Zero the flags, we'll add to them as we go */
-       iwl4965_rt->rt_flags = 0;
-
-       iwl4965_rt->rt_tsf = cpu_to_le64(tsf);
-
-       /* Convert to dBm */
-       iwl4965_rt->rt_dbmsignal = signal;
-       iwl4965_rt->rt_dbmnoise = noise;
-
-       /* Convert the channel frequency and set the flags */
-       iwl4965_rt->rt_channelMHz = cpu_to_le16(stats->freq);
-       if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
-               iwl4965_rt->rt_chbitmask =
-                   cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
-       else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
-               iwl4965_rt->rt_chbitmask =
-                   cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
-       else    /* 802.11g */
-               iwl4965_rt->rt_chbitmask =
-                   cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
-
-       rate = iwl4965_rate_index_from_plcp(rate);
-       if (rate == -1)
-               iwl4965_rt->rt_rate = 0;
-       else
-               iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
-
-       /* antenna number */
-       iwl4965_rt->rt_antenna =
-               le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
-
-       /* set the preamble flag if we have it */
-       if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-               iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
-       IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
-       stats->flag |= RX_FLAG_RADIOTAP;
-       ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
-       rxb->skb = NULL;
-}
-
 
 #define IWL_PACKET_RETRY_TIME HZ
 
@@ -3965,7 +3914,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
        struct sk_buff *beacon;
 
        /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+       beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
 
        if (!beacon) {
                IWL_ERROR("update beacon failed\n");
@@ -4491,7 +4440,8 @@ static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
 
                /* Alloc a new receive buffer */
                rxb->skb =
-                   alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+                   alloc_skb(priv->hw_setting.rx_buf_size,
+                               __GFP_NOWARN | GFP_ATOMIC);
                if (!rxb->skb) {
                        if (net_ratelimit())
                                printk(KERN_CRIT DRV_NAME
@@ -4507,7 +4457,7 @@ static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
                /* Get physical address of RB/SKB */
                rxb->dma_addr =
                    pci_map_single(priv->pci_dev, rxb->skb->data,
-                                  IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                          priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
                list_add_tail(&rxb->list, &rxq->rx_free);
                rxq->free_count++;
        }
@@ -4517,7 +4467,7 @@ static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
 /*
  * this should be called while priv->lock is locked
 */
-void __iwl4965_rx_replenish(void *data)
+static void __iwl4965_rx_replenish(void *data)
 {
        struct iwl4965_priv *priv = data;
 
@@ -4550,7 +4500,8 @@ static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_q
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                        priv->hw_setting.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(rxq->pool[i].skb);
                }
        }
@@ -4601,7 +4552,8 @@ void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, struct iwl4965_rx_queue *
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                        priv->hw_setting.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
                        priv->alloc_rxb_skb--;
                        dev_kfree_skb(rxq->pool[i].skb);
                        rxq->pool[i].skb = NULL;
@@ -4735,7 +4687,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
                rxq->queue[i] = NULL;
 
                pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-                                           IWL_RX_BUF_SIZE,
+                                           priv->hw_setting.rx_buf_size,
                                            PCI_DMA_FROMDEVICE);
                pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 
@@ -4788,7 +4740,8 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
                }
 
                pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-                                IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                priv->hw_setting.rx_buf_size,
+                                PCI_DMA_FROMDEVICE);
                spin_lock_irqsave(&rxq->lock, flags);
                list_add_tail(&rxb->list, &priv->rxq.rx_used);
                spin_unlock_irqrestore(&rxq->lock, flags);
@@ -5184,8 +5137,9 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
 #ifdef CONFIG_IWL4965_DEBUG
        if (iwl4965_debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
-               if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
-                       IWL_DEBUG_ISR("Microcode started or stopped.\n");
+               if (inta & CSR_INT_BIT_SCD)
+                       IWL_DEBUG_ISR("Scheduler finished to transmit "
+                                     "the frame/frames.\n");
 
                /* Alive notification via Rx interrupt will do the real work */
                if (inta & CSR_INT_BIT_ALIVE)
@@ -5193,7 +5147,7 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
        }
 #endif
        /* Safely ignore these bits for debug checks below */
-       inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+       inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
 
        /* HW RF KILL switch toggled */
        if (inta & CSR_INT_BIT_RF_KILL) {
@@ -5322,8 +5276,11 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
        IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
                      inta, inta_mask, inta_fh);
 
+       inta &= ~CSR_INT_BIT_SCD;
+
        /* iwl4965_irq_tasklet() will service interrupts and re-enable them */
-       tasklet_schedule(&priv->irq_tasklet);
+       if (likely(inta || inta_fh))
+               tasklet_schedule(&priv->irq_tasklet);
 
  unplugged:
        spin_unlock(&priv->lock);
@@ -5629,6 +5586,15 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
        return 0;
 }
 
+/*
+ * iwl4965_free_channel_map - undo allocations in iwl4965_init_channel_map
+ */
+static void iwl4965_free_channel_map(struct iwl4965_priv *priv)
+{
+       kfree(priv->channel_info);
+       priv->channel_count = 0;
+}
+
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
@@ -5751,7 +5717,7 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode,
                        scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
                        /* NOTE: if we were doing 6Mb OFDM for scans we'd use
                         * power level:
-                        * scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+                        * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
                         */
                }
 
@@ -5962,6 +5928,17 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
        return 0;
 }
 
+/*
+ * iwl4965_free_geos - undo allocations in iwl4965_init_geos
+ */
+static void iwl4965_free_geos(struct iwl4965_priv *priv)
+{
+       kfree(priv->modes);
+       kfree(priv->ieee_channels);
+       kfree(priv->ieee_rates);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
 /******************************************************************************
  *
  * uCode download functions
@@ -5970,55 +5947,19 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
 
 static void iwl4965_dealloc_ucode_pci(struct iwl4965_priv *priv)
 {
-       if (priv->ucode_code.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_code.len,
-                                   priv->ucode_code.v_addr,
-                                   priv->ucode_code.p_addr);
-               priv->ucode_code.v_addr = NULL;
-       }
-       if (priv->ucode_data.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_data.len,
-                                   priv->ucode_data.v_addr,
-                                   priv->ucode_data.p_addr);
-               priv->ucode_data.v_addr = NULL;
-       }
-       if (priv->ucode_data_backup.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_data_backup.len,
-                                   priv->ucode_data_backup.v_addr,
-                                   priv->ucode_data_backup.p_addr);
-               priv->ucode_data_backup.v_addr = NULL;
-       }
-       if (priv->ucode_init.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_init.len,
-                                   priv->ucode_init.v_addr,
-                                   priv->ucode_init.p_addr);
-               priv->ucode_init.v_addr = NULL;
-       }
-       if (priv->ucode_init_data.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_init_data.len,
-                                   priv->ucode_init_data.v_addr,
-                                   priv->ucode_init_data.p_addr);
-               priv->ucode_init_data.v_addr = NULL;
-       }
-       if (priv->ucode_boot.v_addr != NULL) {
-               pci_free_consistent(priv->pci_dev,
-                                   priv->ucode_boot.len,
-                                   priv->ucode_boot.v_addr,
-                                   priv->ucode_boot.p_addr);
-               priv->ucode_boot.v_addr = NULL;
-       }
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
 /**
  * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
  *     looking at all data.
  */
-static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 * image,
+static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image,
                                 u32 len)
 {
        u32 val;
@@ -6310,11 +6251,6 @@ static void iwl4965_nic_start(struct iwl4965_priv *priv)
        iwl4965_write32(priv, CSR_RESET, 0);
 }
 
-static int iwl4965_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
-{
-       desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
-       return (desc->v_addr != NULL) ? 0 : -ENOMEM;
-}
 
 /**
  * iwl4965_read_ucode - Read uCode images from disk file.
@@ -6425,21 +6361,21 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
        priv->ucode_code.len = inst_size;
-       iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
+       iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
        priv->ucode_data.len = data_size;
-       iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
+       iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
        priv->ucode_data_backup.len = data_size;
-       iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+       iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
        /* Initialization instructions and data */
        if (init_size && init_data_size) {
                priv->ucode_init.len = init_size;
-               iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+               iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
 
                priv->ucode_init_data.len = init_data_size;
-               iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+               iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
 
                if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
                        goto err_pci_alloc;
@@ -6448,7 +6384,7 @@ static int iwl4965_read_ucode(struct iwl4965_priv *priv)
        /* Bootstrap (instructions only, no data) */
        if (boot_size) {
                priv->ucode_boot.len = boot_size;
-               iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
+               iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
                if (!priv->ucode_boot.v_addr)
                        goto err_pci_alloc;
@@ -6654,38 +6590,10 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
        /* Clear out the uCode error bit if it is set */
        clear_bit(STATUS_FW_ERROR, &priv->status);
 
-       rc = iwl4965_init_channel_map(priv);
-       if (rc) {
-               IWL_ERROR("initializing regulatory failed: %d\n", rc);
-               return;
-       }
-
-       iwl4965_init_geos(priv);
-
        if (iwl4965_is_rfkill(priv))
                return;
 
-       if (!priv->mac80211_registered) {
-               /* Unlock so any user space entry points can call back into
-                * the driver without a deadlock... */
-               mutex_unlock(&priv->mutex);
-               iwl4965_rate_control_register(priv->hw);
-               rc = ieee80211_register_hw(priv->hw);
-               priv->hw->conf.beacon_int = 100;
-               mutex_lock(&priv->mutex);
-
-               if (rc) {
-                       iwl4965_rate_control_unregister(priv->hw);
-                       IWL_ERROR("Failed to register network "
-                                 "device (error %d)\n", rc);
-                       return;
-               }
-
-               priv->mac80211_registered = 1;
-
-               iwl4965_reset_channel_flag(priv);
-       } else
-               ieee80211_start_queues(priv->hw);
+       ieee80211_start_queues(priv->hw);
 
        priv->active_rate = priv->rates_mask;
        priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
@@ -6716,7 +6624,9 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
        set_bit(STATUS_READY, &priv->status);
 
        iwl4965_rf_kill_ct_config(priv);
+
        IWL_DEBUG_INFO("ALIVE processing complete.\n");
+       wake_up_interruptible(&priv->wait_command_queue);
 
        if (priv->error_recovering)
                iwl4965_error_recovery(priv);
@@ -6830,9 +6740,7 @@ static void iwl4965_down(struct iwl4965_priv *priv)
 
 static int __iwl4965_up(struct iwl4965_priv *priv)
 {
-       DECLARE_MAC_BUF(mac);
        int rc, i;
-       u32 hw_rf_kill = 0;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARNING("Exit pending; will not bring the NIC up\n");
@@ -6842,7 +6750,19 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
        if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
                IWL_WARNING("Radio disabled by SW RF kill (module "
                            "parameter)\n");
-               return 0;
+               return -ENODEV;
+       }
+
+       /* If platform's RF_KILL switch is NOT set to KILL */
+       if (iwl4965_read32(priv, CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+               clear_bit(STATUS_RF_KILL_HW, &priv->status);
+       else {
+               set_bit(STATUS_RF_KILL_HW, &priv->status);
+               if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
+                       IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+                       return -ENODEV;
+               }
        }
 
        if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
@@ -6875,19 +6795,11 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
         * This will be used to initialize the on-board processor's
         * data SRAM for a clean start when the runtime program first loads. */
        memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
-                       priv->ucode_data.len);
-
-       /* If platform's RF_KILL switch is set to KILL,
-        * wait for BIT_INT_RF_KILL interrupt before loading uCode
-        * and getting things started */
-       if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
-                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-               hw_rf_kill = 1;
+              priv->ucode_data.len);
 
-       if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
-               IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+       /* We return success when we resume from suspend and rf_kill is on. */
+       if (test_bit(STATUS_RF_KILL_HW, &priv->status))
                return 0;
-       }
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
@@ -6906,13 +6818,6 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
                /* start card; "initialize" will load runtime ucode */
                iwl4965_nic_start(priv);
 
-               /* MAC Address location in EEPROM is same for 3945/4965 */
-               get_eeprom_mac(priv, priv->mac_addr);
-               IWL_DEBUG_INFO("MAC address: %s\n",
-                              print_mac(mac, priv->mac_addr));
-
-               SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
-
                IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
 
                return 0;
@@ -7282,7 +7187,7 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
 
        mutex_lock(&priv->mutex);
 
-       if (!priv->interface_id || !priv->is_open) {
+       if (!priv->vif || !priv->is_open) {
                mutex_unlock(&priv->mutex);
                return;
        }
@@ -7304,13 +7209,8 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
        priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
 #ifdef CONFIG_IWL4965_HT
-       if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
-               iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
-       else {
-               priv->active_rate_ht[0] = 0;
-               priv->active_rate_ht[1] = 0;
-               priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
-       }
+       if (priv->current_ht_config.is_ht)
+               iwl4965_set_rxon_ht(priv, &priv->current_ht_config);
 #endif /* CONFIG_IWL4965_HT*/
        iwl4965_set_rxon_chain(priv);
        priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
@@ -7405,8 +7305,8 @@ static void iwl4965_bg_scan_completed(struct work_struct *work)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (priv->cache_conf)
-               iwl4965_mac_config(priv->hw, priv->cache_conf);
+       if (test_bit(STATUS_CONF_PENDING, &priv->status))
+               iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
 
        ieee80211_scan_completed(priv->hw);
 
@@ -7423,23 +7323,83 @@ static void iwl4965_bg_scan_completed(struct work_struct *work)
  *
  *****************************************************************************/
 
+#define UCODE_READY_TIMEOUT    (2 * HZ)
+
 static int iwl4965_mac_start(struct ieee80211_hw *hw)
 {
        struct iwl4965_priv *priv = hw->priv;
+       int ret;
 
        IWL_DEBUG_MAC80211("enter\n");
 
+       if (pci_enable_device(priv->pci_dev)) {
+               IWL_ERROR("Fail to pci_enable_device\n");
+               return -ENODEV;
+       }
+       pci_restore_state(priv->pci_dev);
+       pci_enable_msi(priv->pci_dev);
+
+       ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
+                         DRV_NAME, priv);
+       if (ret) {
+               IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
+               goto out_disable_msi;
+       }
+
        /* we should be verifying the device is ready to be opened */
        mutex_lock(&priv->mutex);
 
-       priv->is_open = 1;
+       memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd));
+       /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+        * ucode filename and max sizes are card-specific. */
+
+       if (!priv->ucode_code.len) {
+               ret = iwl4965_read_ucode(priv);
+               if (ret) {
+                       IWL_ERROR("Could not read microcode: %d\n", ret);
+                       mutex_unlock(&priv->mutex);
+                       goto out_release_irq;
+               }
+       }
 
-       if (!iwl4965_is_rfkill(priv))
-               ieee80211_start_queues(priv->hw);
+       ret = __iwl4965_up(priv);
 
        mutex_unlock(&priv->mutex);
+
+       if (ret)
+               goto out_release_irq;
+
+       IWL_DEBUG_INFO("Start UP work done.\n");
+
+       if (test_bit(STATUS_IN_SUSPEND, &priv->status))
+               return 0;
+
+       /* Wait for START_ALIVE from ucode. Otherwise callbacks from
+        * mac80211 will not be run successfully. */
+       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                       test_bit(STATUS_READY, &priv->status),
+                       UCODE_READY_TIMEOUT);
+       if (!ret) {
+               if (!test_bit(STATUS_READY, &priv->status)) {
+                       IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
+                                 jiffies_to_msecs(UCODE_READY_TIMEOUT));
+                       ret = -ETIMEDOUT;
+                       goto out_release_irq;
+               }
+       }
+
+       priv->is_open = 1;
        IWL_DEBUG_MAC80211("leave\n");
        return 0;
+
+out_release_irq:
+       free_irq(priv->pci_dev->irq, priv);
+out_disable_msi:
+       pci_disable_msi(priv->pci_dev);
+       pci_disable_device(priv->pci_dev);
+       priv->is_open = 0;
+       IWL_DEBUG_MAC80211("leave - failed\n");
+       return ret;
 }
 
 static void iwl4965_mac_stop(struct ieee80211_hw *hw)
@@ -7448,23 +7408,30 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
 
        IWL_DEBUG_MAC80211("enter\n");
 
+       if (!priv->is_open) {
+               IWL_DEBUG_MAC80211("leave - skip\n");
+               return;
+       }
 
-       mutex_lock(&priv->mutex);
-       /* stop mac, cancel any scan request and clear
-        * RXON_FILTER_ASSOC_MSK BIT
-        */
        priv->is_open = 0;
-       if (!iwl4965_is_ready_rf(priv)) {
-               IWL_DEBUG_MAC80211("leave - RF not ready\n");
+
+       if (iwl4965_is_ready_rf(priv)) {
+               /* stop mac, cancel any scan request and clear
+                * RXON_FILTER_ASSOC_MSK BIT
+                */
+               mutex_lock(&priv->mutex);
+               iwl4965_scan_cancel_timeout(priv, 100);
+               cancel_delayed_work(&priv->post_associate);
                mutex_unlock(&priv->mutex);
-               return;
        }
 
-       iwl4965_scan_cancel_timeout(priv, 100);
-       cancel_delayed_work(&priv->post_associate);
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwl4965_commit_rxon(priv);
-       mutex_unlock(&priv->mutex);
+       iwl4965_down(priv);
+
+       flush_workqueue(priv->workqueue);
+       free_irq(priv->pci_dev->irq, priv);
+       pci_disable_msi(priv->pci_dev);
+       pci_save_state(priv->pci_dev);
+       pci_disable_device(priv->pci_dev);
 
        IWL_DEBUG_MAC80211("leave\n");
 }
@@ -7498,15 +7465,15 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
        unsigned long flags;
        DECLARE_MAC_BUF(mac);
 
-       IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+       IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
 
-       if (priv->interface_id) {
-               IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
-               return 0;
+       if (priv->vif) {
+               IWL_DEBUG_MAC80211("leave - vif != NULL\n");
+               return -EOPNOTSUPP;
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       priv->interface_id = conf->if_id;
+       priv->vif = conf->vif;
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -7516,11 +7483,13 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
                IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
                memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
        }
-       iwl4965_set_mode(priv, conf->type);
 
-       IWL_DEBUG_MAC80211("leave\n");
+       if (iwl4965_is_ready(priv))
+               iwl4965_set_mode(priv, conf->type);
+
        mutex_unlock(&priv->mutex);
 
+       IWL_DEBUG_MAC80211("leave\n");
        return 0;
 }
 
@@ -7541,33 +7510,20 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
 
+       priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
        if (!iwl4965_is_ready(priv)) {
                IWL_DEBUG_MAC80211("leave - not ready\n");
                ret = -EIO;
                goto out;
        }
 
-       /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
-        * what is exposed through include/ declarations */
        if (unlikely(!iwl4965_param_disable_hw_scan &&
                     test_bit(STATUS_SCANNING, &priv->status))) {
-
-               if (unlikely(priv->cache_conf))
-                       IWL_DEBUG_MAC80211("leave - still scanning\n");
-               else {
-                       /* Cache the configuration now so that we can
-                        * replay it after the hardware scan is finished. */
-                       priv->cache_conf = kmalloc(sizeof(*conf), GFP_KERNEL);
-                       if (priv->cache_conf) {
-                               memcpy(priv->cache_conf, conf, sizeof(*conf));
-                               IWL_DEBUG_MAC80211("leave - scanning\n");
-                       } else {
-                               IWL_DEBUG_MAC80211("leave - no memory\n");
-                               ret = -ENOMEM;
-                       }
-               }
+               IWL_DEBUG_MAC80211("leave - scanning\n");
+               set_bit(STATUS_CONF_PENDING, &priv->status);
                mutex_unlock(&priv->mutex);
-               return ret;
+               return 0;
        }
 
        spin_lock_irqsave(&priv->lock, flags);
@@ -7636,10 +7592,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
        IWL_DEBUG_MAC80211("leave\n");
 
 out:
-       if (priv->cache_conf) {
-               kfree(priv->cache_conf);
-               priv->cache_conf = NULL;
-       }
+       clear_bit(STATUS_CONF_PENDING, &priv->status);
        mutex_unlock(&priv->mutex);
        return ret;
 }
@@ -7648,7 +7601,7 @@ static void iwl4965_config_ap(struct iwl4965_priv *priv)
 {
        int rc = 0;
 
-       if (priv->status & STATUS_EXIT_PENDING)
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
@@ -7706,7 +7659,8 @@ static void iwl4965_config_ap(struct iwl4965_priv *priv)
         * clear sta table, add BCAST sta... */
 }
 
-static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
                                    struct ieee80211_if_conf *conf)
 {
        struct iwl4965_priv *priv = hw->priv;
@@ -7724,9 +7678,11 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
                return 0;
        }
 
+       if (!iwl4965_is_alive(priv))
+               return -EAGAIN;
+
        mutex_lock(&priv->mutex);
 
-       IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
        if (conf->bssid)
                IWL_DEBUG_MAC80211("bssid: %s\n",
                                   print_mac(mac, conf->bssid));
@@ -7743,8 +7699,8 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
                return 0;
        }
 
-       if (priv->interface_id != if_id) {
-               IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+       if (priv->vif != vif) {
+               IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
                mutex_unlock(&priv->mutex);
                return 0;
        }
@@ -7842,8 +7798,8 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
                iwl4965_commit_rxon(priv);
        }
-       if (priv->interface_id == conf->if_id) {
-               priv->interface_id = 0;
+       if (priv->vif == conf->vif) {
+               priv->vif = NULL;
                memset(priv->bssid, 0, ETH_ALEN);
                memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
                priv->essid_len = 0;
@@ -7853,25 +7809,35 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
        IWL_DEBUG_MAC80211("leave\n");
 
 }
-static void iwl4965_mac_erp_ie_changed(struct ieee80211_hw *hw,
-               u8 changes, int cts_protection, int preamble)
+
+static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
+                                    struct ieee80211_bss_conf *bss_conf,
+                                    u32 changes)
 {
        struct iwl4965_priv *priv = hw->priv;
 
-       if (changes & IEEE80211_ERP_CHANGE_PREAMBLE) {
-               if (preamble == WLAN_ERP_PREAMBLE_SHORT)
+       if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+               if (bss_conf->use_short_preamble)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
        }
 
-       if (changes & IEEE80211_ERP_CHANGE_PROTECTION) {
-               if (cts_protection && (priv->phymode != MODE_IEEE80211A))
+       if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+               if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A))
                        priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
        }
 
+       if (changes & BSS_CHANGED_ASSOC) {
+               /*
+                * TODO:
+                * do stuff instead of sniffing assoc resp
+                */
+       }
+
        if (iwl4965_is_associated(priv))
                iwl4965_send_rxon_assoc(priv);
 }
@@ -8112,7 +8078,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        priv->lq_mngr.lq_ready = 0;
 #ifdef CONFIG_IWL4965_HT
        spin_lock_irqsave(&priv->lock, flags);
-       memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
+       memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
        spin_unlock_irqrestore(&priv->lock, flags);
 #ifdef CONFIG_IWL4965_HT_AGG
 /*     if (priv->lq_mngr.agg_ctrl.granted_ba)
@@ -8184,7 +8150,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211("leave\n");
-
 }
 
 static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -8232,132 +8197,61 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
 }
 
 #ifdef CONFIG_IWL4965_HT
-union ht_cap_info {
-       struct {
-               u16 advanced_coding_cap         :1;
-               u16 supported_chan_width_set    :1;
-               u16 mimo_power_save_mode        :2;
-               u16 green_field                 :1;
-               u16 short_GI20                  :1;
-               u16 short_GI40                  :1;
-               u16 tx_stbc                     :1;
-               u16 rx_stbc                     :1;
-               u16 beam_forming                :1;
-               u16 delayed_ba                  :1;
-               u16 maximal_amsdu_size          :1;
-               u16 cck_mode_at_40MHz           :1;
-               u16 psmp_support                :1;
-               u16 stbc_ctrl_frame_support     :1;
-               u16 sig_txop_protection_support :1;
-       };
-       u16 val;
-} __attribute__ ((packed));
-
-union ht_param_info{
-       struct {
-               u8 max_rx_ampdu_factor  :2;
-               u8 mpdu_density         :3;
-               u8 reserved             :3;
-       };
-       u8 val;
-} __attribute__ ((packed));
-
-union ht_exra_param_info {
-       struct {
-               u8 ext_chan_offset              :2;
-               u8 tx_chan_width                :1;
-               u8 rifs_mode                    :1;
-               u8 controlled_access_only       :1;
-               u8 service_interval_granularity :3;
-       };
-       u8 val;
-} __attribute__ ((packed));
-
-union ht_operation_mode{
-       struct {
-               u16 op_mode     :2;
-               u16 non_GF      :1;
-               u16 reserved    :13;
-       };
-       u16 val;
-} __attribute__ ((packed));
 
-
-static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap,
-                           struct ieee80211_ht_additional_info *ht_extra,
-                           struct sta_ht_info *ht_info_ap,
-                           struct sta_ht_info *ht_info)
+static void iwl4965_ht_info_fill(struct ieee80211_conf *conf,
+                                struct iwl4965_priv *priv)
 {
-       union ht_cap_info cap;
-       union ht_operation_mode op_mode;
-       union ht_param_info param_info;
-       union ht_exra_param_info extra_param_info;
+       struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+       struct ieee80211_ht_info *ht_conf = &conf->ht_conf;
+       struct ieee80211_ht_bss_info *ht_bss_conf = &conf->ht_bss_conf;
 
        IWL_DEBUG_MAC80211("enter: \n");
 
-       if (!ht_info) {
-               IWL_DEBUG_MAC80211("leave: ht_info is NULL\n");
-               return -1;
+       if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) {
+               iwl_conf->is_ht = 0;
+               return;
        }
 
-       if (ht_cap) {
-               cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info);
-               param_info.val = ht_cap->mac_ht_params_info;
-               ht_info->is_ht = 1;
-               if (cap.short_GI20)
-                       ht_info->sgf |= 0x1;
-               if (cap.short_GI40)
-                       ht_info->sgf |= 0x2;
-               ht_info->is_green_field = cap.green_field;
-               ht_info->max_amsdu_size = cap.maximal_amsdu_size;
-               ht_info->supported_chan_width = cap.supported_chan_width_set;
-               ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
-               memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16);
-
-               ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
-               ht_info->mpdu_density = param_info.mpdu_density;
-
-               IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n",
-                                   ht_cap->supported_mcs_set[0],
-                                   ht_cap->supported_mcs_set[1]);
-
-               if (ht_info_ap) {
-                       ht_info->control_channel = ht_info_ap->control_channel;
-                       ht_info->extension_chan_offset =
-                               ht_info_ap->extension_chan_offset;
-                       ht_info->tx_chan_width = ht_info_ap->tx_chan_width;
-                       ht_info->operating_mode = ht_info_ap->operating_mode;
-               }
-
-               if (ht_extra) {
-                       extra_param_info.val = ht_extra->ht_param;
-                       ht_info->control_channel = ht_extra->control_chan;
-                       ht_info->extension_chan_offset =
-                           extra_param_info.ext_chan_offset;
-                       ht_info->tx_chan_width = extra_param_info.tx_chan_width;
-                       op_mode.val = (u16)
-                           le16_to_cpu(ht_extra->operation_mode);
-                       ht_info->operating_mode = op_mode.op_mode;
-                       IWL_DEBUG_MAC80211("control channel %d\n",
-                                           ht_extra->control_chan);
-               }
-       } else
-               ht_info->is_ht = 0;
-
+       iwl_conf->is_ht = 1;
+       priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+
+       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
+               iwl_conf->sgf |= 0x1;
+       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+               iwl_conf->sgf |= 0x2;
+
+       iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+       iwl_conf->max_amsdu_size =
+               !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+       iwl_conf->supported_chan_width =
+               !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+       iwl_conf->tx_mimo_ps_mode =
+               (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+       memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+
+       iwl_conf->control_channel = ht_bss_conf->primary_channel;
+       iwl_conf->extension_chan_offset =
+               ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+       iwl_conf->tx_chan_width =
+               !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+       iwl_conf->ht_protection =
+               ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+       iwl_conf->non_GF_STA_present =
+               !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+
+       IWL_DEBUG_MAC80211("control channel %d\n",
+               iwl_conf->control_channel);
        IWL_DEBUG_MAC80211("leave\n");
-       return 0;
 }
 
 static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw,
-                          struct ieee80211_ht_capability *ht_cap,
-                          struct ieee80211_ht_additional_info *ht_extra)
+                              struct ieee80211_conf *conf)
 {
        struct iwl4965_priv *priv = hw->priv;
-       int rs;
 
        IWL_DEBUG_MAC80211("enter: \n");
 
-       rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht);
+       iwl4965_ht_info_fill(conf, priv);
        iwl4965_set_rxon_chain(priv);
 
        if (priv && priv->assoc_id &&
@@ -8372,10 +8266,8 @@ static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw,
                spin_unlock_irqrestore(&priv->lock, flags);
        }
 
-       IWL_DEBUG_MAC80211("leave: control channel %d\n",
-                       ht_extra->control_chan);
-       return rs;
-
+       IWL_DEBUG_MAC80211("leave:\n");
+       return 0;
 }
 
 static void iwl4965_set_ht_capab(struct ieee80211_hw *hw,
@@ -8400,23 +8292,6 @@ static void iwl4965_set_ht_capab(struct ieee80211_hw *hw,
                                        IEEE80211_HT_CAP_AMPDU_DENSITY);
 }
 
-static void iwl4965_mac_get_ht_capab(struct ieee80211_hw *hw,
-                                struct ieee80211_ht_capability *ht_cap)
-{
-       u8 use_wide_channel = 1;
-       struct iwl4965_priv *priv = hw->priv;
-
-       IWL_DEBUG_MAC80211("enter: \n");
-       if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
-               use_wide_channel = 0;
-
-       /* no fat tx allowed on 2.4GHZ */
-       if (priv->phymode != MODE_IEEE80211A)
-               use_wide_channel = 0;
-
-       iwl4965_set_ht_capab(hw, ht_cap, use_wide_channel);
-       IWL_DEBUG_MAC80211("leave: \n");
-}
 #endif /*CONFIG_IWL4965_HT*/
 
 /*****************************************************************************
@@ -9131,15 +9006,13 @@ static struct ieee80211_ops iwl4965_hw_ops = {
        .get_tsf = iwl4965_mac_get_tsf,
        .reset_tsf = iwl4965_mac_reset_tsf,
        .beacon_update = iwl4965_mac_beacon_update,
-       .erp_ie_changed = iwl4965_mac_erp_ie_changed,
+       .bss_info_changed = iwl4965_bss_info_changed,
 #ifdef CONFIG_IWL4965_HT
        .conf_ht = iwl4965_mac_conf_ht,
-       .get_ht_capab = iwl4965_mac_get_ht_capab,
+       .ampdu_action = iwl4965_mac_ampdu_action,
 #ifdef CONFIG_IWL4965_HT_AGG
        .ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start,
        .ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop,
-       .ht_rx_agg_start = iwl4965_mac_ht_rx_agg_start,
-       .ht_rx_agg_stop = iwl4965_mac_ht_rx_agg_stop,
 #endif  /* CONFIG_IWL4965_HT_AGG */
 #endif  /* CONFIG_IWL4965_HT */
        .hw_scan = iwl4965_mac_hw_scan
@@ -9151,6 +9024,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        struct iwl4965_priv *priv;
        struct ieee80211_hw *hw;
        int i;
+       DECLARE_MAC_BUF(mac);
 
        /* Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan. */
@@ -9292,7 +9166,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /* Device-specific setup */
        if (iwl4965_hw_set_hw_setting(priv)) {
                IWL_ERROR("failed to set hw settings\n");
-               mutex_unlock(&priv->mutex);
                goto out_iounmap;
        }
 
@@ -9317,50 +9190,70 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        iwl4965_disable_interrupts(priv);
 
-       pci_enable_msi(pdev);
-
-       err = request_irq(pdev->irq, iwl4965_isr, IRQF_SHARED, DRV_NAME, priv);
-       if (err) {
-               IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
-               goto out_disable_msi;
-       }
-
-       mutex_lock(&priv->mutex);
-
        err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
        if (err) {
                IWL_ERROR("failed to create sysfs device attributes\n");
-               mutex_unlock(&priv->mutex);
                goto out_release_irq;
        }
 
-       /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
-        * ucode filename and max sizes are card-specific. */
-       err = iwl4965_read_ucode(priv);
+       /* nic init */
+       iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+                    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+        iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+        err = iwl4965_poll_bit(priv, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+        if (err < 0) {
+                IWL_DEBUG_INFO("Failed to init the card\n");
+               goto out_remove_sysfs;
+        }
+       /* Read the EEPROM */
+       err = iwl4965_eeprom_init(priv);
        if (err) {
-               IWL_ERROR("Could not read microcode: %d\n", err);
-               mutex_unlock(&priv->mutex);
-               goto out_pci_alloc;
+               IWL_ERROR("Unable to init EEPROM\n");
+               goto out_remove_sysfs;
        }
+       /* MAC Address location in EEPROM same for 3945/4965 */
+       get_eeprom_mac(priv, priv->mac_addr);
+       IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+       SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
-       mutex_unlock(&priv->mutex);
+       err = iwl4965_init_channel_map(priv);
+       if (err) {
+               IWL_ERROR("initializing regulatory failed: %d\n", err);
+               goto out_remove_sysfs;
+       }
 
-       IWL_DEBUG_INFO("Queueing UP work.\n");
+       err = iwl4965_init_geos(priv);
+       if (err) {
+               IWL_ERROR("initializing geos failed: %d\n", err);
+               goto out_free_channel_map;
+       }
+       iwl4965_reset_channel_flag(priv);
 
-       queue_work(priv->workqueue, &priv->up);
+       iwl4965_rate_control_register(priv->hw);
+       err = ieee80211_register_hw(priv->hw);
+       if (err) {
+               IWL_ERROR("Failed to register network device (error %d)\n", err);
+               goto out_free_geos;
+       }
 
-       return 0;
+       priv->hw->conf.beacon_int = 100;
+       priv->mac80211_registered = 1;
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
 
- out_pci_alloc:
-       iwl4965_dealloc_ucode_pci(priv);
+       return 0;
 
+ out_free_geos:
+       iwl4965_free_geos(priv);
+ out_free_channel_map:
+       iwl4965_free_channel_map(priv);
+ out_remove_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
  out_release_irq:
-       free_irq(pdev->irq, priv);
-
- out_disable_msi:
-       pci_disable_msi(pdev);
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
        iwl4965_unset_hw_setting(priv);
@@ -9426,17 +9319,13 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
 
-       free_irq(pdev->irq, priv);
-       pci_disable_msi(pdev);
        pci_iounmap(pdev, priv->hw_base);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
-       kfree(priv->channel_info);
-
-       kfree(priv->ieee_channels);
-       kfree(priv->ieee_rates);
+       iwl4965_free_channel_map(priv);
+       iwl4965_free_geos(priv);
 
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
@@ -9450,89 +9339,27 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct iwl4965_priv *priv = pci_get_drvdata(pdev);
 
-       set_bit(STATUS_IN_SUSPEND, &priv->status);
-
-       /* Take down the device; powers it off, etc. */
-       iwl4965_down(priv);
-
-       if (priv->mac80211_registered)
-               ieee80211_stop_queues(priv->hw);
+       if (priv->is_open) {
+               set_bit(STATUS_IN_SUSPEND, &priv->status);
+               iwl4965_mac_stop(priv->hw);
+               priv->is_open = 1;
+       }
 
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
 
        return 0;
 }
 
-static void iwl4965_resume(struct iwl4965_priv *priv)
-{
-       unsigned long flags;
-
-       /* The following it a temporary work around due to the
-        * suspend / resume not fully initializing the NIC correctly.
-        * Without all of the following, resume will not attempt to take
-        * down the NIC (it shouldn't really need to) and will just try
-        * and bring the NIC back up.  However that fails during the
-        * ucode verification process.  This then causes iwl4965_down to be
-        * called *after* iwl4965_hw_nic_init() has succeeded -- which
-        * then lets the next init sequence succeed.  So, we've
-        * replicated all of that NIC init code here... */
-
-       iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
-
-       iwl4965_hw_nic_init(priv);
-
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-       iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       /* tell the device to stop sending interrupts */
-       iwl4965_disable_interrupts(priv);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-       if (!iwl4965_grab_nic_access(priv)) {
-               iwl4965_write_prph(priv, APMG_CLK_DIS_REG,
-                               APMG_CLK_VAL_DMA_CLK_RQT);
-               iwl4965_release_nic_access(priv);
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       udelay(5);
-
-       iwl4965_hw_nic_reset(priv);
-
-       /* Bring the device back up */
-       clear_bit(STATUS_IN_SUSPEND, &priv->status);
-       queue_work(priv->workqueue, &priv->up);
-}
-
 static int iwl4965_pci_resume(struct pci_dev *pdev)
 {
        struct iwl4965_priv *priv = pci_get_drvdata(pdev);
-       int err;
-
-       printk(KERN_INFO "Coming out of suspend...\n");
 
        pci_set_power_state(pdev, PCI_D0);
-       err = pci_enable_device(pdev);
-       pci_restore_state(pdev);
-
-       /*
-        * Suspend/Resume resets the PCI configuration space, so we have to
-        * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
-        * from interfering with C3 CPU state. pci_restore_state won't help
-        * here since it only restores the first 64 bytes pci config header.
-        */
-       pci_write_config_byte(pdev, 0x41, 0x00);
 
-       iwl4965_resume(priv);
+       if (priv->is_open)
+               iwl4965_mac_start(priv->hw);
 
+       clear_bit(STATUS_IN_SUSPEND, &priv->status);
        return 0;
 }
 
@@ -9604,6 +9431,8 @@ MODULE_PARM_DESC(queues_num, "number of hw queues.");
 /* QoS */
 module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444);
 MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
 
 module_exit(iwl4965_exit);
 module_init(iwl4965_init);