Merge branch 'for-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[linux-3.10.git] / drivers / net / wireless / ipw2x00 / ipw2100.c
index 7f0d98b..534e655 100644 (file)
@@ -63,7 +63,7 @@ When data is sent to the firmware, the first TBD is used to indicate to the
 firmware if a Command or Data is being sent.  If it is Command, all of the
 command information is contained within the physical address referred to by the
 TBD.  If it is Data, the first TBD indicates the type of data packet, number
-of fragments, etc.  The next TBD then referrs to the actual packet location.
+of fragments, etc.  The next TBD then refers to the actual packet location.
 
 The Tx flow cycle is as follows:
 
@@ -161,11 +161,12 @@ that only one external action is invoked at a time.
 #include <linux/firmware.h>
 #include <linux/acpi.h>
 #include <linux/ctype.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #include <net/lib80211.h>
 
 #include "ipw2100.h"
+#include "ipw.h"
 
 #define IPW2100_VERSION "git-1.2.2"
 
@@ -174,7 +175,7 @@ that only one external action is invoked at a time.
 #define DRV_DESCRIPTION        "Intel(R) PRO/Wireless 2100 Network Driver"
 #define DRV_COPYRIGHT  "Copyright(c) 2003-2006 Intel Corporation"
 
-struct pm_qos_request_list ipw2100_pm_qos_req;
+static struct pm_qos_request ipw2100_pm_qos_req;
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
@@ -287,7 +288,7 @@ static const char *command_types[] = {
        "unused",               /* HOST_INTERRUPT_COALESCING */
        "undefined",
        "CARD_DISABLE_PHY_OFF",
-       "MSDU_TX_RATES" "undefined",
+       "MSDU_TX_RATES",
        "undefined",
        "SET_STATION_STAT_BITS",
        "CLEAR_STATIONS_STAT_BITS",
@@ -298,8 +299,6 @@ static const char *command_types[] = {
 };
 #endif
 
-#define WEXT_USECHANNELS 1
-
 static const long ipw2100_frequencies[] = {
        2412, 2417, 2422, 2427,
        2432, 2437, 2442, 2447,
@@ -309,13 +308,6 @@ static const long ipw2100_frequencies[] = {
 
 #define FREQ_COUNT     ARRAY_SIZE(ipw2100_frequencies)
 
-static const long ipw2100_rates_11b[] = {
-       1000000,
-       2000000,
-       5500000,
-       11000000
-};
-
 static struct ieee80211_rate ipw2100_bg_rates[] = {
        { .bitrate = 10 },
        { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
@@ -323,7 +315,7 @@ static struct ieee80211_rate ipw2100_bg_rates[] = {
        { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
 };
 
-#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
+#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
 
 /* Pre-decl until we get the code solid and then we can clean it up */
 static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
@@ -352,38 +344,50 @@ static struct iw_handler_def ipw2100_wx_handler_def;
 
 static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
 {
-       *val = readl((void __iomem *)(dev->base_addr + reg));
+       struct ipw2100_priv *priv = libipw_priv(dev);
+
+       *val = ioread32(priv->ioaddr + reg);
        IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
 }
 
 static inline void write_register(struct net_device *dev, u32 reg, u32 val)
 {
-       writel(val, (void __iomem *)(dev->base_addr + reg));
+       struct ipw2100_priv *priv = libipw_priv(dev);
+
+       iowrite32(val, priv->ioaddr + reg);
        IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
 }
 
 static inline void read_register_word(struct net_device *dev, u32 reg,
                                      u16 * val)
 {
-       *val = readw((void __iomem *)(dev->base_addr + reg));
+       struct ipw2100_priv *priv = libipw_priv(dev);
+
+       *val = ioread16(priv->ioaddr + reg);
        IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
 }
 
 static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
 {
-       *val = readb((void __iomem *)(dev->base_addr + reg));
+       struct ipw2100_priv *priv = libipw_priv(dev);
+
+       *val = ioread8(priv->ioaddr + reg);
        IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
 }
 
 static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
 {
-       writew(val, (void __iomem *)(dev->base_addr + reg));
+       struct ipw2100_priv *priv = libipw_priv(dev);
+
+       iowrite16(val, priv->ioaddr + reg);
        IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
 }
 
 static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
 {
-       writeb(val, (void __iomem *)(dev->base_addr + reg));
+       struct ipw2100_priv *priv = libipw_priv(dev);
+
+       iowrite8(val, priv->ioaddr + reg);
        IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
 }
 
@@ -515,13 +519,13 @@ static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
                read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
 }
 
-static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
+static bool ipw2100_hw_is_adapter_in_system(struct net_device *dev)
 {
-       return (dev->base_addr &&
-               (readl
-                ((void __iomem *)(dev->base_addr +
-                                  IPW_REG_DOA_DEBUG_AREA_START))
-                == IPW_DATA_DOA_DEBUG_VALUE));
+       u32 dbg;
+
+       read_register(dev, IPW_REG_DOA_DEBUG_AREA_START, &dbg);
+
+       return dbg == IPW_DATA_DOA_DEBUG_VALUE;
 }
 
 static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
@@ -706,11 +710,10 @@ static void schedule_reset(struct ipw2100_priv *priv)
                netif_stop_queue(priv->net_dev);
                priv->status |= STATUS_RESET_PENDING;
                if (priv->reset_backoff)
-                       queue_delayed_work(priv->workqueue, &priv->reset_work,
-                                          priv->reset_backoff * HZ);
+                       schedule_delayed_work(&priv->reset_work,
+                                             priv->reset_backoff * HZ);
                else
-                       queue_delayed_work(priv->workqueue, &priv->reset_work,
-                                          0);
+                       schedule_delayed_work(&priv->reset_work, 0);
 
                if (priv->reset_backoff < MAX_RESET_BACKOFF)
                        priv->reset_backoff++;
@@ -1397,7 +1400,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
 }
 
 /*
- * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it
+ * Send the CARD_DISABLE_PHY_OFF command to the card to disable it
  *
  * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
  *
@@ -1474,7 +1477,7 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
 
        if (priv->stop_hang_check) {
                priv->stop_hang_check = 0;
-               queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+               schedule_delayed_work(&priv->hang_check, HZ / 2);
        }
 
       fail_up:
@@ -1808,8 +1811,8 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
 
                if (priv->stop_rf_kill) {
                        priv->stop_rf_kill = 0;
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          round_jiffies_relative(HZ));
+                       schedule_delayed_work(&priv->rf_kill,
+                                             round_jiffies_relative(HZ));
                }
 
                deferred = 1;
@@ -1900,19 +1903,13 @@ static void ipw2100_down(struct ipw2100_priv *priv)
        netif_stop_queue(priv->net_dev);
 }
 
-/* Called by register_netdev() */
-static int ipw2100_net_init(struct net_device *dev)
+static int ipw2100_wdev_init(struct net_device *dev)
 {
        struct ipw2100_priv *priv = libipw_priv(dev);
        const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
        struct wireless_dev *wdev = &priv->ieee->wdev;
-       int ret;
        int i;
 
-       ret = ipw2100_up(priv, 1);
-       if (ret)
-               return ret;
-
        memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
 
        /* fill-out priv->ieee->bg_band */
@@ -1921,9 +1918,13 @@ static int ipw2100_net_init(struct net_device *dev)
 
                bg_band->band = IEEE80211_BAND_2GHZ;
                bg_band->n_channels = geo->bg_channels;
-               bg_band->channels =
-                       kzalloc(geo->bg_channels *
-                               sizeof(struct ieee80211_channel), GFP_KERNEL);
+               bg_band->channels = kcalloc(geo->bg_channels,
+                                           sizeof(struct ieee80211_channel),
+                                           GFP_KERNEL);
+               if (!bg_band->channels) {
+                       ipw2100_down(priv);
+                       return -ENOMEM;
+               }
                /* translate geo->bg to bg_band.channels */
                for (i = 0; i < geo->bg_channels; i++) {
                        bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
@@ -1950,11 +1951,12 @@ static int ipw2100_net_init(struct net_device *dev)
                wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
        }
 
+       wdev->wiphy->cipher_suites = ipw_cipher_suites;
+       wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
+
        set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
-       if (wiphy_register(wdev->wiphy)) {
-               ipw2100_down(priv);
+       if (wiphy_register(wdev->wiphy))
                return -EIO;
-       }
        return 0;
 }
 
@@ -2040,7 +2042,8 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
                return;
        }
        len = ETH_ALEN;
-       ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
+       ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid,
+                                 &len);
        if (ret) {
                IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
                               __LINE__);
@@ -2082,7 +2085,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
        priv->status |= STATUS_ASSOCIATING;
        priv->connect_start = get_seconds();
 
-       queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
+       schedule_delayed_work(&priv->wx_event_work, HZ / 10);
 }
 
 static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
@@ -2162,9 +2165,9 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
                return;
 
        if (priv->status & STATUS_SECURITY_UPDATED)
-               queue_delayed_work(priv->workqueue, &priv->security_work, 0);
+               schedule_delayed_work(&priv->security_work, 0);
 
-       queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0);
+       schedule_delayed_work(&priv->wx_event_work, 0);
 }
 
 static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
@@ -2178,9 +2181,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
 
        /* Make sure the RF Kill check timer is running */
        priv->stop_rf_kill = 0;
-       cancel_delayed_work(&priv->rf_kill);
-       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                          round_jiffies_relative(HZ));
+       mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
 }
 
 static void send_scan_event(void *data)
@@ -2215,13 +2216,12 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
        /* Only userspace-requested scan completion events go out immediately */
        if (!priv->user_requested_scan) {
                if (!delayed_work_pending(&priv->scan_event_later))
-                       queue_delayed_work(priv->workqueue,
-                                       &priv->scan_event_later,
-                                       round_jiffies_relative(msecs_to_jiffies(4000)));
+                       schedule_delayed_work(&priv->scan_event_later,
+                                             round_jiffies_relative(msecs_to_jiffies(4000)));
        } else {
                priv->user_requested_scan = 0;
                cancel_delayed_work(&priv->scan_event_later);
-               queue_work(priv->workqueue, &priv->scan_event_now);
+               schedule_work(&priv->scan_event_now);
        }
 }
 
@@ -2719,14 +2719,6 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
 
                packet = &priv->rx_buffers[i];
 
-               /* Sync the DMA for the STATUS buffer so CPU is sure to get
-                * the correct values */
-               pci_dma_sync_single_for_cpu(priv->pci_dev,
-                                           sq->nic +
-                                           sizeof(struct ipw2100_status) * i,
-                                           sizeof(struct ipw2100_status),
-                                           PCI_DMA_FROMDEVICE);
-
                /* Sync the DMA for the RX buffer so CPU is sure to get
                 * the correct values */
                pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
@@ -3060,9 +3052,9 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
 
                packet = list_entry(element, struct ipw2100_tx_packet, list);
 
-               IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
+               IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
                             &txq->drv[txq->next],
-                            (void *)(txq->nic + txq->next *
+                            (u32) (txq->nic + txq->next *
                                      sizeof(struct ipw2100_bd)));
 
                packet->index = txq->next;
@@ -3467,15 +3459,10 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
        dma_addr_t p;
 
        priv->msg_buffers =
-           (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
-                                               sizeof(struct
-                                                      ipw2100_tx_packet),
-                                               GFP_KERNEL);
-       if (!priv->msg_buffers) {
-               printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
-                      "buffers.\n", priv->net_dev->name);
+           kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
+                   GFP_KERNEL);
+       if (!priv->msg_buffers)
                return -ENOMEM;
-       }
 
        for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
                v = pci_alloc_consistent(priv->pci_dev,
@@ -3792,7 +3779,7 @@ IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
            IPW2100_ORD(COUNTRY_CODE,
                                "IEEE country code as recv'd from beacon"),
            IPW2100_ORD(COUNTRY_CHANNELS,
-                               "channels suported by country"),
+                               "channels supported by country"),
            IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
            IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
            IPW2100_ORD(ANTENNA_DIVERSITY,
@@ -4081,7 +4068,7 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
        ipw2100_firmware.version = 0;
 #endif
 
-       printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name);
+       printk(KERN_INFO "%s: Resetting on mode change.\n", priv->net_dev->name);
        priv->reset_backoff = 0;
        schedule_reset(priv);
 
@@ -4334,9 +4321,8 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
                                          "disabled by HW switch\n");
                        /* Make sure the RF_KILL check timer is running */
                        priv->stop_rf_kill = 0;
-                       cancel_delayed_work(&priv->rf_kill);
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          round_jiffies_relative(HZ));
+                       mod_delayed_work(system_wq, &priv->rf_kill,
+                                        round_jiffies_relative(HZ));
                } else
                        schedule_reset(priv);
        }
@@ -4467,20 +4453,17 @@ static void bd_queue_initialize(struct ipw2100_priv *priv,
        IPW_DEBUG_INFO("exit\n");
 }
 
-static void ipw2100_kill_workqueue(struct ipw2100_priv *priv)
+static void ipw2100_kill_works(struct ipw2100_priv *priv)
 {
-       if (priv->workqueue) {
-               priv->stop_rf_kill = 1;
-               priv->stop_hang_check = 1;
-               cancel_delayed_work(&priv->reset_work);
-               cancel_delayed_work(&priv->security_work);
-               cancel_delayed_work(&priv->wx_event_work);
-               cancel_delayed_work(&priv->hang_check);
-               cancel_delayed_work(&priv->rf_kill);
-               cancel_delayed_work(&priv->scan_event_later);
-               destroy_workqueue(priv->workqueue);
-               priv->workqueue = NULL;
-       }
+       priv->stop_rf_kill = 1;
+       priv->stop_hang_check = 1;
+       cancel_delayed_work_sync(&priv->reset_work);
+       cancel_delayed_work_sync(&priv->security_work);
+       cancel_delayed_work_sync(&priv->wx_event_work);
+       cancel_delayed_work_sync(&priv->hang_check);
+       cancel_delayed_work_sync(&priv->rf_kill);
+       cancel_work_sync(&priv->scan_event_now);
+       cancel_delayed_work_sync(&priv->scan_event_later);
 }
 
 static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
@@ -4499,10 +4482,8 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
        }
 
        priv->tx_buffers =
-           (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
-                                               sizeof(struct
-                                                      ipw2100_tx_packet),
-                                               GFP_ATOMIC);
+           kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
+                   GFP_ATOMIC);
        if (!priv->tx_buffers) {
                printk(KERN_ERR DRV_NAME
                       ": %s: alloc failed form tx buffers.\n",
@@ -4651,9 +4632,9 @@ static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
        /*
         * allocate packets
         */
-       priv->rx_buffers = (struct ipw2100_rx_packet *)
-           kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
-                   GFP_KERNEL);
+       priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH *
+                                  sizeof(struct ipw2100_rx_packet),
+                                  GFP_KERNEL);
        if (!priv->rx_buffers) {
                IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
 
@@ -5233,7 +5214,7 @@ struct security_info_params {
        u8 auth_mode;
        u8 replay_counters_number;
        u8 unicast_using_group;
-} __attribute__ ((packed));
+} __packed;
 
 static int ipw2100_set_security_information(struct ipw2100_priv *priv,
                                            int auth_mode,
@@ -5993,8 +5974,8 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev,
        struct ipw2100_priv *priv = libipw_priv(dev);
        char fw_ver[64], ucode_ver[64];
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 
        ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
        ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
@@ -6002,7 +5983,8 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev,
        snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
                 fw_ver, priv->eeprom_version, ucode_ver);
 
-       strcpy(info->bus_info, pci_name(priv->pci_dev));
+       strlcpy(info->bus_info, pci_name(priv->pci_dev),
+               sizeof(info->bus_info));
 }
 
 static u32 ipw2100_ethtool_get_link(struct net_device *dev)
@@ -6054,7 +6036,7 @@ static void ipw2100_hang_check(struct work_struct *work)
        priv->last_rtc = rtc;
 
        if (!priv->stop_hang_check)
-               queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+               schedule_delayed_work(&priv->hang_check, HZ / 2);
 
        spin_unlock_irqrestore(&priv->low_lock, flags);
 }
@@ -6070,8 +6052,8 @@ static void ipw2100_rf_kill(struct work_struct *work)
        if (rf_kill_active(priv)) {
                IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
                if (!priv->stop_rf_kill)
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          round_jiffies_relative(HZ));
+                       schedule_delayed_work(&priv->rf_kill,
+                                             round_jiffies_relative(HZ));
                goto exit_unlock;
        }
 
@@ -6096,7 +6078,6 @@ static const struct net_device_ops ipw2100_netdev_ops = {
        .ndo_stop               = ipw2100_close,
        .ndo_start_xmit         = libipw_xmit,
        .ndo_change_mtu         = libipw_change_mtu,
-       .ndo_init               = ipw2100_net_init,
        .ndo_tx_timeout         = ipw2100_tx_timeout,
        .ndo_set_mac_address    = ipw2100_set_address,
        .ndo_validate_addr      = eth_validate_addr,
@@ -6105,9 +6086,7 @@ static const struct net_device_ops ipw2100_netdev_ops = {
 /* Look into using netdev destructor to shutdown libipw? */
 
 static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
-                                              void __iomem * base_addr,
-                                              unsigned long mem_start,
-                                              unsigned long mem_len)
+                                              void __iomem * ioaddr)
 {
        struct ipw2100_priv *priv;
        struct net_device *dev;
@@ -6119,6 +6098,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        priv->ieee = netdev_priv(dev);
        priv->pci_dev = pci_dev;
        priv->net_dev = dev;
+       priv->ioaddr = ioaddr;
 
        priv->ieee->hard_start_xmit = ipw2100_tx;
        priv->ieee->set_security = shim__set_security;
@@ -6134,10 +6114,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        dev->watchdog_timeo = 3 * HZ;
        dev->irq = 0;
 
-       dev->base_addr = (unsigned long)base_addr;
-       dev->mem_start = mem_start;
-       dev->mem_end = dev->mem_start + mem_len - 1;
-
        /* NOTE: We don't use the wireless_handlers hook
         * in dev as the system will start throwing WX requests
         * to us before we're actually initialized and it just
@@ -6217,8 +6193,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        INIT_LIST_HEAD(&priv->fw_pend_list);
        INIT_STAT(&priv->fw_pend_stat);
 
-       priv->workqueue = create_workqueue(DRV_NAME);
-
        INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
        INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
        INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
@@ -6240,8 +6214,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
 static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
                                const struct pci_device_id *ent)
 {
-       unsigned long mem_start, mem_len, mem_flags;
-       void __iomem *base_addr = NULL;
+       void __iomem *ioaddr;
        struct net_device *dev = NULL;
        struct ipw2100_priv *priv = NULL;
        int err = 0;
@@ -6250,18 +6223,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
 
        IPW_DEBUG_INFO("enter\n");
 
-       mem_start = pci_resource_start(pci_dev, 0);
-       mem_len = pci_resource_len(pci_dev, 0);
-       mem_flags = pci_resource_flags(pci_dev, 0);
-
-       if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) {
+       if (!(pci_resource_flags(pci_dev, 0) & IORESOURCE_MEM)) {
                IPW_DEBUG_INFO("weird - resource type is not memory\n");
                err = -ENODEV;
-               goto fail;
+               goto out;
        }
 
-       base_addr = ioremap_nocache(mem_start, mem_len);
-       if (!base_addr) {
+       ioaddr = pci_iomap(pci_dev, 0, 0);
+       if (!ioaddr) {
                printk(KERN_WARNING DRV_NAME
                       "Error calling ioremap_nocache.\n");
                err = -EIO;
@@ -6269,7 +6238,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
        }
 
        /* allocate and initialize our net_device */
-       dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len);
+       dev = ipw2100_alloc_device(pci_dev, ioaddr);
        if (!dev) {
                printk(KERN_WARNING DRV_NAME
                       "Error calling ipw2100_alloc_device.\n");
@@ -6350,25 +6319,29 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
        printk(KERN_INFO DRV_NAME
               ": Detected Intel PRO/Wireless 2100 Network Connection\n");
 
+       err = ipw2100_up(priv, 1);
+       if (err)
+               goto fail;
+
+       err = ipw2100_wdev_init(dev);
+       if (err)
+               goto fail;
+       registered = 1;
+
        /* Bring up the interface.  Pre 0.46, after we registered the
         * network device we would call ipw2100_up.  This introduced a race
         * condition with newer hotplug configurations (network was coming
         * up and making calls before the device was initialized).
-        *
-        * If we called ipw2100_up before we registered the device, then the
-        * device name wasn't registered.  So, we instead use the net_dev->init
-        * member to call a function that then just turns and calls ipw2100_up.
-        * net_dev->init is called after name allocation but before the
-        * notifier chain is called */
+        */
        err = register_netdev(dev);
        if (err) {
                printk(KERN_WARNING DRV_NAME
                       "Error calling register_netdev.\n");
                goto fail;
        }
+       registered = 2;
 
        mutex_lock(&priv->action_mutex);
-       registered = 1;
 
        IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
 
@@ -6400,17 +6373,21 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
        priv->status |= STATUS_INITIALIZED;
 
        mutex_unlock(&priv->action_mutex);
-
-       return 0;
+out:
+       return err;
 
       fail_unlock:
        mutex_unlock(&priv->action_mutex);
-
       fail:
        if (dev) {
-               if (registered)
+               if (registered >= 2)
                        unregister_netdev(dev);
 
+               if (registered) {
+                       wiphy_unregister(priv->ieee->wdev.wiphy);
+                       kfree(priv->ieee->bg_band.channels);
+               }
+
                ipw2100_hw_stop_adapter(priv);
 
                ipw2100_disable_interrupts(priv);
@@ -6418,7 +6395,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
                if (dev->irq)
                        free_irq(dev->irq, priv);
 
-               ipw2100_kill_workqueue(priv);
+               ipw2100_kill_works(priv);
 
                /* These are safe to call even if they weren't allocated */
                ipw2100_queues_free(priv);
@@ -6429,65 +6406,56 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
                pci_set_drvdata(pci_dev, NULL);
        }
 
-       if (base_addr)
-               iounmap(base_addr);
+       pci_iounmap(pci_dev, ioaddr);
 
        pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
-
-       return err;
+       goto out;
 }
 
 static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
 {
        struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
-       struct net_device *dev;
+       struct net_device *dev = priv->net_dev;
 
-       if (priv) {
-               mutex_lock(&priv->action_mutex);
+       mutex_lock(&priv->action_mutex);
 
-               priv->status &= ~STATUS_INITIALIZED;
+       priv->status &= ~STATUS_INITIALIZED;
 
-               dev = priv->net_dev;
-               sysfs_remove_group(&pci_dev->dev.kobj,
-                                  &ipw2100_attribute_group);
+       sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
 
 #ifdef CONFIG_PM
-               if (ipw2100_firmware.version)
-                       ipw2100_release_firmware(priv, &ipw2100_firmware);
+       if (ipw2100_firmware.version)
+               ipw2100_release_firmware(priv, &ipw2100_firmware);
 #endif
-               /* Take down the hardware */
-               ipw2100_down(priv);
+       /* Take down the hardware */
+       ipw2100_down(priv);
 
-               /* Release the mutex so that the network subsystem can
-                * complete any needed calls into the driver... */
-               mutex_unlock(&priv->action_mutex);
+       /* Release the mutex so that the network subsystem can
+        * complete any needed calls into the driver... */
+       mutex_unlock(&priv->action_mutex);
 
-               /* Unregister the device first - this results in close()
-                * being called if the device is open.  If we free storage
-                * first, then close() will crash. */
-               unregister_netdev(dev);
+       /* Unregister the device first - this results in close()
+        * being called if the device is open.  If we free storage
+        * first, then close() will crash.
+        * FIXME: remove the comment above. */
+       unregister_netdev(dev);
 
-               /* ipw2100_down will ensure that there is no more pending work
-                * in the workqueue's, so we can safely remove them now. */
-               ipw2100_kill_workqueue(priv);
+       ipw2100_kill_works(priv);
 
-               ipw2100_queues_free(priv);
+       ipw2100_queues_free(priv);
 
-               /* Free potential debugging firmware snapshot */
-               ipw2100_snapshot_free(priv);
+       /* Free potential debugging firmware snapshot */
+       ipw2100_snapshot_free(priv);
 
-               if (dev->irq)
-                       free_irq(dev->irq, priv);
+       free_irq(dev->irq, priv);
 
-               if (dev->base_addr)
-                       iounmap((void __iomem *)dev->base_addr);
+       pci_iounmap(pci_dev, priv->ioaddr);
 
-               /* wiphy_unregister needs to be here, before free_libipw */
-               wiphy_unregister(priv->ieee->wdev.wiphy);
-               kfree(priv->ieee->bg_band.channels);
-               free_libipw(dev, 0);
-       }
+       /* wiphy_unregister needs to be here, before free_libipw */
+       wiphy_unregister(priv->ieee->wdev.wiphy);
+       kfree(priv->ieee->bg_band.channels);
+       free_libipw(dev, 0);
 
        pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
@@ -6665,12 +6633,13 @@ static int __init ipw2100_init(void)
        printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
        printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
 
+       pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+                          PM_QOS_DEFAULT_VALUE);
+
        ret = pci_register_driver(&ipw2100_pci_driver);
        if (ret)
                goto out;
 
-       pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
 #ifdef CONFIG_IPW2100_DEBUG
        ipw2100_debug_level = debug;
        ret = driver_create_file(&ipw2100_pci_driver.driver,
@@ -6905,7 +6874,7 @@ static int ipw2100_wx_get_range(struct net_device *dev,
        range->num_bitrates = RATE_COUNT;
 
        for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
-               range->bitrate[i] = ipw2100_rates_11b[i];
+               range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
        }
 
        range->min_rts = MIN_RTS_THRESHOLD;
@@ -8117,61 +8086,41 @@ static int ipw2100_wx_get_crc_check(struct net_device *dev,
 #endif                         /* CONFIG_IPW2100_MONITOR */
 
 static iw_handler ipw2100_wx_handlers[] = {
-       NULL,                   /* SIOCSIWCOMMIT */
-       ipw2100_wx_get_name,    /* SIOCGIWNAME */
-       NULL,                   /* SIOCSIWNWID */
-       NULL,                   /* SIOCGIWNWID */
-       ipw2100_wx_set_freq,    /* SIOCSIWFREQ */
-       ipw2100_wx_get_freq,    /* SIOCGIWFREQ */
-       ipw2100_wx_set_mode,    /* SIOCSIWMODE */
-       ipw2100_wx_get_mode,    /* SIOCGIWMODE */
-       NULL,                   /* SIOCSIWSENS */
-       NULL,                   /* SIOCGIWSENS */
-       NULL,                   /* SIOCSIWRANGE */
-       ipw2100_wx_get_range,   /* SIOCGIWRANGE */
-       NULL,                   /* SIOCSIWPRIV */
-       NULL,                   /* SIOCGIWPRIV */
-       NULL,                   /* SIOCSIWSTATS */
-       NULL,                   /* SIOCGIWSTATS */
-       NULL,                   /* SIOCSIWSPY */
-       NULL,                   /* SIOCGIWSPY */
-       NULL,                   /* SIOCGIWTHRSPY */
-       NULL,                   /* SIOCWIWTHRSPY */
-       ipw2100_wx_set_wap,     /* SIOCSIWAP */
-       ipw2100_wx_get_wap,     /* SIOCGIWAP */
-       ipw2100_wx_set_mlme,    /* SIOCSIWMLME */
-       NULL,                   /* SIOCGIWAPLIST -- deprecated */
-       ipw2100_wx_set_scan,    /* SIOCSIWSCAN */
-       ipw2100_wx_get_scan,    /* SIOCGIWSCAN */
-       ipw2100_wx_set_essid,   /* SIOCSIWESSID */
-       ipw2100_wx_get_essid,   /* SIOCGIWESSID */
-       ipw2100_wx_set_nick,    /* SIOCSIWNICKN */
-       ipw2100_wx_get_nick,    /* SIOCGIWNICKN */
-       NULL,                   /* -- hole -- */
-       NULL,                   /* -- hole -- */
-       ipw2100_wx_set_rate,    /* SIOCSIWRATE */
-       ipw2100_wx_get_rate,    /* SIOCGIWRATE */
-       ipw2100_wx_set_rts,     /* SIOCSIWRTS */
-       ipw2100_wx_get_rts,     /* SIOCGIWRTS */
-       ipw2100_wx_set_frag,    /* SIOCSIWFRAG */
-       ipw2100_wx_get_frag,    /* SIOCGIWFRAG */
-       ipw2100_wx_set_txpow,   /* SIOCSIWTXPOW */
-       ipw2100_wx_get_txpow,   /* SIOCGIWTXPOW */
-       ipw2100_wx_set_retry,   /* SIOCSIWRETRY */
-       ipw2100_wx_get_retry,   /* SIOCGIWRETRY */
-       ipw2100_wx_set_encode,  /* SIOCSIWENCODE */
-       ipw2100_wx_get_encode,  /* SIOCGIWENCODE */
-       ipw2100_wx_set_power,   /* SIOCSIWPOWER */
-       ipw2100_wx_get_power,   /* SIOCGIWPOWER */
-       NULL,                   /* -- hole -- */
-       NULL,                   /* -- hole -- */
-       ipw2100_wx_set_genie,   /* SIOCSIWGENIE */
-       ipw2100_wx_get_genie,   /* SIOCGIWGENIE */
-       ipw2100_wx_set_auth,    /* SIOCSIWAUTH */
-       ipw2100_wx_get_auth,    /* SIOCGIWAUTH */
-       ipw2100_wx_set_encodeext,       /* SIOCSIWENCODEEXT */
-       ipw2100_wx_get_encodeext,       /* SIOCGIWENCODEEXT */
-       NULL,                   /* SIOCSIWPMKSA */
+       IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
+       IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
+       IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
+       IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
+       IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
+       IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
+       IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
+       IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
+       IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
+       IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
+       IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
+       IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
+       IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
+       IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
+       IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
+       IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
+       IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
+       IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
+       IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
+       IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
+       IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
+       IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
+       IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
+       IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
+       IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
+       IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
+       IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
+       IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
+       IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
+       IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
+       IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
+       IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
+       IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
+       IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
+       IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
 };
 
 #define IPW2100_PRIV_SET_MONITOR       SIOCIWFIRSTPRIV
@@ -8475,7 +8424,7 @@ struct ipw2100_fw_header {
        short mode;
        unsigned int fw_size;
        unsigned int uc_size;
-} __attribute__ ((packed));
+} __packed;
 
 static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
 {
@@ -8549,8 +8498,7 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv,
                                     struct ipw2100_fw *fw)
 {
        fw->version = 0;
-       if (fw->fw_entry)
-               release_firmware(fw->fw_entry);
+       release_firmware(fw->fw_entry);
        fw->fw_entry = NULL;
 }
 
@@ -8650,7 +8598,7 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv,
        struct net_device *dev = priv->net_dev;
        const unsigned char *microcode_data = fw->uc.data;
        unsigned int microcode_data_left = fw->uc.size;
-       void __iomem *reg = (void __iomem *)dev->base_addr;
+       void __iomem *reg = priv->ioaddr;
 
        struct symbol_alive_response response;
        int i, j;