Merge branch 'from-linus' into upstream
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 11 Sep 2006 18:08:41 +0000 (14:08 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 11 Sep 2006 18:08:41 +0000 (14:08 -0400)
50 files changed:
MAINTAINERS
drivers/net/wireless/Kconfig
drivers/net/wireless/airo.c
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
drivers/net/wireless/bcm43xx/bcm43xx_dma.c
drivers/net/wireless/bcm43xx/bcm43xx_dma.h
drivers/net/wireless/bcm43xx/bcm43xx_leds.c
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_main.h
drivers/net/wireless/bcm43xx/bcm43xx_phy.c
drivers/net/wireless/bcm43xx/bcm43xx_pio.c
drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
drivers/net/wireless/bcm43xx/bcm43xx_wx.c
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
drivers/net/wireless/ipw2100.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/ipw2200.h
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.h
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/isl_ioctl.h
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_dev.h
drivers/net/wireless/ray_cs.c
drivers/net/wireless/zd1211rw/Makefile
drivers/net/wireless/zd1211rw/zd_chip.c
drivers/net/wireless/zd1211rw/zd_chip.h
drivers/net/wireless/zd1211rw/zd_def.h
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/wireless/zd1211rw/zd_mac.h
drivers/net/wireless/zd1211rw/zd_netdev.c
drivers/net/wireless/zd1211rw/zd_rf.c
drivers/net/wireless/zd1211rw/zd_rf.h
drivers/net/wireless/zd1211rw/zd_rf_al2230.c
drivers/net/wireless/zd1211rw/zd_rf_al7230b.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/wireless/zd1211rw/zd_usb.h
include/net/ieee80211.h
include/net/ieee80211softmac.h
net/ieee80211/ieee80211_crypt_ccmp.c
net/ieee80211/ieee80211_crypt_tkip.c
net/ieee80211/ieee80211_crypt_wep.c
net/ieee80211/ieee80211_rx.c
net/ieee80211/ieee80211_tx.c
net/ieee80211/softmac/ieee80211softmac_assoc.c
net/ieee80211/softmac/ieee80211softmac_io.c
net/ieee80211/softmac/ieee80211softmac_module.c
net/ieee80211/softmac/ieee80211softmac_priv.h

index 25cd7073a20bbedc0094630b575ffc90edab8e51..c04c25ea31419b70fb623115c8df47ae79c754e0 100644 (file)
@@ -449,9 +449,9 @@ L:  linux-hams@vger.kernel.org
 W:     http://www.baycom.org/~tom/ham/ham.html
 S:     Maintained
 
-BCM43XX WIRELESS DRIVER
-P:     Michael Buesch
-M:     mb@bu3sch.de
+BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION)
+P:     Larry Finger
+M:     Larry.Finger@lwfinger.net
 P:     Stefano Brivio
 M:     st3@riseup.net
 W:     http://bcm43xx.berlios.de/
@@ -2616,6 +2616,18 @@ P:       Nicolas Pitre
 M:     nico@cam.org
 S:     Maintained
 
+SOFTMAC LAYER (IEEE 802.11)
+P:     Johannes Berg
+M:     johannes@sipsolutions.net
+P:     Joe Jezak
+M:     josejx@gentoo.org
+P:     Daniel Drake
+M:     dsd@gentoo.org
+W:     http://softmac.sipsolutions.net/
+L:     softmac-dev@sipsolutions.net
+L:     netdev@vger.kernel.org
+S:     Maintained
+
 SOFTWARE RAID (Multiple Disks) SUPPORT
 P:     Ingo Molnar
 M:     mingo@redhat.com
@@ -3341,6 +3353,15 @@ W:       http://www.qsl.net/dl1bke/
 L:     linux-hams@vger.kernel.org
 S:     Maintained
 
+ZD1211RW WIRELESS DRIVER
+P:     Daniel Drake
+M:     dsd@gentoo.org
+P:     Ulrich Kunitz
+M:     kune@deine-taler.de
+W:     http://zd1211.ath.cx/wiki/DriverRewrite
+L:     zd1211-devs@lists.sourceforge.net (subscribers-only)
+S:     Maintained
+
 ZF MACHZ WATCHDOG
 P:     Fernando Fuganti
 M:     fuganti@netbank.com.br
index 2e8ac995d56f0b404a98ed4f24e9b2cc549750c5..bd4a68c85a4717e00cb354c7c43125bd325d88af 100644 (file)
@@ -271,25 +271,14 @@ config IPW2200_DEBUG
        bool "Enable full debugging output in IPW2200 module."
        depends on IPW2200
        ---help---
-         This option will enable debug tracing output for the IPW2200.  
+         This option will enable low level debug tracing output for IPW2200.
 
-         This will result in the kernel module being ~100k larger.  You can 
-         control which debug output is sent to the kernel log by setting the 
-         value in 
-
-         /sys/bus/pci/drivers/ipw2200/debug_level
-
-         This entry will only exist if this option is enabled.
+         Note, normal debug code is already compiled in. This low level
+         debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
+         will result in the kernel module being ~70 larger.  Most users
+         will typically not need this high verbosity debug information.
 
-         To set a value, simply echo an 8-byte hex value to the same file:
-
-         % echo 0x00000FFO > /sys/bus/pci/drivers/ipw2200/debug_level
-
-         You can find the list of debug mask values in 
-         drivers/net/wireless/ipw2200.h
-
-         If you are not trying to debug or develop the IPW2200 driver, you 
-         most likely want to say N here.
+         If you are not sure, say N here.
 
 config AIRO
        tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
index a4dd1394271446192ccf51a26a82d70c4d0bf042..e088ceefb4a35468918fe059e129ab497fbc2ac4 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/pci.h>
 #include <asm/uaccess.h>
 #include <net/ieee80211.h>
+#include <linux/kthread.h>
 
 #include "airo.h"
 
@@ -1187,11 +1188,10 @@ struct airo_info {
                        int whichbap);
        unsigned short *flash;
        tdsRssiEntry *rssi;
-       struct task_struct *task;
+       struct task_struct *list_bss_task;
+       struct task_struct *airo_thread_task;
        struct semaphore sem;
-       pid_t thr_pid;
        wait_queue_head_t thr_wait;
-       struct completion thr_exited;
        unsigned long expires;
        struct {
                struct sk_buff *skb;
@@ -1733,12 +1733,12 @@ static int readBSSListRid(struct airo_info *ai, int first,
                cmd.cmd=CMD_LISTBSS;
                if (down_interruptible(&ai->sem))
                        return -ERESTARTSYS;
+               ai->list_bss_task = current;
                issuecommand(ai, &cmd, &rsp);
                up(&ai->sem);
                /* Let the command take effect */
-               ai->task = current;
-               ssleep(3);
-               ai->task = NULL;
+               schedule_timeout_uninterruptible(3 * HZ);
+               ai->list_bss_task = NULL;
        }
        rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
                            list, ai->bssListRidLen, 1);
@@ -2400,8 +2400,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
                clear_bit(FLAG_REGISTERED, &ai->flags);
        }
        set_bit(JOB_DIE, &ai->jobs);
-       kill_proc(ai->thr_pid, SIGTERM, 1);
-       wait_for_completion(&ai->thr_exited);
+       kthread_stop(ai->airo_thread_task);
 
        /*
         * Clean out tx queue
@@ -2811,9 +2810,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        ai->config.len = 0;
        ai->pci = pci;
        init_waitqueue_head (&ai->thr_wait);
-       init_completion (&ai->thr_exited);
-       ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
-       if (ai->thr_pid < 0)
+       ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
+       if (IS_ERR(ai->airo_thread_task))
                goto err_out_free;
        ai->tfm = NULL;
        rc = add_airo_dev( dev );
@@ -2930,8 +2928,7 @@ err_out_unlink:
        del_airo_dev(dev);
 err_out_thr:
        set_bit(JOB_DIE, &ai->jobs);
-       kill_proc(ai->thr_pid, SIGTERM, 1);
-       wait_for_completion(&ai->thr_exited);
+       kthread_stop(ai->airo_thread_task);
 err_out_free:
        free_netdev(dev);
        return NULL;
@@ -3063,13 +3060,7 @@ static int airo_thread(void *data) {
        struct airo_info *ai = dev->priv;
        int locked;
        
-       daemonize("%s", dev->name);
-       allow_signal(SIGTERM);
-
        while(1) {
-               if (signal_pending(current))
-                       flush_signals(current);
-
                /* make swsusp happy with our thread */
                try_to_freeze();
 
@@ -3097,7 +3088,7 @@ static int airo_thread(void *data) {
                                                set_bit(JOB_AUTOWEP, &ai->jobs);
                                                break;
                                        }
-                                       if (!signal_pending(current)) {
+                                       if (!kthread_should_stop()) {
                                                unsigned long wake_at;
                                                if (!ai->expires || !ai->scan_timeout) {
                                                        wake_at = max(ai->expires,
@@ -3109,7 +3100,7 @@ static int airo_thread(void *data) {
                                                schedule_timeout(wake_at - jiffies);
                                                continue;
                                        }
-                               } else if (!signal_pending(current)) {
+                               } else if (!kthread_should_stop()) {
                                        schedule();
                                        continue;
                                }
@@ -3154,7 +3145,8 @@ static int airo_thread(void *data) {
                else  /* Shouldn't get here, but we make sure to unlock */
                        up(&ai->sem);
        }
-       complete_and_exit (&ai->thr_exited, 0);
+
+       return 0;
 }
 
 static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
@@ -3235,8 +3227,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                        if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
                                if (auto_wep)
                                        apriv->expires = 0;
-                               if (apriv->task)
-                                       wake_up_process (apriv->task);
+                               if (apriv->list_bss_task)
+                                       wake_up_process(apriv->list_bss_task);
                                set_bit(FLAG_UPDATE_UNI, &apriv->flags);
                                set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
 
@@ -3950,13 +3942,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
        pRsp->rsp0 = IN4500(ai, RESP0);
        pRsp->rsp1 = IN4500(ai, RESP1);
        pRsp->rsp2 = IN4500(ai, RESP2);
-       if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
-               airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
-               airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
-               airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
-               airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
-               airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
-       }
+       if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
+               airo_print_err(ai->dev->name,
+                       "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
+                       pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
+                       pRsp->rsp2);
 
        // clear stuck command busy if necessary
        if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
index 17a56828e232953a9c2ac0f80328606377918f1c..62fd7e2377890158b3fcc9de5df6820b6b576ba1 100644 (file)
 #define BCM43xx_PCICFG_ICR             0x94
 
 /* MMIO offsets */
-#define BCM43xx_MMIO_DMA1_REASON       0x20
-#define BCM43xx_MMIO_DMA1_IRQ_MASK     0x24
-#define BCM43xx_MMIO_DMA2_REASON       0x28
-#define BCM43xx_MMIO_DMA2_IRQ_MASK     0x2C
-#define BCM43xx_MMIO_DMA3_REASON       0x30
-#define BCM43xx_MMIO_DMA3_IRQ_MASK     0x34
-#define BCM43xx_MMIO_DMA4_REASON       0x38
-#define BCM43xx_MMIO_DMA4_IRQ_MASK     0x3C
+#define BCM43xx_MMIO_DMA0_REASON       0x20
+#define BCM43xx_MMIO_DMA0_IRQ_MASK     0x24
+#define BCM43xx_MMIO_DMA1_REASON       0x28
+#define BCM43xx_MMIO_DMA1_IRQ_MASK     0x2C
+#define BCM43xx_MMIO_DMA2_REASON       0x30
+#define BCM43xx_MMIO_DMA2_IRQ_MASK     0x34
+#define BCM43xx_MMIO_DMA3_REASON       0x38
+#define BCM43xx_MMIO_DMA3_IRQ_MASK     0x3C
+#define BCM43xx_MMIO_DMA4_REASON       0x40
+#define BCM43xx_MMIO_DMA4_IRQ_MASK     0x44
+#define BCM43xx_MMIO_DMA5_REASON       0x48
+#define BCM43xx_MMIO_DMA5_IRQ_MASK     0x4C
 #define BCM43xx_MMIO_STATUS_BITFIELD   0x120
 #define BCM43xx_MMIO_STATUS2_BITFIELD  0x124
 #define BCM43xx_MMIO_GEN_IRQ_REASON    0x128
 #define BCM43xx_MMIO_XMITSTAT_1                0x174
 #define BCM43xx_MMIO_REV3PLUS_TSF_LOW  0x180 /* core rev >= 3 only */
 #define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
-#define BCM43xx_MMIO_DMA1_BASE         0x200
-#define BCM43xx_MMIO_DMA2_BASE         0x220
-#define BCM43xx_MMIO_DMA3_BASE         0x240
-#define BCM43xx_MMIO_DMA4_BASE         0x260
+
+/* 32-bit DMA */
+#define BCM43xx_MMIO_DMA32_BASE0       0x200
+#define BCM43xx_MMIO_DMA32_BASE1       0x220
+#define BCM43xx_MMIO_DMA32_BASE2       0x240
+#define BCM43xx_MMIO_DMA32_BASE3       0x260
+#define BCM43xx_MMIO_DMA32_BASE4       0x280
+#define BCM43xx_MMIO_DMA32_BASE5       0x2A0
+/* 64-bit DMA */
+#define BCM43xx_MMIO_DMA64_BASE0       0x200
+#define BCM43xx_MMIO_DMA64_BASE1       0x240
+#define BCM43xx_MMIO_DMA64_BASE2       0x280
+#define BCM43xx_MMIO_DMA64_BASE3       0x2C0
+#define BCM43xx_MMIO_DMA64_BASE4       0x300
+#define BCM43xx_MMIO_DMA64_BASE5       0x340
+/* PIO */
 #define BCM43xx_MMIO_PIO1_BASE         0x300
 #define BCM43xx_MMIO_PIO2_BASE         0x310
 #define BCM43xx_MMIO_PIO3_BASE         0x320
 #define BCM43xx_MMIO_PIO4_BASE         0x330
+
 #define BCM43xx_MMIO_PHY_VER           0x3E0
 #define BCM43xx_MMIO_PHY_RADIO         0x3E2
 #define BCM43xx_MMIO_ANTENNA           0x3E8
 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK  0x20000
 
 /* sbtmstatehigh state flags */
-#define BCM43xx_SBTMSTATEHIGH_SERROR           0x1
-#define BCM43xx_SBTMSTATEHIGH_BUSY             0x4
+#define BCM43xx_SBTMSTATEHIGH_SERROR           0x00000001
+#define BCM43xx_SBTMSTATEHIGH_BUSY             0x00000004
+#define BCM43xx_SBTMSTATEHIGH_TIMEOUT          0x00000020
+#define BCM43xx_SBTMSTATEHIGH_COREFLAGS                0x1FFF0000
+#define BCM43xx_SBTMSTATEHIGH_DMA64BIT         0x10000000
+#define BCM43xx_SBTMSTATEHIGH_GATEDCLK         0x20000000
+#define BCM43xx_SBTMSTATEHIGH_BISTFAILED       0x40000000
+#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE     0x80000000
 
 /* sbimstate flags */
 #define BCM43xx_SBIMSTATE_IB_ERROR             0x20000
@@ -504,6 +527,12 @@ struct bcm43xx_phyinfo {
         * This lock is only used by bcm43xx_phy_{un}lock()
         */
        spinlock_t lock;
+
+       /* Firmware. */
+       const struct firmware *ucode;
+       const struct firmware *pcm;
+       const struct firmware *initvals0;
+       const struct firmware *initvals1;
 };
 
 
@@ -568,8 +597,11 @@ struct bcm43xx_dma {
        struct bcm43xx_dmaring *tx_ring1;
        struct bcm43xx_dmaring *tx_ring2;
        struct bcm43xx_dmaring *tx_ring3;
+       struct bcm43xx_dmaring *tx_ring4;
+       struct bcm43xx_dmaring *tx_ring5;
+
        struct bcm43xx_dmaring *rx_ring0;
-       struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
+       struct bcm43xx_dmaring *rx_ring3; /* only available on core.rev < 5 */
 };
 
 /* Data structures for PIO transmission, per 80211 core. */
@@ -593,12 +625,14 @@ struct bcm43xx_coreinfo {
        u8 available:1,
           enabled:1,
           initialized:1;
-       /** core_id ID number */
-       u16 id;
        /** core_rev revision number */
        u8 rev;
        /** Index number for _switch_core() */
        u8 index;
+       /** core_id ID number */
+       u16 id;
+       /** Core-specific data. */
+       void *priv;
 };
 
 /* Additional information for each 80211 core. */
@@ -647,7 +681,23 @@ enum {
        BCM43xx_STAT_RESTARTING,        /* controller_restart() called. */
 };
 #define bcm43xx_status(bcm)            atomic_read(&(bcm)->init_status)
-#define bcm43xx_set_status(bcm, stat)  atomic_set(&(bcm)->init_status, (stat))
+#define bcm43xx_set_status(bcm, stat)  do {                    \
+               atomic_set(&(bcm)->init_status, (stat));        \
+               smp_wmb();                                      \
+                                       } while (0)
+
+/*    *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
+ *                   and the device registers. This mutex does _not_ protect
+ *                   against concurrency from the IRQ handler.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * Please note that, if you only take the irq_lock, you are not protected
+ * against concurrency from the periodic work handlers.
+ * Most times you want to take _both_ locks.
+ */
 
 struct bcm43xx_private {
        struct ieee80211_device *ieee;
@@ -659,7 +709,6 @@ struct bcm43xx_private {
 
        void __iomem *mmio_addr;
 
-       /* Locking, see "theory of locking" text below. */
        spinlock_t irq_lock;
        struct mutex mutex;
 
@@ -691,6 +740,7 @@ struct bcm43xx_private {
        struct bcm43xx_sprominfo sprom;
 #define BCM43xx_NR_LEDS                4
        struct bcm43xx_led leds[BCM43xx_NR_LEDS];
+       spinlock_t leds_lock;
 
        /* The currently active core. */
        struct bcm43xx_coreinfo *current_core;
@@ -708,10 +758,6 @@ struct bcm43xx_private {
        struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
        /* Additional information, specific to the 80211 cores. */
        struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
-       /* Index of the current 80211 core. If current_core is not
-        * an 80211 core, this is -1.
-        */
-       int current_80211_core_idx;
        /* Number of available 80211 cores. */
        int nr_80211_available;
 
@@ -719,11 +765,13 @@ struct bcm43xx_private {
 
        /* Reason code of the last interrupt. */
        u32 irq_reason;
-       u32 dma_reason[4];
+       u32 dma_reason[6];
        /* saved irq enable/disable state bitfield. */
        u32 irq_savedstate;
        /* Link Quality calculation context. */
        struct bcm43xx_noise_calculation noisecalc;
+       /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+       int mac_suspended;
 
        /* Threshold values. */
        //TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
@@ -746,12 +794,6 @@ struct bcm43xx_private {
        struct bcm43xx_key key[54];
        u8 default_key_idx;
 
-       /* Firmware. */
-       const struct firmware *ucode;
-       const struct firmware *pcm;
-       const struct firmware *initvals0;
-       const struct firmware *initvals1;
-
        /* Random Number Generator. */
        struct hwrng rng;
        char rng_name[20 + 1];
@@ -763,55 +805,6 @@ struct bcm43xx_private {
 };
 
 
-/*    *** THEORY OF LOCKING ***
- *
- * We have two different locks in the bcm43xx driver.
- * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
- *                   and the device registers.
- * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
- *
- * We have three types of helper function pairs to utilize these locks.
- *     (Always use the helper functions.)
- * 1) bcm43xx_{un}lock_noirq():
- *     Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
- *     so it is almost always unsafe, if device IRQs are enabled.
- *     So only use this, if device IRQs are masked.
- *     Locking may sleep.
- *     You can sleep within the critical section.
- * 2) bcm43xx_{un}lock_irqonly():
- *     Takes bcm->irq_lock. Does _not_ protect against
- *     bcm43xx_lock_noirq() critical sections.
- *     Does only protect against the IRQ handler path and other
- *     irqonly() critical sections.
- *     Locking does not sleep.
- *     You must not sleep within the critical section.
- * 3) bcm43xx_{un}lock_irqsafe():
- *     This is the cummulative lock and takes both, mutex and irq_lock.
- *     Protects against noirq() and irqonly() critical sections (and
- *     the IRQ handler path).
- *     Locking may sleep.
- *     You must not sleep within the critical section.
- */
-
-/* Lock type 1 */
-#define bcm43xx_lock_noirq(bcm)                mutex_lock(&(bcm)->mutex)
-#define bcm43xx_unlock_noirq(bcm)      mutex_unlock(&(bcm)->mutex)
-/* Lock type 2 */
-#define bcm43xx_lock_irqonly(bcm, flags)       \
-       spin_lock_irqsave(&(bcm)->irq_lock, flags)
-#define bcm43xx_unlock_irqonly(bcm, flags)     \
-       spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
-/* Lock type 3 */
-#define bcm43xx_lock_irqsafe(bcm, flags) do {  \
-       bcm43xx_lock_noirq(bcm);                \
-       bcm43xx_lock_irqonly(bcm, flags);       \
-               } while (0)
-#define bcm43xx_unlock_irqsafe(bcm, flags) do {        \
-       bcm43xx_unlock_irqonly(bcm, flags);     \
-       bcm43xx_unlock_noirq(bcm);              \
-               } while (0)
-
-
 static inline
 struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
 {
@@ -863,34 +856,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm)
  * any of these functions.
  */
 static inline
+struct bcm43xx_coreinfo_80211 *
+bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
+{
+       assert(bcm->current_core->id == BCM43xx_COREID_80211);
+       return bcm->current_core->priv;
+}
+static inline
 struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
 {
        assert(bcm43xx_using_pio(bcm));
-       assert(bcm->current_80211_core_idx >= 0);
-       assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-       return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
+       return &(bcm43xx_current_80211_priv(bcm)->pio);
 }
 static inline
 struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
 {
        assert(!bcm43xx_using_pio(bcm));
-       assert(bcm->current_80211_core_idx >= 0);
-       assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-       return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
+       return &(bcm43xx_current_80211_priv(bcm)->dma);
 }
 static inline
 struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
 {
-       assert(bcm->current_80211_core_idx >= 0);
-       assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-       return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
+       return &(bcm43xx_current_80211_priv(bcm)->phy);
 }
 static inline
 struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
 {
-       assert(bcm->current_80211_core_idx >= 0);
-       assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-       return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
+       return &(bcm43xx_current_80211_priv(bcm)->radio);
 }
 
 
index ce2e40b29b4f0533c1e8150161c29ccfeb18efd6..923275ea0789aa6e26b031a74b521b64f2ce7eb2 100644 (file)
@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
 
        down(&big_buffer_sem);
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
                fappend("Board not initialized.\n");
                goto out;
@@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
        fappend("\n");
 
 out:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
        up(&big_buffer_sem);
        return res;
@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
        unsigned long flags;
 
        down(&big_buffer_sem);
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
                fappend("Board not initialized.\n");
                goto out;
@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
        fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
 
 out:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
        up(&big_buffer_sem);
        return res;
@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
        u64 tsf;
 
        down(&big_buffer_sem);
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
                fappend("Board not initialized.\n");
                goto out;
@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
                (unsigned int)(tsf & 0xFFFFFFFFULL));
 
 out:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
        up(&big_buffer_sem);
        return res;
@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
                res = -EFAULT;
                goto out_up;
        }
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
                printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
                res = -EFAULT;
@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
        res = buf_size;
        
 out_unlock:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 out_up:
        up(&big_buffer_sem);
        return res;
@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
        int i, cnt, j = 0;
 
        down(&big_buffer_sem);
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
 
        fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
                BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
                        i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
        }
 
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-       bcm43xx_lock_irqsafe(bcm, flags);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (*ppos == pos) {
                /* Done. Drop the copied data. */
                e->xmitstatus_printing = 0;
        }
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
+       up(&big_buffer_sem);
+       return res;
+}
+
+static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct bcm43xx_private *bcm = file->private_data;
+       char *buf = really_big_buffer;
+       ssize_t buf_size;
+       ssize_t res;
+       unsigned long flags;
+
+       buf_size = min(count, sizeof (really_big_buffer) - 1);
+       down(&big_buffer_sem);
+       if (copy_from_user(buf, user_buf, buf_size)) {
+               res = -EFAULT;
+               goto out_up;
+       }
+       mutex_lock(&(bcm)->mutex);
+       spin_lock_irqsave(&(bcm)->irq_lock, flags);
+       if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+               printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+               res = -EFAULT;
+               goto out_unlock;
+       }
+       if (count > 0 && buf[0] == '1') {
+               bcm43xx_controller_restart(bcm, "manually restarted");
+               res = count;
+       } else
+               res = -EINVAL;
+
+out_unlock:
+       spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
+       mutex_unlock(&(bcm)->mutex);
+out_up:
        up(&big_buffer_sem);
        return res;
 }
@@ -339,6 +385,11 @@ static struct file_operations txstat_fops = {
        .open = open_file_generic,
 };
 
+static struct file_operations restart_fops = {
+       .write = restart_write_file,
+       .open = open_file_generic,
+};
+
 
 void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
 {
@@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
                                                bcm, &txstat_fops);
        if (!e->dentry_txstat)
                printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
+       e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
+                                               bcm, &restart_fops);
+       if (!e->dentry_restart)
+               printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
 }
 
 void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
@@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
        debugfs_remove(e->dentry_devinfo);
        debugfs_remove(e->dentry_tsf);
        debugfs_remove(e->dentry_txstat);
+       debugfs_remove(e->dentry_restart);
        debugfs_remove(e->subdir);
        kfree(e->xmitstatus_buffer);
        kfree(e->xmitstatus_print_buffer);
index 50ce267f794d0fe51a37dbee1e52e61919a2ca87..a40d1af355452eca3ec1d16fb967a58a2ca847c7 100644 (file)
@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
        struct dentry *dentry_spromdump;
        struct dentry *dentry_tsf;
        struct dentry *dentry_txstat;
+       struct dentry *dentry_restart;
 
        struct bcm43xx_private *bcm;
 
index d0318e525ba767d12016d429ab8ca967569ea57c..76e3aed4b4711893a4cd96fc8ef6a06af20fc35d 100644 (file)
@@ -4,7 +4,7 @@
 
   DMA ringbuffer and descriptor allocation/management
 
-  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+  Copyright (c) 2005, 2006 Michael Buesch <mbuesch@freenet.de>
 
   Some code in this file is derived from the b44.c driver
   Copyright (C) 2002 David S. Miller
@@ -109,6 +109,35 @@ void return_slot(struct bcm43xx_dmaring *ring, int slot)
        }
 }
 
+u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
+{
+       static const u16 map64[] = {
+               BCM43xx_MMIO_DMA64_BASE0,
+               BCM43xx_MMIO_DMA64_BASE1,
+               BCM43xx_MMIO_DMA64_BASE2,
+               BCM43xx_MMIO_DMA64_BASE3,
+               BCM43xx_MMIO_DMA64_BASE4,
+               BCM43xx_MMIO_DMA64_BASE5,
+       };
+       static const u16 map32[] = {
+               BCM43xx_MMIO_DMA32_BASE0,
+               BCM43xx_MMIO_DMA32_BASE1,
+               BCM43xx_MMIO_DMA32_BASE2,
+               BCM43xx_MMIO_DMA32_BASE3,
+               BCM43xx_MMIO_DMA32_BASE4,
+               BCM43xx_MMIO_DMA32_BASE5,
+       };
+
+       if (dma64bit) {
+               assert(controller_idx >= 0 &&
+                      controller_idx < ARRAY_SIZE(map64));
+               return map64[controller_idx];
+       }
+       assert(controller_idx >= 0 &&
+              controller_idx < ARRAY_SIZE(map32));
+       return map32[controller_idx];
+}
+
 static inline
 dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
                          unsigned char *buf,
@@ -172,7 +201,6 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
 /* Unmap and free a descriptor buffer. */
 static inline
 void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
-                           struct bcm43xx_dmadesc *desc,
                            struct bcm43xx_dmadesc_meta *meta,
                            int irq_context)
 {
@@ -188,23 +216,13 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
 {
        struct device *dev = &(ring->bcm->pci_dev->dev);
 
-       ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-                                        &(ring->dmabase), GFP_KERNEL);
-       if (!ring->vbase) {
+       ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+                                           &(ring->dmabase), GFP_KERNEL);
+       if (!ring->descbase) {
                printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
                return -ENOMEM;
        }
-       if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
-               printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RINGMEMORY >1G "
-                                   "(0x%llx, len: %lu)\n",
-                               (unsigned long long)ring->dmabase,
-                               BCM43xx_DMA_RINGMEMSIZE);
-               dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-                                 ring->vbase, ring->dmabase);
-               return -ENOMEM;
-       }
-       assert(!(ring->dmabase & 0x000003FF));
-       memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+       memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
 
        return 0;
 }
@@ -214,26 +232,34 @@ static void free_ringmemory(struct bcm43xx_dmaring *ring)
        struct device *dev = &(ring->bcm->pci_dev->dev);
 
        dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-                         ring->vbase, ring->dmabase);
+                         ring->descbase, ring->dmabase);
 }
 
 /* Reset the RX DMA channel */
 int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
-                                  u16 mmio_base)
+                                  u16 mmio_base, int dma64)
 {
        int i;
        u32 value;
+       u16 offset;
 
-       bcm43xx_write32(bcm,
-                       mmio_base + BCM43xx_DMA_RX_CONTROL,
-                       0x00000000);
+       offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
+       bcm43xx_write32(bcm, mmio_base + offset, 0);
        for (i = 0; i < 1000; i++) {
-               value = bcm43xx_read32(bcm,
-                                      mmio_base + BCM43xx_DMA_RX_STATUS);
-               value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
-               if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
-                       i = -1;
-                       break;
+               offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
+               value = bcm43xx_read32(bcm, mmio_base + offset);
+               if (dma64) {
+                       value &= BCM43xx_DMA64_RXSTAT;
+                       if (value == BCM43xx_DMA64_RXSTAT_DISABLED) {
+                               i = -1;
+                               break;
+                       }
+               } else {
+                       value &= BCM43xx_DMA32_RXSTATE;
+                       if (value == BCM43xx_DMA32_RXSTAT_DISABLED) {
+                               i = -1;
+                               break;
+                       }
                }
                udelay(10);
        }
@@ -247,31 +273,47 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
 
 /* Reset the RX DMA channel */
 int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
-                                  u16 mmio_base)
+                                  u16 mmio_base, int dma64)
 {
        int i;
        u32 value;
+       u16 offset;
 
        for (i = 0; i < 1000; i++) {
-               value = bcm43xx_read32(bcm,
-                                      mmio_base + BCM43xx_DMA_TX_STATUS);
-               value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
-               if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
-                   value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
-                   value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
-                       break;
+               offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+               value = bcm43xx_read32(bcm, mmio_base + offset);
+               if (dma64) {
+                       value &= BCM43xx_DMA64_TXSTAT;
+                       if (value == BCM43xx_DMA64_TXSTAT_DISABLED ||
+                           value == BCM43xx_DMA64_TXSTAT_IDLEWAIT ||
+                           value == BCM43xx_DMA64_TXSTAT_STOPPED)
+                               break;
+               } else {
+                       value &= BCM43xx_DMA32_TXSTATE;
+                       if (value == BCM43xx_DMA32_TXSTAT_DISABLED ||
+                           value == BCM43xx_DMA32_TXSTAT_IDLEWAIT ||
+                           value == BCM43xx_DMA32_TXSTAT_STOPPED)
+                               break;
+               }
                udelay(10);
        }
-       bcm43xx_write32(bcm,
-                       mmio_base + BCM43xx_DMA_TX_CONTROL,
-                       0x00000000);
+       offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
+       bcm43xx_write32(bcm, mmio_base + offset, 0);
        for (i = 0; i < 1000; i++) {
-               value = bcm43xx_read32(bcm,
-                                      mmio_base + BCM43xx_DMA_TX_STATUS);
-               value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
-               if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
-                       i = -1;
-                       break;
+               offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+               value = bcm43xx_read32(bcm, mmio_base + offset);
+               if (dma64) {
+                       value &= BCM43xx_DMA64_TXSTAT;
+                       if (value == BCM43xx_DMA64_TXSTAT_DISABLED) {
+                               i = -1;
+                               break;
+                       }
+               } else {
+                       value &= BCM43xx_DMA32_TXSTATE;
+                       if (value == BCM43xx_DMA32_TXSTAT_DISABLED) {
+                               i = -1;
+                               break;
+                       }
                }
                udelay(10);
        }
@@ -285,47 +327,98 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
        return 0;
 }
 
+static void fill_descriptor(struct bcm43xx_dmaring *ring,
+                           struct bcm43xx_dmadesc_generic *desc,
+                           dma_addr_t dmaaddr,
+                           u16 bufsize,
+                           int start, int end, int irq)
+{
+       int slot;
+
+       slot = bcm43xx_dma_desc2idx(ring, desc);
+       assert(slot >= 0 && slot < ring->nr_slots);
+
+       if (ring->dma64) {
+               u32 ctl0 = 0, ctl1 = 0;
+               u32 addrlo, addrhi;
+               u32 addrext;
+
+               addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
+               addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING);
+               addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+               addrhi |= ring->routing;
+               if (slot == ring->nr_slots - 1)
+                       ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND;
+               if (start)
+                       ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART;
+               if (end)
+                       ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND;
+               if (irq)
+                       ctl0 |= BCM43xx_DMA64_DCTL0_IRQ;
+               ctl1 |= (bufsize - ring->frameoffset)
+                       & BCM43xx_DMA64_DCTL1_BYTECNT;
+               ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT)
+                       & BCM43xx_DMA64_DCTL1_ADDREXT_MASK;
+
+               desc->dma64.control0 = cpu_to_le32(ctl0);
+               desc->dma64.control1 = cpu_to_le32(ctl1);
+               desc->dma64.address_low = cpu_to_le32(addrlo);
+               desc->dma64.address_high = cpu_to_le32(addrhi);
+       } else {
+               u32 ctl;
+               u32 addr;
+               u32 addrext;
+
+               addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING);
+               addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING)
+                          >> BCM43xx_DMA32_ROUTING_SHIFT;
+               addr |= ring->routing;
+               ctl = (bufsize - ring->frameoffset)
+                     & BCM43xx_DMA32_DCTL_BYTECNT;
+               if (slot == ring->nr_slots - 1)
+                       ctl |= BCM43xx_DMA32_DCTL_DTABLEEND;
+               if (start)
+                       ctl |= BCM43xx_DMA32_DCTL_FRAMESTART;
+               if (end)
+                       ctl |= BCM43xx_DMA32_DCTL_FRAMEEND;
+               if (irq)
+                       ctl |= BCM43xx_DMA32_DCTL_IRQ;
+               ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT)
+                      & BCM43xx_DMA32_DCTL_ADDREXT_MASK;
+
+               desc->dma32.control = cpu_to_le32(ctl);
+               desc->dma32.address = cpu_to_le32(addr);
+       }
+}
+
 static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
-                              struct bcm43xx_dmadesc *desc,
+                              struct bcm43xx_dmadesc_generic *desc,
                               struct bcm43xx_dmadesc_meta *meta,
                               gfp_t gfp_flags)
 {
        struct bcm43xx_rxhdr *rxhdr;
+       struct bcm43xx_hwxmitstatus *xmitstat;
        dma_addr_t dmaaddr;
-       u32 desc_addr;
-       u32 desc_ctl;
-       const int slot = (int)(desc - ring->vbase);
        struct sk_buff *skb;
 
-       assert(slot >= 0 && slot < ring->nr_slots);
        assert(!ring->tx);
 
        skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
        if (unlikely(!skb))
                return -ENOMEM;
        dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
-       if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
-               unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
-               dev_kfree_skb_any(skb);
-               printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RX SKB >1G "
-                                   "(0x%llx, len: %u)\n",
-                       (unsigned long long)dmaaddr, ring->rx_buffersize);
-               return -ENOMEM;
-       }
        meta->skb = skb;
        meta->dmaaddr = dmaaddr;
        skb->dev = ring->bcm->net_dev;
-       desc_addr = (u32)(dmaaddr + ring->memoffset);
-       desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
-                   (u32)(ring->rx_buffersize - ring->frameoffset));
-       if (slot == ring->nr_slots - 1)
-               desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
-       set_desc_addr(desc, desc_addr);
-       set_desc_ctl(desc, desc_ctl);
+
+       fill_descriptor(ring, desc, dmaaddr,
+                       ring->rx_buffersize, 0, 0, 0);
 
        rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
        rxhdr->frame_length = 0;
        rxhdr->flags1 = 0;
+       xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data);
+       xmitstat->cookie = 0;
 
        return 0;
 }
@@ -336,17 +429,17 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
 static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
 {
        int i, err = -ENOMEM;
-       struct bcm43xx_dmadesc *desc;
+       struct bcm43xx_dmadesc_generic *desc;
        struct bcm43xx_dmadesc_meta *meta;
 
        for (i = 0; i < ring->nr_slots; i++) {
-               desc = ring->vbase + i;
-               meta = ring->meta + i;
+               desc = bcm43xx_dma_idx2desc(ring, i, &meta);
 
                err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
                if (err)
                        goto err_unwind;
        }
+       mb();
        ring->used_slots = ring->nr_slots;
        err = 0;
 out:
@@ -354,8 +447,7 @@ out:
 
 err_unwind:
        for (i--; i >= 0; i--) {
-               desc = ring->vbase + i;
-               meta = ring->meta + i;
+               desc = bcm43xx_dma_idx2desc(ring, i, &meta);
 
                unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
                dev_kfree_skb(meta->skb);
@@ -371,27 +463,67 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
 {
        int err = 0;
        u32 value;
+       u32 addrext;
 
        if (ring->tx) {
-               /* Set Transmit Control register to "transmit enable" */
-               bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
-                                 BCM43xx_DMA_TXCTRL_ENABLE);
-               /* Set Transmit Descriptor ring address. */
-               bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING,
-                                 ring->dmabase + ring->memoffset);
+               if (ring->dma64) {
+                       u64 ringbase = (u64)(ring->dmabase);
+
+                       addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+                       value = BCM43xx_DMA64_TXENABLE;
+                       value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT)
+                               & BCM43xx_DMA64_TXADDREXT_MASK;
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO,
+                                       (ringbase & 0xFFFFFFFF));
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI,
+                                       ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+                                       | ring->routing);
+               } else {
+                       u32 ringbase = (u32)(ring->dmabase);
+
+                       addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+                       value = BCM43xx_DMA32_TXENABLE;
+                       value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT)
+                               & BCM43xx_DMA32_TXADDREXT_MASK;
+                       bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING,
+                                       (ringbase & ~BCM43xx_DMA32_ROUTING)
+                                       | ring->routing);
+               }
        } else {
                err = alloc_initial_descbuffers(ring);
                if (err)
                        goto out;
-               /* Set Receive Control "receive enable" and frame offset */
-               value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
-               value |= BCM43xx_DMA_RXCTRL_ENABLE;
-               bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value);
-               /* Set Receive Descriptor ring address. */
-               bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING,
-                                 ring->dmabase + ring->memoffset);
-               /* Init the descriptor pointer. */
-               bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200);
+               if (ring->dma64) {
+                       u64 ringbase = (u64)(ring->dmabase);
+
+                       addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+                       value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT);
+                       value |= BCM43xx_DMA64_RXENABLE;
+                       value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT)
+                               & BCM43xx_DMA64_RXADDREXT_MASK;
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO,
+                                       (ringbase & 0xFFFFFFFF));
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI,
+                                       ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+                                       | ring->routing);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200);
+               } else {
+                       u32 ringbase = (u32)(ring->dmabase);
+
+                       addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+                       value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT);
+                       value |= BCM43xx_DMA32_RXENABLE;
+                       value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT)
+                               & BCM43xx_DMA32_RXADDREXT_MASK;
+                       bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING,
+                                       (ringbase & ~BCM43xx_DMA32_ROUTING)
+                                       | ring->routing);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200);
+               }
        }
 
 out:
@@ -402,27 +534,32 @@ out:
 static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
 {
        if (ring->tx) {
-               bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
-               /* Zero out Transmit Descriptor ring address. */
-               bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0);
+               bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+               if (ring->dma64) {
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0);
+               } else
+                       bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0);
        } else {
-               bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
-               /* Zero out Receive Descriptor ring address. */
-               bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0);
+               bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+               if (ring->dma64) {
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0);
+                       bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0);
+               } else
+                       bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0);
        }
 }
 
 static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
 {
-       struct bcm43xx_dmadesc *desc;
+       struct bcm43xx_dmadesc_generic *desc;
        struct bcm43xx_dmadesc_meta *meta;
        int i;
 
        if (!ring->used_slots)
                return;
        for (i = 0; i < ring->nr_slots; i++) {
-               desc = ring->vbase + i;
-               meta = ring->meta + i;
+               desc = bcm43xx_dma_idx2desc(ring, i, &meta);
 
                if (!meta->skb) {
                        assert(ring->tx);
@@ -430,62 +567,67 @@ static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
                }
                if (ring->tx) {
                        unmap_descbuffer(ring, meta->dmaaddr,
-                                        meta->skb->len, 1);
+                                       meta->skb->len, 1);
                } else {
                        unmap_descbuffer(ring, meta->dmaaddr,
-                                        ring->rx_buffersize, 0);
+                                       ring->rx_buffersize, 0);
                }
-               free_descriptor_buffer(ring, desc, meta, 0);
+               free_descriptor_buffer(ring, meta, 0);
        }
 }
 
 /* Main initialization function. */
 static
 struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
-                                              u16 dma_controller_base,
-                                              int nr_descriptor_slots,
-                                              int tx)
+                                              int controller_index,
+                                              int for_tx,
+                                              int dma64)
 {
        struct bcm43xx_dmaring *ring;
        int err;
+       int nr_slots;
 
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
        if (!ring)
                goto out;
 
-       ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
+       nr_slots = BCM43xx_RXRING_SLOTS;
+       if (for_tx)
+               nr_slots = BCM43xx_TXRING_SLOTS;
+
+       ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta),
                             GFP_KERNEL);
        if (!ring->meta)
                goto err_kfree_ring;
 
-       ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
+       ring->routing = BCM43xx_DMA32_CLIENTTRANS;
+       if (dma64)
+               ring->routing = BCM43xx_DMA64_CLIENTTRANS;
 #ifdef CONFIG_BCM947XX
        if (bcm->pci_dev->bus->number == 0)
-               ring->memoffset = 0;
+               ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
 #endif
 
        ring->bcm = bcm;
-       ring->nr_slots = nr_descriptor_slots;
+       ring->nr_slots = nr_slots;
        ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
        ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
        assert(ring->suspend_mark < ring->resume_mark);
-       ring->mmio_base = dma_controller_base;
-       if (tx) {
+       ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index);
+       ring->index = controller_index;
+       ring->dma64 = !!dma64;
+       if (for_tx) {
                ring->tx = 1;
                ring->current_slot = -1;
        } else {
-               switch (dma_controller_base) {
-               case BCM43xx_MMIO_DMA1_BASE:
-                       ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
-                       ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
-                       break;
-               case BCM43xx_MMIO_DMA4_BASE:
-                       ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
-                       ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
-                       break;
-               default:
+               if (ring->index == 0) {
+                       ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE;
+                       ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET;
+               } else if (ring->index == 3) {
+                       ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE;
+                       ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET;
+               } else
                        assert(0);
-               }
        }
 
        err = alloc_ringmemory(ring);
@@ -514,7 +656,8 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
        if (!ring)
                return;
 
-       dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
+       dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
+               (ring->dma64) ? "64" : "32",
                ring->mmio_base,
                (ring->tx) ? "TX" : "RX",
                ring->max_used_slots, ring->nr_slots);
@@ -537,10 +680,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm)
                return;
        dma = bcm43xx_current_dma(bcm);
 
-       bcm43xx_destroy_dmaring(dma->rx_ring1);
-       dma->rx_ring1 = NULL;
+       bcm43xx_destroy_dmaring(dma->rx_ring3);
+       dma->rx_ring3 = NULL;
        bcm43xx_destroy_dmaring(dma->rx_ring0);
        dma->rx_ring0 = NULL;
+
+       bcm43xx_destroy_dmaring(dma->tx_ring5);
+       dma->tx_ring5 = NULL;
+       bcm43xx_destroy_dmaring(dma->tx_ring4);
+       dma->tx_ring4 = NULL;
        bcm43xx_destroy_dmaring(dma->tx_ring3);
        dma->tx_ring3 = NULL;
        bcm43xx_destroy_dmaring(dma->tx_ring2);
@@ -556,48 +704,59 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
        struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
        struct bcm43xx_dmaring *ring;
        int err = -ENOMEM;
+       int dma64 = 0;
+       u32 sbtmstatehi;
+
+       sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+       if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT)
+               dma64 = 1;
 
        /* setup TX DMA channels. */
-       ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
-                                    BCM43xx_TXRING_SLOTS, 1);
+       ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
        if (!ring)
                goto out;
        dma->tx_ring0 = ring;
 
-       ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
-                                    BCM43xx_TXRING_SLOTS, 1);
+       ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64);
        if (!ring)
                goto err_destroy_tx0;
        dma->tx_ring1 = ring;
 
-       ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
-                                    BCM43xx_TXRING_SLOTS, 1);
+       ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64);
        if (!ring)
                goto err_destroy_tx1;
        dma->tx_ring2 = ring;
 
-       ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
-                                    BCM43xx_TXRING_SLOTS, 1);
+       ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64);
        if (!ring)
                goto err_destroy_tx2;
        dma->tx_ring3 = ring;
 
-       /* setup RX DMA channels. */
-       ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
-                                    BCM43xx_RXRING_SLOTS, 0);
+       ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64);
        if (!ring)
                goto err_destroy_tx3;
+       dma->tx_ring4 = ring;
+
+       ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64);
+       if (!ring)
+               goto err_destroy_tx4;
+       dma->tx_ring5 = ring;
+
+       /* setup RX DMA channels. */
+       ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64);
+       if (!ring)
+               goto err_destroy_tx5;
        dma->rx_ring0 = ring;
 
        if (bcm->current_core->rev < 5) {
-               ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
-                                            BCM43xx_RXRING_SLOTS, 0);
+               ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
                if (!ring)
                        goto err_destroy_rx0;
-               dma->rx_ring1 = ring;
+               dma->rx_ring3 = ring;
        }
 
-       dprintk(KERN_INFO PFX "DMA initialized\n");
+       dprintk(KERN_INFO PFX "%s DMA initialized\n",
+                       dma64 ? "64-bit" : "32-bit");
        err = 0;
 out:
        return err;
@@ -605,6 +764,12 @@ out:
 err_destroy_rx0:
        bcm43xx_destroy_dmaring(dma->rx_ring0);
        dma->rx_ring0 = NULL;
+err_destroy_tx5:
+       bcm43xx_destroy_dmaring(dma->tx_ring5);
+       dma->tx_ring5 = NULL;
+err_destroy_tx4:
+       bcm43xx_destroy_dmaring(dma->tx_ring4);
+       dma->tx_ring4 = NULL;
 err_destroy_tx3:
        bcm43xx_destroy_dmaring(dma->tx_ring3);
        dma->tx_ring3 = NULL;
@@ -624,7 +789,7 @@ err_destroy_tx0:
 static u16 generate_cookie(struct bcm43xx_dmaring *ring,
                           int slot)
 {
-       u16 cookie = 0xF000;
+       u16 cookie = 0x1000;
 
        /* Use the upper 4 bits of the cookie as
         * DMA controller ID and store the slot number
@@ -632,21 +797,25 @@ static u16 generate_cookie(struct bcm43xx_dmaring *ring,
         * Note that the cookie must never be 0, as this
         * is a special value used in RX path.
         */
-       switch (ring->mmio_base) {
-       default:
-               assert(0);
-       case BCM43xx_MMIO_DMA1_BASE:
+       switch (ring->index) {
+       case 0:
                cookie = 0xA000;
                break;
-       case BCM43xx_MMIO_DMA2_BASE:
+       case 1:
                cookie = 0xB000;
                break;
-       case BCM43xx_MMIO_DMA3_BASE:
+       case 2:
                cookie = 0xC000;
                break;
-       case BCM43xx_MMIO_DMA4_BASE:
+       case 3:
                cookie = 0xD000;
                break;
+       case 4:
+               cookie = 0xE000;
+               break;
+       case 5:
+               cookie = 0xF000;
+               break;
        }
        assert(((u16)slot & 0xF000) == 0x0000);
        cookie |= (u16)slot;
@@ -675,6 +844,12 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
        case 0xD000:
                ring = dma->tx_ring3;
                break;
+       case 0xE000:
+               ring = dma->tx_ring4;
+               break;
+       case 0xF000:
+               ring = dma->tx_ring5;
+               break;
        default:
                assert(0);
        }
@@ -687,6 +862,9 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
 static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
                                  int slot)
 {
+       u16 offset;
+       int descsize;
+
        /* Everything is ready to start. Buffers are DMA mapped and
         * associated with slots.
         * "slot" is the last slot of the new frame we want to transmit.
@@ -694,25 +872,26 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
         */
        wmb();
        slot = next_slot(ring, slot);
-       bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX,
-                         (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+       offset = (ring->dma64) ? BCM43xx_DMA64_TXINDEX : BCM43xx_DMA32_TXINDEX;
+       descsize = (ring->dma64) ? sizeof(struct bcm43xx_dmadesc64)
+               : sizeof(struct bcm43xx_dmadesc32);
+       bcm43xx_dma_write(ring, offset,
+                       (u32)(slot * descsize));
 }
 
-static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
-                          struct sk_buff *skb,
-                          u8 cur_frag)
+static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
+                           struct sk_buff *skb,
+                           u8 cur_frag)
 {
        int slot;
-       struct bcm43xx_dmadesc *desc;
+       struct bcm43xx_dmadesc_generic *desc;
        struct bcm43xx_dmadesc_meta *meta;
-       u32 desc_ctl;
-       u32 desc_addr;
+       dma_addr_t dmaaddr;
 
        assert(skb_shinfo(skb)->nr_frags == 0);
 
        slot = request_slot(ring);
-       desc = ring->vbase + slot;
-       meta = ring->meta + slot;
+       desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
 
        /* Add a device specific TX header. */
        assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
@@ -729,29 +908,14 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
                               generate_cookie(ring, slot));
 
        meta->skb = skb;
-       meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
-       if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
-               return_slot(ring, slot);
-               printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA TX SKB >1G "
-                                   "(0x%llx, len: %u)\n",
-                       (unsigned long long)meta->dmaaddr, skb->len);
-               return -ENOMEM;
-       }
+       dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+       meta->dmaaddr = dmaaddr;
 
-       desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
-       desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
-       desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
-       desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
-                    (u32)(meta->skb->len - ring->frameoffset));
-       if (slot == ring->nr_slots - 1)
-               desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+       fill_descriptor(ring, desc, dmaaddr,
+                       skb->len, 1, 1, 1);
 
-       set_desc_ctl(desc, desc_ctl);
-       set_desc_addr(desc, desc_addr);
        /* Now transfer the whole frame. */
        dmacontroller_poke_tx(ring, slot);
-
-       return 0;
 }
 
 int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
@@ -781,7 +945,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
                /* Take skb from ieee80211_txb_free */
                txb->fragments[i] = NULL;
                dma_tx_fragment(ring, skb, i);
-               //TODO: handle failure of dma_tx_fragment
        }
        ieee80211_txb_free(txb);
 
@@ -792,23 +955,28 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
                                   struct bcm43xx_xmitstatus *status)
 {
        struct bcm43xx_dmaring *ring;
-       struct bcm43xx_dmadesc *desc;
+       struct bcm43xx_dmadesc_generic *desc;
        struct bcm43xx_dmadesc_meta *meta;
        int is_last_fragment;
        int slot;
+       u32 tmp;
 
        ring = parse_cookie(bcm, status->cookie, &slot);
        assert(ring);
        assert(ring->tx);
-       assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
        while (1) {
                assert(slot >= 0 && slot < ring->nr_slots);
-               desc = ring->vbase + slot;
-               meta = ring->meta + slot;
+               desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
 
-               is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
+               if (ring->dma64) {
+                       tmp = le32_to_cpu(desc->dma64.control0);
+                       is_last_fragment = !!(tmp & BCM43xx_DMA64_DCTL0_FRAMEEND);
+               } else {
+                       tmp = le32_to_cpu(desc->dma32.control);
+                       is_last_fragment = !!(tmp & BCM43xx_DMA32_DCTL_FRAMEEND);
+               }
                unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
-               free_descriptor_buffer(ring, desc, meta, 1);
+               free_descriptor_buffer(ring, meta, 1);
                /* Everything belonging to the slot is unmapped
                 * and freed, so we can return it.
                 */
@@ -824,7 +992,7 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
 static void dma_rx(struct bcm43xx_dmaring *ring,
                   int *slot)
 {
-       struct bcm43xx_dmadesc *desc;
+       struct bcm43xx_dmadesc_generic *desc;
        struct bcm43xx_dmadesc_meta *meta;
        struct bcm43xx_rxhdr *rxhdr;
        struct sk_buff *skb;
@@ -832,13 +1000,12 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
        int err;
        dma_addr_t dmaaddr;
 
-       desc = ring->vbase + *slot;
-       meta = ring->meta + *slot;
+       desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
 
        sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
        skb = meta->skb;
 
-       if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
+       if (ring->index == 3) {
                /* We received an xmit status. */
                struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
                struct bcm43xx_xmitstatus stat;
@@ -894,8 +1061,7 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
                s32 tmp = len;
 
                while (1) {
-                       desc = ring->vbase + *slot;
-                       meta = ring->meta + *slot;
+                       desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
                        /* recycle the descriptor buffer. */
                        sync_descbuffer_for_device(ring, meta->dmaaddr,
                                                   ring->rx_buffersize);
@@ -906,8 +1072,8 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
                                break;
                }
                printkl(KERN_ERR PFX "DMA RX buffer too small "
-                                    "(len: %u, buffer: %u, nr-dropped: %d)\n",
-                       len, ring->rx_buffersize, cnt);
+                       "(len: %u, buffer: %u, nr-dropped: %d)\n",
+                       len, ring->rx_buffersize, cnt);
                goto drop;
        }
        len -= IEEE80211_FCS_LEN;
@@ -945,9 +1111,15 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
 #endif
 
        assert(!ring->tx);
-       status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS);
-       descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
-       current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
+       if (ring->dma64) {
+               status = bcm43xx_dma_read(ring, BCM43xx_DMA64_RXSTATUS);
+               descptr = (status & BCM43xx_DMA64_RXSTATDPTR);
+               current_slot = descptr / sizeof(struct bcm43xx_dmadesc64);
+       } else {
+               status = bcm43xx_dma_read(ring, BCM43xx_DMA32_RXSTATUS);
+               descptr = (status & BCM43xx_DMA32_RXDPTR);
+               current_slot = descptr / sizeof(struct bcm43xx_dmadesc32);
+       }
        assert(current_slot >= 0 && current_slot < ring->nr_slots);
 
        slot = ring->current_slot;
@@ -958,8 +1130,13 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
                        ring->max_used_slots = used_slots;
 #endif
        }
-       bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX,
-                         (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+       if (ring->dma64) {
+               bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX,
+                               (u32)(slot * sizeof(struct bcm43xx_dmadesc64)));
+       } else {
+               bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX,
+                               (u32)(slot * sizeof(struct bcm43xx_dmadesc32)));
+       }
        ring->current_slot = slot;
 }
 
@@ -967,16 +1144,28 @@ void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
 {
        assert(ring->tx);
        bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
-       bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
-                         bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
-                         | BCM43xx_DMA_TXCTRL_SUSPEND);
+       if (ring->dma64) {
+               bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
+                               bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
+                               | BCM43xx_DMA64_TXSUSPEND);
+       } else {
+               bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
+                               bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
+                               | BCM43xx_DMA32_TXSUSPEND);
+       }
 }
 
 void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
 {
        assert(ring->tx);
-       bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
-                         bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
-                         & ~BCM43xx_DMA_TXCTRL_SUSPEND);
+       if (ring->dma64) {
+               bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
+                               bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
+                               & ~BCM43xx_DMA64_TXSUSPEND);
+       } else {
+               bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
+                               bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
+                               & ~BCM43xx_DMA32_TXSUSPEND);
+       }
        bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
 }
index b7d77638ba8c53877e1837c6456d9de998e6f9c8..e04bcaddd1d004d1b514a39bf047f11a963e1bbf 100644 (file)
 #define BCM43xx_DMAIRQ_NONFATALMASK    (1 << 13)
 #define BCM43xx_DMAIRQ_RX_DONE         (1 << 16)
 
-/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
-#define BCM43xx_DMA_TX_CONTROL         0x00
-#define BCM43xx_DMA_TX_DESC_RING       0x04
-#define BCM43xx_DMA_TX_DESC_INDEX      0x08
-#define BCM43xx_DMA_TX_STATUS          0x0c
-#define BCM43xx_DMA_RX_CONTROL         0x10
-#define BCM43xx_DMA_RX_DESC_RING       0x14
-#define BCM43xx_DMA_RX_DESC_INDEX      0x18
-#define BCM43xx_DMA_RX_STATUS          0x1c
-
-/* DMA controller channel control word values. */
-#define BCM43xx_DMA_TXCTRL_ENABLE              (1 << 0)
-#define BCM43xx_DMA_TXCTRL_SUSPEND             (1 << 1)
-#define BCM43xx_DMA_TXCTRL_LOOPBACK            (1 << 2)
-#define BCM43xx_DMA_TXCTRL_FLUSH               (1 << 4)
-#define BCM43xx_DMA_RXCTRL_ENABLE              (1 << 0)
-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK       0x000000fe
-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT      1
-#define BCM43xx_DMA_RXCTRL_PIO                 (1 << 8)
-/* DMA controller channel status word values. */
-#define BCM43xx_DMA_TXSTAT_DPTR_MASK           0x00000fff
-#define BCM43xx_DMA_TXSTAT_STAT_MASK           0x0000f000
-#define BCM43xx_DMA_TXSTAT_STAT_DISABLED       0x00000000
-#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE         0x00001000
-#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT       0x00002000
-#define BCM43xx_DMA_TXSTAT_STAT_STOPPED                0x00003000
-#define BCM43xx_DMA_TXSTAT_STAT_SUSP           0x00004000
-#define BCM43xx_DMA_TXSTAT_ERROR_MASK          0x000f0000
-#define BCM43xx_DMA_TXSTAT_FLUSHED             (1 << 20)
-#define BCM43xx_DMA_RXSTAT_DPTR_MASK           0x00000fff
-#define BCM43xx_DMA_RXSTAT_STAT_MASK           0x0000f000
-#define BCM43xx_DMA_RXSTAT_STAT_DISABLED       0x00000000
-#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE         0x00001000
-#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT       0x00002000
-#define BCM43xx_DMA_RXSTAT_STAT_RESERVED       0x00003000
-#define BCM43xx_DMA_RXSTAT_STAT_ERRORS         0x00004000
-#define BCM43xx_DMA_RXSTAT_ERROR_MASK          0x000f0000
-
-/* DMA descriptor control field values. */
-#define BCM43xx_DMADTOR_BYTECNT_MASK           0x00001fff
-#define BCM43xx_DMADTOR_DTABLEEND              (1 << 28) /* End of descriptor table */
-#define BCM43xx_DMADTOR_COMPIRQ                        (1 << 29) /* IRQ on completion request */
-#define BCM43xx_DMADTOR_FRAMEEND               (1 << 30)
-#define BCM43xx_DMADTOR_FRAMESTART             (1 << 31)
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define BCM43xx_DMA32_TXCTL                            0x00
+#define                BCM43xx_DMA32_TXENABLE                  0x00000001
+#define                BCM43xx_DMA32_TXSUSPEND                 0x00000002
+#define                BCM43xx_DMA32_TXLOOPBACK                0x00000004
+#define                BCM43xx_DMA32_TXFLUSH                   0x00000010
+#define                BCM43xx_DMA32_TXADDREXT_MASK            0x00030000
+#define                BCM43xx_DMA32_TXADDREXT_SHIFT           16
+#define BCM43xx_DMA32_TXRING                           0x04
+#define BCM43xx_DMA32_TXINDEX                          0x08
+#define BCM43xx_DMA32_TXSTATUS                         0x0C
+#define                BCM43xx_DMA32_TXDPTR                    0x00000FFF
+#define                BCM43xx_DMA32_TXSTATE                   0x0000F000
+#define                        BCM43xx_DMA32_TXSTAT_DISABLED   0x00000000
+#define                        BCM43xx_DMA32_TXSTAT_ACTIVE     0x00001000
+#define                        BCM43xx_DMA32_TXSTAT_IDLEWAIT   0x00002000
+#define                        BCM43xx_DMA32_TXSTAT_STOPPED    0x00003000
+#define                        BCM43xx_DMA32_TXSTAT_SUSP       0x00004000
+#define                BCM43xx_DMA32_TXERROR                   0x000F0000
+#define                        BCM43xx_DMA32_TXERR_NOERR       0x00000000
+#define                        BCM43xx_DMA32_TXERR_PROT        0x00010000
+#define                        BCM43xx_DMA32_TXERR_UNDERRUN    0x00020000
+#define                        BCM43xx_DMA32_TXERR_BUFREAD     0x00030000
+#define                        BCM43xx_DMA32_TXERR_DESCREAD    0x00040000
+#define                BCM43xx_DMA32_TXACTIVE                  0xFFF00000
+#define BCM43xx_DMA32_RXCTL                            0x10
+#define                BCM43xx_DMA32_RXENABLE                  0x00000001
+#define                BCM43xx_DMA32_RXFROFF_MASK              0x000000FE
+#define                BCM43xx_DMA32_RXFROFF_SHIFT             1
+#define                BCM43xx_DMA32_RXDIRECTFIFO              0x00000100
+#define                BCM43xx_DMA32_RXADDREXT_MASK            0x00030000
+#define                BCM43xx_DMA32_RXADDREXT_SHIFT           16
+#define BCM43xx_DMA32_RXRING                           0x14
+#define BCM43xx_DMA32_RXINDEX                          0x18
+#define BCM43xx_DMA32_RXSTATUS                         0x1C
+#define                BCM43xx_DMA32_RXDPTR                    0x00000FFF
+#define                BCM43xx_DMA32_RXSTATE                   0x0000F000
+#define                        BCM43xx_DMA32_RXSTAT_DISABLED   0x00000000
+#define                        BCM43xx_DMA32_RXSTAT_ACTIVE     0x00001000
+#define                        BCM43xx_DMA32_RXSTAT_IDLEWAIT   0x00002000
+#define                        BCM43xx_DMA32_RXSTAT_STOPPED    0x00003000
+#define                BCM43xx_DMA32_RXERROR                   0x000F0000
+#define                        BCM43xx_DMA32_RXERR_NOERR       0x00000000
+#define                        BCM43xx_DMA32_RXERR_PROT        0x00010000
+#define                        BCM43xx_DMA32_RXERR_OVERFLOW    0x00020000
+#define                        BCM43xx_DMA32_RXERR_BUFWRITE    0x00030000
+#define                        BCM43xx_DMA32_RXERR_DESCREAD    0x00040000
+#define                BCM43xx_DMA32_RXACTIVE                  0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct bcm43xx_dmadesc32 {
+       __le32 control;
+       __le32 address;
+} __attribute__((__packed__));
+#define BCM43xx_DMA32_DCTL_BYTECNT             0x00001FFF
+#define BCM43xx_DMA32_DCTL_ADDREXT_MASK                0x00030000
+#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT       16
+#define BCM43xx_DMA32_DCTL_DTABLEEND           0x10000000
+#define BCM43xx_DMA32_DCTL_IRQ                 0x20000000
+#define BCM43xx_DMA32_DCTL_FRAMEEND            0x40000000
+#define BCM43xx_DMA32_DCTL_FRAMESTART          0x80000000
+
+/* Address field Routing value. */
+#define BCM43xx_DMA32_ROUTING                  0xC0000000
+#define BCM43xx_DMA32_ROUTING_SHIFT            30
+#define                BCM43xx_DMA32_NOTRANS           0x00000000
+#define                BCM43xx_DMA32_CLIENTTRANS       0x40000000
+
+
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define BCM43xx_DMA64_TXCTL                            0x00
+#define                BCM43xx_DMA64_TXENABLE                  0x00000001
+#define                BCM43xx_DMA64_TXSUSPEND                 0x00000002
+#define                BCM43xx_DMA64_TXLOOPBACK                0x00000004
+#define                BCM43xx_DMA64_TXFLUSH                   0x00000010
+#define                BCM43xx_DMA64_TXADDREXT_MASK            0x00030000
+#define                BCM43xx_DMA64_TXADDREXT_SHIFT           16
+#define BCM43xx_DMA64_TXINDEX                          0x04
+#define BCM43xx_DMA64_TXRINGLO                         0x08
+#define BCM43xx_DMA64_TXRINGHI                         0x0C
+#define BCM43xx_DMA64_TXSTATUS                         0x10
+#define                BCM43xx_DMA64_TXSTATDPTR                0x00001FFF
+#define                BCM43xx_DMA64_TXSTAT                    0xF0000000
+#define                        BCM43xx_DMA64_TXSTAT_DISABLED   0x00000000
+#define                        BCM43xx_DMA64_TXSTAT_ACTIVE     0x10000000
+#define                        BCM43xx_DMA64_TXSTAT_IDLEWAIT   0x20000000
+#define                        BCM43xx_DMA64_TXSTAT_STOPPED    0x30000000
+#define                        BCM43xx_DMA64_TXSTAT_SUSP       0x40000000
+#define BCM43xx_DMA64_TXERROR                          0x14
+#define                BCM43xx_DMA64_TXERRDPTR                 0x0001FFFF
+#define                BCM43xx_DMA64_TXERR                     0xF0000000
+#define                        BCM43xx_DMA64_TXERR_NOERR       0x00000000
+#define                        BCM43xx_DMA64_TXERR_PROT        0x10000000
+#define                        BCM43xx_DMA64_TXERR_UNDERRUN    0x20000000
+#define                        BCM43xx_DMA64_TXERR_TRANSFER    0x30000000
+#define                        BCM43xx_DMA64_TXERR_DESCREAD    0x40000000
+#define                        BCM43xx_DMA64_TXERR_CORE        0x50000000
+#define BCM43xx_DMA64_RXCTL                            0x20
+#define                BCM43xx_DMA64_RXENABLE                  0x00000001
+#define                BCM43xx_DMA64_RXFROFF_MASK              0x000000FE
+#define                BCM43xx_DMA64_RXFROFF_SHIFT             1
+#define                BCM43xx_DMA64_RXDIRECTFIFO              0x00000100
+#define                BCM43xx_DMA64_RXADDREXT_MASK            0x00030000
+#define                BCM43xx_DMA64_RXADDREXT_SHIFT           16
+#define BCM43xx_DMA64_RXINDEX                          0x24
+#define BCM43xx_DMA64_RXRINGLO                         0x28
+#define BCM43xx_DMA64_RXRINGHI                         0x2C
+#define BCM43xx_DMA64_RXSTATUS                         0x30
+#define                BCM43xx_DMA64_RXSTATDPTR                0x00001FFF
+#define                BCM43xx_DMA64_RXSTAT                    0xF0000000
+#define                        BCM43xx_DMA64_RXSTAT_DISABLED   0x00000000
+#define                        BCM43xx_DMA64_RXSTAT_ACTIVE     0x10000000
+#define                        BCM43xx_DMA64_RXSTAT_IDLEWAIT   0x20000000
+#define                        BCM43xx_DMA64_RXSTAT_STOPPED    0x30000000
+#define                        BCM43xx_DMA64_RXSTAT_SUSP       0x40000000
+#define BCM43xx_DMA64_RXERROR                          0x34
+#define                BCM43xx_DMA64_RXERRDPTR                 0x0001FFFF
+#define                BCM43xx_DMA64_RXERR                     0xF0000000
+#define                        BCM43xx_DMA64_RXERR_NOERR       0x00000000
+#define                        BCM43xx_DMA64_RXERR_PROT        0x10000000
+#define                        BCM43xx_DMA64_RXERR_UNDERRUN    0x20000000
+#define                        BCM43xx_DMA64_RXERR_TRANSFER    0x30000000
+#define                        BCM43xx_DMA64_RXERR_DESCREAD    0x40000000
+#define                        BCM43xx_DMA64_RXERR_CORE        0x50000000
+
+/* 64-bit DMA descriptor. */
+struct bcm43xx_dmadesc64 {
+       __le32 control0;
+       __le32 control1;
+       __le32 address_low;
+       __le32 address_high;
+} __attribute__((__packed__));
+#define BCM43xx_DMA64_DCTL0_DTABLEEND          0x10000000
+#define BCM43xx_DMA64_DCTL0_IRQ                        0x20000000
+#define BCM43xx_DMA64_DCTL0_FRAMEEND           0x40000000
+#define BCM43xx_DMA64_DCTL0_FRAMESTART         0x80000000
+#define BCM43xx_DMA64_DCTL1_BYTECNT            0x00001FFF
+#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK       0x00030000
+#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT      16
+
+/* Address field Routing value. */
+#define BCM43xx_DMA64_ROUTING                  0xC0000000
+#define BCM43xx_DMA64_ROUTING_SHIFT            30
+#define                BCM43xx_DMA64_NOTRANS           0x00000000
+#define                BCM43xx_DMA64_CLIENTTRANS       0x80000000
+
+
+
+struct bcm43xx_dmadesc_generic {
+       union {
+               struct bcm43xx_dmadesc32 dma32;
+               struct bcm43xx_dmadesc64 dma64;
+       } __attribute__((__packed__));
+} __attribute__((__packed__));
+
 
 /* Misc DMA constants */
 #define BCM43xx_DMA_RINGMEMSIZE                PAGE_SIZE
-#define BCM43xx_DMA_BUSADDRMAX         0x3FFFFFFF
-#define BCM43xx_DMA_DMABUSADDROFFSET   (1 << 30)
-#define BCM43xx_DMA1_RX_FRAMEOFFSET    30
-#define BCM43xx_DMA4_RX_FRAMEOFFSET    0
+#define BCM43xx_DMA0_RX_FRAMEOFFSET    30
+#define BCM43xx_DMA3_RX_FRAMEOFFSET    0
+
 
 /* DMA engine tuning knobs */
 #define BCM43xx_TXRING_SLOTS           512
 #define BCM43xx_RXRING_SLOTS           64
-#define BCM43xx_DMA1_RXBUFFERSIZE      (2304 + 100)
-#define BCM43xx_DMA4_RXBUFFERSIZE      16
+#define BCM43xx_DMA0_RX_BUFFERSIZE     (2304 + 100)
+#define BCM43xx_DMA3_RX_BUFFERSIZE     16
 /* Suspend the tx queue, if less than this percent slots are free. */
 #define BCM43xx_TXSUSPEND_PERCENT      20
 /* Resume the tx queue, if more than this percent slots are free. */
@@ -86,17 +202,6 @@ struct bcm43xx_private;
 struct bcm43xx_xmitstatus;
 
 
-struct bcm43xx_dmadesc {
-       __le32 _control;
-       __le32 _address;
-} __attribute__((__packed__));
-
-/* Macros to access the bcm43xx_dmadesc struct */
-#define get_desc_ctl(desc)             le32_to_cpu((desc)->_control)
-#define set_desc_ctl(desc, ctl)                do { (desc)->_control = cpu_to_le32(ctl); } while (0)
-#define get_desc_addr(desc)            le32_to_cpu((desc)->_address)
-#define set_desc_addr(desc, addr)      do { (desc)->_address = cpu_to_le32(addr); } while (0)
-
 struct bcm43xx_dmadesc_meta {
        /* The kernel DMA-able buffer. */
        struct sk_buff *skb;
@@ -105,15 +210,14 @@ struct bcm43xx_dmadesc_meta {
 };
 
 struct bcm43xx_dmaring {
-       struct bcm43xx_private *bcm;
        /* Kernel virtual base address of the ring memory. */
-       struct bcm43xx_dmadesc *vbase;
-       /* DMA memory offset */
-       dma_addr_t memoffset;
-       /* (Unadjusted) DMA base bus-address of the ring memory. */
-       dma_addr_t dmabase;
+       void *descbase;
        /* Meta data about all descriptors. */
        struct bcm43xx_dmadesc_meta *meta;
+       /* DMA Routing value. */
+       u32 routing;
+       /* (Unadjusted) DMA base bus-address of the ring memory. */
+       dma_addr_t dmabase;
        /* Number of descriptor slots in the ring. */
        int nr_slots;
        /* Number of used descriptor slots. */
@@ -127,12 +231,17 @@ struct bcm43xx_dmaring {
        u32 frameoffset;
        /* Descriptor buffer size. */
        u16 rx_buffersize;
-       /* The MMIO base register of the DMA controller, this
-        * ring is posted to.
-        */
+       /* The MMIO base register of the DMA controller. */
        u16 mmio_base;
-       u8 tx:1,        /* TRUE, if this is a TX ring. */
-          suspended:1; /* TRUE, if transfers are suspended on this ring. */
+       /* DMA controller index number (0-5). */
+       int index;
+       /* Boolean. Is this a TX ring? */
+       u8 tx;
+       /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+       u8 dma64;
+       /* Boolean. Are transfers suspended on this ring? */
+       u8 suspended;
+       struct bcm43xx_private *bcm;
 #ifdef CONFIG_BCM43XX_DEBUG
        /* Maximum number of used slots. */
        int max_used_slots;
@@ -140,6 +249,34 @@ struct bcm43xx_dmaring {
 };
 
 
+static inline
+int bcm43xx_dma_desc2idx(struct bcm43xx_dmaring *ring,
+                        struct bcm43xx_dmadesc_generic *desc)
+{
+       if (ring->dma64) {
+               struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
+               return (int)(&(desc->dma64) - dd64);
+       } else {
+               struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
+               return (int)(&(desc->dma32) - dd32);
+       }
+}
+
+static inline
+struct bcm43xx_dmadesc_generic * bcm43xx_dma_idx2desc(struct bcm43xx_dmaring *ring,
+                                                     int slot,
+                                                     struct bcm43xx_dmadesc_meta **meta)
+{
+       *meta = &(ring->meta[slot]);
+       if (ring->dma64) {
+               struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
+               return (struct bcm43xx_dmadesc_generic *)(&(dd64[slot]));
+       } else {
+               struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
+               return (struct bcm43xx_dmadesc_generic *)(&(dd32[slot]));
+       }
+}
+
 static inline
 u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
                     u16 offset)
@@ -159,9 +296,13 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm);
 void bcm43xx_dma_free(struct bcm43xx_private *bcm);
 
 int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
-                                  u16 dmacontroller_mmio_base);
+                                  u16 dmacontroller_mmio_base,
+                                  int dma64);
 int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
-                                  u16 dmacontroller_mmio_base);
+                                  u16 dmacontroller_mmio_base,
+                                  int dma64);
+
+u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
 
 void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
 void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
@@ -173,7 +314,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
                   struct ieee80211_txb *txb);
 void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
 
-
 #else /* CONFIG_BCM43XX_DMA */
 
 
@@ -188,13 +328,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm)
 }
 static inline
 int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
-                                  u16 dmacontroller_mmio_base)
+                                  u16 dmacontroller_mmio_base,
+                                  int dma64)
 {
        return 0;
 }
 static inline
 int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
-                                  u16 dmacontroller_mmio_base)
+                                  u16 dmacontroller_mmio_base,
+                                  int dma64)
 {
        return 0;
 }
index ec80692d638a45d7440cf83710eecad403847529..c3f90c8563d915ee4175afe6ca8cd6a4a41627fb 100644 (file)
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d)
        struct bcm43xx_private *bcm = led->bcm;
        unsigned long flags;
 
-       bcm43xx_lock_irqonly(bcm, flags);
+       spin_lock_irqsave(&bcm->leds_lock, flags);
        if (led->blink_interval) {
                bcm43xx_led_changestate(led);
                mod_timer(&led->blink_timer, jiffies + led->blink_interval);
        }
-       bcm43xx_unlock_irqonly(bcm, flags);
+       spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
 
 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
        int i, turn_on;
        unsigned long interval = 0;
        u16 ledctl;
+       unsigned long flags;
 
+       spin_lock_irqsave(&bcm->leds_lock, flags);
        ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
        for (i = 0; i < BCM43xx_NR_LEDS; i++) {
                led = &(bcm->leds[i]);
@@ -266,6 +268,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
                        ledctl &= ~(1 << i);
        }
        bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+       spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
 
 void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
@@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
        u16 ledctl;
        int i;
        int bit_on;
+       unsigned long flags;
 
+       spin_lock_irqsave(&bcm->leds_lock, flags);
        ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
        for (i = 0; i < BCM43xx_NR_LEDS; i++) {
                led = &(bcm->leds[i]);
@@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
                        ledctl &= ~(1 << i);
        }
        bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+       spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
index df317c1e12a89df16d84ce861ffac7d302cea8ad..966815be69557b4b610bf03bcca6d647c2d7fdd9 100644 (file)
@@ -509,23 +509,19 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
 }
 
 /* Make sure we don't receive more data from the device. */
-static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
+static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
 {
        unsigned long flags;
-       u32 old;
 
-       bcm43xx_lock_irqonly(bcm, flags);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
-               bcm43xx_unlock_irqonly(bcm, flags);
+               spin_unlock_irqrestore(&bcm->irq_lock, flags);
                return -EBUSY;
        }
-       old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-       bcm43xx_unlock_irqonly(bcm, flags);
+       bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
        bcm43xx_synchronize_irq(bcm);
 
-       if (oldstate)
-               *oldstate = old;
-
        return 0;
 }
 
@@ -537,7 +533,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
        u16 manufact;
        u16 version;
        u8 revision;
-       s8 i;
 
        if (bcm->chip_id == 0x4317) {
                if (bcm->chip_rev == 0x00)
@@ -580,20 +575,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
        radio->version = version;
        radio->revision = revision;
 
-       /* Set default attenuation values. */
-       radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
-       radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
-       radio->txctl1 = bcm43xx_default_txctl1(bcm);
-       radio->txctl2 = 0xFFFF;
        if (phy->type == BCM43xx_PHYTYPE_A)
                radio->txpower_desired = bcm->sprom.maxpower_aphy;
        else
                radio->txpower_desired = bcm->sprom.maxpower_bgphy;
 
-       /* Initialize the in-memory nrssi Lookup Table. */
-       for (i = 0; i < 64; i++)
-               radio->nrssi_lt[i] = i;
-
        return 0;
 
 err_unsupported_radio:
@@ -1250,10 +1236,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
                goto out;
 
        bcm->current_core = new_core;
-       bcm->current_80211_core_idx = -1;
-       if (new_core->id == BCM43xx_COREID_80211)
-               bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
-
 out:
        return err;
 }
@@ -1389,6 +1371,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
        if ((bcm43xx_core_enabled(bcm)) &&
            !bcm43xx_using_pio(bcm)) {
 //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
+#if 0
 #ifndef CONFIG_BCM947XX
                /* reset all used DMA controllers. */
                bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
@@ -1398,6 +1381,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
                bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
                if (bcm->current_core->rev < 5)
                        bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
+#endif
 #endif
        }
        if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
@@ -1423,43 +1407,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
        bcm43xx_core_disable(bcm, 0);
 }
 
-/* Mark the current 80211 core inactive.
- * "active_80211_core" is the other 80211 core, which is used.
- */
-static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
-                                              struct bcm43xx_coreinfo *active_80211_core)
+/* Mark the current 80211 core inactive. */
+static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
 {
        u32 sbtmstatelow;
-       struct bcm43xx_coreinfo *old_core;
-       int err = 0;
 
        bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
        bcm43xx_radio_turn_off(bcm);
        sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-       sbtmstatelow &= ~0x200a0000;
-       sbtmstatelow |= 0xa0000;
+       sbtmstatelow &= 0xDFF5FFFF;
+       sbtmstatelow |= 0x000A0000;
        bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
        udelay(1);
        sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-       sbtmstatelow &= ~0xa0000;
-       sbtmstatelow |= 0x80000;
+       sbtmstatelow &= 0xFFF5FFFF;
+       sbtmstatelow |= 0x00080000;
        bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
        udelay(1);
-
-       if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
-               old_core = bcm->current_core;
-               err = bcm43xx_switch_core(bcm, active_80211_core);
-               if (err)
-                       goto out;
-               sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-               sbtmstatelow &= ~0x20000000;
-               sbtmstatelow |= 0x20000000;
-               bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
-               err = bcm43xx_switch_core(bcm, old_core);
-       }
-
-out:
-       return err;
 }
 
 static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
@@ -1709,8 +1673,9 @@ static void handle_irq_beacon(struct bcm43xx_private *bcm)
 static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
 {
        u32 reason;
-       u32 dma_reason[4];
-       int activity = 0;
+       u32 dma_reason[6];
+       u32 merged_dma_reason = 0;
+       int i, activity = 0;
        unsigned long flags;
 
 #ifdef CONFIG_BCM43XX_DEBUG
@@ -1720,12 +1685,12 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
 # define bcmirq_handled(irq)   do { /* nothing */ } while (0)
 #endif /* CONFIG_BCM43XX_DEBUG*/
 
-       bcm43xx_lock_irqonly(bcm, flags);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        reason = bcm->irq_reason;
-       dma_reason[0] = bcm->dma_reason[0];
-       dma_reason[1] = bcm->dma_reason[1];
-       dma_reason[2] = bcm->dma_reason[2];
-       dma_reason[3] = bcm->dma_reason[3];
+       for (i = 5; i >= 0; i--) {
+               dma_reason[i] = bcm->dma_reason[i];
+               merged_dma_reason |= dma_reason[i];
+       }
 
        if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
                /* TX error. We get this when Template Ram is written in wrong endianess
@@ -1736,27 +1701,25 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
                printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
                bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
        }
-       if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
-                    (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
-                    (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
-                    (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
+       if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) {
                printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
-                                    "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+                                    "0x%08X, 0x%08X, 0x%08X, "
+                                    "0x%08X, 0x%08X, 0x%08X\n",
                        dma_reason[0], dma_reason[1],
-                       dma_reason[2], dma_reason[3]);
+                       dma_reason[2], dma_reason[3],
+                       dma_reason[4], dma_reason[5]);
                bcm43xx_controller_restart(bcm, "DMA error");
                mmiowb();
-               bcm43xx_unlock_irqonly(bcm, flags);
+               spin_unlock_irqrestore(&bcm->irq_lock, flags);
                return;
        }
-       if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
-                    (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
-                    (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
-                    (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
+       if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) {
                printkl(KERN_ERR PFX "DMA error: "
-                                    "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+                                    "0x%08X, 0x%08X, 0x%08X, "
+                                    "0x%08X, 0x%08X, 0x%08X\n",
                        dma_reason[0], dma_reason[1],
-                       dma_reason[2], dma_reason[3]);
+                       dma_reason[2], dma_reason[3],
+                       dma_reason[4], dma_reason[5]);
        }
 
        if (reason & BCM43xx_IRQ_PS) {
@@ -1791,8 +1754,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
        }
 
        /* Check the DMA reason registers for received data. */
-       assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
-       assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
        if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
                if (bcm43xx_using_pio(bcm))
                        bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
@@ -1800,13 +1761,17 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
                        bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
                /* We intentionally don't set "activity" to 1, here. */
        }
+       assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
+       assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
        if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
                if (bcm43xx_using_pio(bcm))
                        bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
                else
-                       bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
+                       bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3);
                activity = 1;
        }
+       assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE));
+       assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE));
        bcmirq_handled(BCM43xx_IRQ_RX);
 
        if (reason & BCM43xx_IRQ_XMIT_STATUS) {
@@ -1834,7 +1799,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
                bcm43xx_leds_update(bcm, activity);
        bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
        mmiowb();
-       bcm43xx_unlock_irqonly(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1863,14 +1828,18 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
 
        bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
 
-       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON,
                        bcm->dma_reason[0]);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
                        bcm->dma_reason[1]);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
                        bcm->dma_reason[2]);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
                        bcm->dma_reason[3]);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+                       bcm->dma_reason[4]);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON,
+                       bcm->dma_reason[5]);
 }
 
 /* Interrupt handler top-half */
@@ -1885,14 +1854,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
 
        spin_lock(&bcm->irq_lock);
 
-       /* Only accept IRQs, if we are initialized properly.
-        * This avoids an RX race while initializing.
-        * We should probably not enable IRQs before we are initialized
-        * completely, but some careful work is needed to fix this. I think it
-        * is best to stay with this cheap workaround for now... .
-        */
-       if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
-               goto out;
+       assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+       assert(bcm->current_core->id == BCM43xx_COREID_80211);
 
        reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
        if (reason == 0xffffffff) {
@@ -1904,14 +1867,18 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
        if (!reason)
                goto out;
 
-       bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
-                            & 0x0001dc00;
-       bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
-                            & 0x0000dc00;
-       bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
-                            & 0x0000dc00;
-       bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
-                            & 0x0001dc00;
+       bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)
+                            & 0x0001DC00;
+       bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
+                            & 0x0000DC00;
+       bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
+                            & 0x0000DC00;
+       bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
+                            & 0x0001DC00;
+       bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
+                            & 0x0000DC00;
+       bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON)
+                            & 0x0000DC00;
 
        bcm43xx_interrupt_ack(bcm, reason);
 
@@ -1930,16 +1897,18 @@ out:
 
 static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
 {
+       struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
        if (bcm->firmware_norelease && !force)
                return; /* Suspending or controller reset. */
-       release_firmware(bcm->ucode);
-       bcm->ucode = NULL;
-       release_firmware(bcm->pcm);
-       bcm->pcm = NULL;
-       release_firmware(bcm->initvals0);
-       bcm->initvals0 = NULL;
-       release_firmware(bcm->initvals1);
-       bcm->initvals1 = NULL;
+       release_firmware(phy->ucode);
+       phy->ucode = NULL;
+       release_firmware(phy->pcm);
+       phy->pcm = NULL;
+       release_firmware(phy->initvals0);
+       phy->initvals0 = NULL;
+       release_firmware(phy->initvals1);
+       phy->initvals1 = NULL;
 }
 
 static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
@@ -1950,11 +1919,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
        int nr;
        char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
 
-       if (!bcm->ucode) {
+       if (!phy->ucode) {
                snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
                         (rev >= 5 ? 5 : rev),
                         modparam_fwpostfix);
-               err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
+               err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
                if (err) {
                        printk(KERN_ERR PFX 
                               "Error: Microcode \"%s\" not available or load failed.\n",
@@ -1963,12 +1932,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                }
        }
 
-       if (!bcm->pcm) {
+       if (!phy->pcm) {
                snprintf(buf, ARRAY_SIZE(buf),
                         "bcm43xx_pcm%d%s.fw",
                         (rev < 5 ? 4 : 5),
                         modparam_fwpostfix);
-               err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
+               err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
                if (err) {
                        printk(KERN_ERR PFX
                               "Error: PCM \"%s\" not available or load failed.\n",
@@ -1977,7 +1946,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                }
        }
 
-       if (!bcm->initvals0) {
+       if (!phy->initvals0) {
                if (rev == 2 || rev == 4) {
                        switch (phy->type) {
                        case BCM43xx_PHYTYPE_A:
@@ -2008,20 +1977,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
                         nr, modparam_fwpostfix);
 
-               err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
+               err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
                if (err) {
                        printk(KERN_ERR PFX 
                               "Error: InitVals \"%s\" not available or load failed.\n",
                                buf);
                        goto error;
                }
-               if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
+               if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
                        printk(KERN_ERR PFX "InitVals fileformat error.\n");
                        goto error;
                }
        }
 
-       if (!bcm->initvals1) {
+       if (!phy->initvals1) {
                if (rev >= 5) {
                        u32 sbtmstatehigh;
 
@@ -2043,14 +2012,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                        snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
                                 nr, modparam_fwpostfix);
 
-                       err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
+                       err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
                        if (err) {
                                printk(KERN_ERR PFX 
                                       "Error: InitVals \"%s\" not available or load failed.\n",
                                        buf);
                                goto error;
                        }
-                       if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
+                       if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
                                printk(KERN_ERR PFX "InitVals fileformat error.\n");
                                goto error;
                        }
@@ -2070,12 +2039,13 @@ err_noinitval:
 
 static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
 {
+       struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        const u32 *data;
        unsigned int i, len;
 
        /* Upload Microcode. */
-       data = (u32 *)(bcm->ucode->data);
-       len = bcm->ucode->size / sizeof(u32);
+       data = (u32 *)(phy->ucode->data);
+       len = phy->ucode->size / sizeof(u32);
        bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
        for (i = 0; i < len; i++) {
                bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
@@ -2084,8 +2054,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
        }
 
        /* Upload PCM data. */
-       data = (u32 *)(bcm->pcm->data);
-       len = bcm->pcm->size / sizeof(u32);
+       data = (u32 *)(phy->pcm->data);
+       len = phy->pcm->size / sizeof(u32);
        bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
        bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
        bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
@@ -2131,15 +2101,16 @@ err_format:
 
 static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
 {
+       struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        int err;
 
-       err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
-                                    bcm->initvals0->size / sizeof(struct bcm43xx_initval));
+       err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
+                                    phy->initvals0->size / sizeof(struct bcm43xx_initval));
        if (err)
                goto out;
-       if (bcm->initvals1) {
-               err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
-                                            bcm->initvals1->size / sizeof(struct bcm43xx_initval));
+       if (phy->initvals1) {
+               err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
+                                            phy->initvals1->size / sizeof(struct bcm43xx_initval));
                if (err)
                        goto out;
        }
@@ -2156,9 +2127,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = {
 
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
-       int res;
-       unsigned int i;
-       u32 data;
+       int err;
 
        bcm->irq = bcm->pci_dev->irq;
 #ifdef CONFIG_BCM947XX
@@ -2175,32 +2144,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
                }
        }
 #endif
-       res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
+       err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
                          IRQF_SHARED, KBUILD_MODNAME, bcm);
-       if (res) {
+       if (err)
                printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
-               return -ENODEV;
-       }
-       bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
-       i = 0;
-       while (1) {
-               data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
-               if (data == BCM43xx_IRQ_READY)
-                       break;
-               i++;
-               if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
-                       printk(KERN_ERR PFX "Card IRQ register not responding. "
-                                           "Giving up.\n");
-                       free_irq(bcm->irq, bcm);
-                       return -ENODEV;
-               }
-               udelay(10);
-       }
-       // dummy read
-       bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 
-       return 0;
+       return err;
 }
 
 /* Switch to the core used to write the GPIO register.
@@ -2298,13 +2247,17 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
 /* http://bcm-specs.sipsolutions.net/EnableMac */
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
 {
-       bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-                       bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-                       | BCM43xx_SBF_MAC_ENABLED);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
-       bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
-       bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-       bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+       bcm->mac_suspended--;
+       assert(bcm->mac_suspended >= 0);
+       if (bcm->mac_suspended == 0) {
+               bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+                               bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+                               | BCM43xx_SBF_MAC_ENABLED);
+               bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+               bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+               bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+               bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+       }
 }
 
 /* http://bcm-specs.sipsolutions.net/SuspendMAC */
@@ -2313,18 +2266,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
        int i;
        u32 tmp;
 
-       bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-                       bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-                       & ~BCM43xx_SBF_MAC_ENABLED);
-       bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-       for (i = 100000; i; i--) {
-               tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
-               if (tmp & BCM43xx_IRQ_READY)
-                       return;
-               udelay(10);
+       assert(bcm->mac_suspended >= 0);
+       if (bcm->mac_suspended == 0) {
+               bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+               bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+                               bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+                               & ~BCM43xx_SBF_MAC_ENABLED);
+               bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+               for (i = 10000; i; i--) {
+                       tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+                       if (tmp & BCM43xx_IRQ_READY)
+                               goto out;
+                       udelay(1);
+               }
+               printkl(KERN_ERR PFX "MAC suspend failed\n");
        }
-       printkl(KERN_ERR PFX "MAC suspend failed\n");
+out:
+       bcm->mac_suspended++;
 }
 
 void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
@@ -2394,7 +2352,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
        if (!modparam_noleds)
                bcm43xx_leds_exit(bcm);
        bcm43xx_gpio_cleanup(bcm);
-       free_irq(bcm->irq, bcm);
        bcm43xx_release_firmware(bcm, 0);
 }
 
@@ -2406,7 +2363,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
        struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        int err;
-       int tmp;
+       int i, tmp;
        u32 value32;
        u16 value16;
 
@@ -2419,13 +2376,26 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
                goto out;
        bcm43xx_upload_microcode(bcm);
 
-       err = bcm43xx_initialize_irq(bcm);
-       if (err)
-               goto err_release_fw;
+       bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
+       i = 0;
+       while (1) {
+               value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+               if (value32 == BCM43xx_IRQ_READY)
+                       break;
+               i++;
+               if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
+                       printk(KERN_ERR PFX "IRQ_READY timeout\n");
+                       err = -ENODEV;
+                       goto err_release_fw;
+               }
+               udelay(10);
+       }
+       bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
 
        err = bcm43xx_gpio_init(bcm);
        if (err)
-               goto err_free_irq;
+               goto err_release_fw;
 
        err = bcm43xx_upload_initvals(bcm);
        if (err)
@@ -2489,10 +2459,12 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
                bcm43xx_write32(bcm, 0x018C, 0x02000000);
        }
        bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
        bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
-       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
 
        value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
        value32 |= 0x00100000;
@@ -2509,8 +2481,6 @@ err_radio_off:
        bcm43xx_radio_turn_off(bcm);
 err_gpio_cleanup:
        bcm43xx_gpio_cleanup(bcm);
-err_free_irq:
-       free_irq(bcm->irq, bcm);
 err_release_fw:
        bcm43xx_release_firmware(bcm, 1);
        goto out;
@@ -2550,11 +2520,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
 {
        /* Initialize a "phyinfo" structure. The structure is already
         * zeroed out.
+        * This is called on insmod time to initialize members.
         */
-       phy->antenna_diversity = 0xFFFF;
        phy->savedpctlreg = 0xFFFF;
-       phy->minlowsig[0] = 0xFFFF;
-       phy->minlowsig[1] = 0xFFFF;
        spin_lock_init(&phy->lock);
 }
 
@@ -2562,14 +2530,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
 {
        /* Initialize a "radioinfo" structure. The structure is already
         * zeroed out.
+        * This is called on insmod time to initialize members.
         */
        radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
        radio->channel = 0xFF;
        radio->initial_channel = 0xFF;
-       radio->lofcal = 0xFFFF;
-       radio->initval = 0xFFFF;
-       radio->nrssi[0] = -1000;
-       radio->nrssi[1] = -1000;
 }
 
 static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
@@ -2587,7 +2552,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
                                    * BCM43xx_MAX_80211_CORES);
        memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
                                        * BCM43xx_MAX_80211_CORES);
-       bcm->current_80211_core_idx = -1;
        bcm->nr_80211_available = 0;
        bcm->current_core = NULL;
        bcm->active_80211_core = NULL;
@@ -2757,6 +2721,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
                                goto out;
                        }
                        bcm->nr_80211_available++;
+                       core->priv = ext_80211;
                        bcm43xx_init_struct_phyinfo(&ext_80211->phy);
                        bcm43xx_init_struct_radioinfo(&ext_80211->radio);
                        break;
@@ -2857,7 +2822,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
 }
 
 /* http://bcm-specs.sipsolutions.net/80211Init */
-static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
+static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
+                                     int active_wlcore)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
@@ -2939,19 +2905,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
        if (bcm->current_core->rev >= 5)
                bcm43xx_write16(bcm, 0x043C, 0x000C);
 
-       if (bcm43xx_using_pio(bcm))
-               err = bcm43xx_pio_init(bcm);
-       else
-               err = bcm43xx_dma_init(bcm);
-       if (err)
-               goto err_chip_cleanup;
+       if (active_wlcore) {
+               if (bcm43xx_using_pio(bcm))
+                       err = bcm43xx_pio_init(bcm);
+               else
+                       err = bcm43xx_dma_init(bcm);
+               if (err)
+                       goto err_chip_cleanup;
+       }
        bcm43xx_write16(bcm, 0x0612, 0x0050);
        bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
        bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
 
-       bcm43xx_mac_enable(bcm);
-       bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+       if (active_wlcore) {
+               if (radio->initial_channel != 0xFF)
+                       bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
+       }
 
+       /* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
+        * We enable it later.
+        */
        bcm->current_core->initialized = 1;
 out:
        return err;
@@ -3066,11 +3039,6 @@ out:
        return err;
 }
 
-static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
-{
-       ieee80211softmac_start(bcm->net_dev);
-}
-
 static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -3182,39 +3150,40 @@ static void bcm43xx_periodic_work_handler(void *d)
                /* Periodic work will take a long time, so we want it to
                 * be preemtible.
                 */
-               bcm43xx_lock_irqonly(bcm, flags);
                netif_stop_queue(bcm->net_dev);
+               synchronize_net();
+               spin_lock_irqsave(&bcm->irq_lock, flags);
+               bcm43xx_mac_suspend(bcm);
                if (bcm43xx_using_pio(bcm))
                        bcm43xx_pio_freeze_txqueues(bcm);
                savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-               bcm43xx_unlock_irqonly(bcm, flags);
-               bcm43xx_lock_noirq(bcm);
+               spin_unlock_irqrestore(&bcm->irq_lock, flags);
+               mutex_lock(&bcm->mutex);
                bcm43xx_synchronize_irq(bcm);
        } else {
                /* Periodic work should take short time, so we want low
                 * locking overhead.
                 */
-               bcm43xx_lock_irqsafe(bcm, flags);
+               mutex_lock(&bcm->mutex);
+               spin_lock_irqsave(&bcm->irq_lock, flags);
        }
 
        do_periodic_work(bcm);
 
        if (badness > BADNESS_LIMIT) {
-               bcm43xx_lock_irqonly(bcm, flags);
+               spin_lock_irqsave(&bcm->irq_lock, flags);
                if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
                        tasklet_enable(&bcm->isr_tasklet);
                        bcm43xx_interrupt_enable(bcm, savedirqs);
                        if (bcm43xx_using_pio(bcm))
                                bcm43xx_pio_thaw_txqueues(bcm);
+                       bcm43xx_mac_enable(bcm);
                }
                netif_wake_queue(bcm->net_dev);
-               mmiowb();
-               bcm43xx_unlock_irqonly(bcm, flags);
-               bcm43xx_unlock_noirq(bcm);
-       } else {
-               mmiowb();
-               bcm43xx_unlock_irqsafe(bcm, flags);
        }
+       mmiowb();
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 }
 
 static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
@@ -3243,9 +3212,9 @@ static int bcm43xx_rng_read(struct hwrng *rng, u32 *data)
        struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
        unsigned long flags;
 
-       bcm43xx_lock_irqonly(bcm, flags);
+       spin_lock_irqsave(&(bcm)->irq_lock, flags);
        *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
-       bcm43xx_unlock_irqonly(bcm, flags);
+       spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
 
        return (sizeof(u16));
 }
@@ -3271,139 +3240,330 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
        return err;
 }
 
-/* This is the opposite of bcm43xx_init_board() */
-static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
 {
+       int ret = 0;
        int i, err;
+       struct bcm43xx_coreinfo *core;
+
+       bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+       for (i = 0; i < bcm->nr_80211_available; i++) {
+               core = &(bcm->core_80211[i]);
+               assert(core->available);
+               if (!core->initialized)
+                       continue;
+               err = bcm43xx_switch_core(bcm, core);
+               if (err) {
+                       dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
+                                            "switch_core failed (%d)\n", err);
+                       ret = err;
+                       continue;
+               }
+               bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+               bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+               bcm43xx_wireless_core_cleanup(bcm);
+               if (core == bcm->active_80211_core)
+                       bcm->active_80211_core = NULL;
+       }
+       free_irq(bcm->irq, bcm);
+       bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
 
-       bcm43xx_lock_noirq(bcm);
+       return ret;
+}
+
+/* This is the opposite of bcm43xx_init_board() */
+static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+{
+       bcm43xx_rng_exit(bcm);
        bcm43xx_sysfs_unregister(bcm);
        bcm43xx_periodic_tasks_delete(bcm);
 
-       bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+       mutex_lock(&(bcm)->mutex);
+       bcm43xx_shutdown_all_wireless_cores(bcm);
+       bcm43xx_pctl_set_crystal(bcm, 0);
+       mutex_unlock(&(bcm)->mutex);
+}
 
-       bcm43xx_rng_exit(bcm);
+static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
+{
+       phy->antenna_diversity = 0xFFFF;
+       memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+       memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+       /* Flags */
+       phy->calibrated = 0;
+       phy->is_locked = 0;
+
+       if (phy->_lo_pairs) {
+               memset(phy->_lo_pairs, 0,
+                      sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
+       }
+       memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
+}
+
+static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
+                                      struct bcm43xx_radioinfo *radio)
+{
+       int i;
+
+       /* Set default attenuation values. */
+       radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+       radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+       radio->txctl1 = bcm43xx_default_txctl1(bcm);
+       radio->txctl2 = 0xFFFF;
+       radio->txpwr_offset = 0;
+
+       /* NRSSI */
+       radio->nrssislope = 0;
+       for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
+               radio->nrssi[i] = -1000;
+       for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
+               radio->nrssi_lt[i] = i;
+
+       radio->lofcal = 0xFFFF;
+       radio->initval = 0xFFFF;
+
+       radio->aci_enable = 0;
+       radio->aci_wlan_automatic = 0;
+       radio->aci_hw_rssi = 0;
+}
+
+static void prepare_priv_for_init(struct bcm43xx_private *bcm)
+{
+       int i;
+       struct bcm43xx_coreinfo *core;
+       struct bcm43xx_coreinfo_80211 *wlext;
+
+       assert(!bcm->active_80211_core);
+
+       bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+
+       /* Flags */
+       bcm->was_initialized = 0;
+       bcm->reg124_set_0x4 = 0;
+
+       /* Stats */
+       memset(&bcm->stats, 0, sizeof(bcm->stats));
+
+       /* Wireless core data */
        for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
-               if (!bcm->core_80211[i].available)
-                       continue;
-               if (!bcm->core_80211[i].initialized)
+               core = &(bcm->core_80211[i]);
+               wlext = core->priv;
+
+               if (!core->available)
                        continue;
+               assert(wlext == &(bcm->core_80211_ext[i]));
 
-               err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
-               assert(err == 0);
-               bcm43xx_wireless_core_cleanup(bcm);
+               prepare_phydata_for_init(&wlext->phy);
+               prepare_radiodata_for_init(bcm, &wlext->radio);
        }
 
-       bcm43xx_pctl_set_crystal(bcm, 0);
+       /* IRQ related flags */
+       bcm->irq_reason = 0;
+       memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
+       bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
 
-       bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
-       bcm43xx_unlock_noirq(bcm);
+       bcm->mac_suspended = 1;
+
+       /* Noise calculation context */
+       memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
+
+       /* Periodic work context */
+       bcm->periodic_state = 0;
 }
 
-static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+static int wireless_core_up(struct bcm43xx_private *bcm,
+                           int active_wlcore)
+{
+       int err;
+
+       if (!bcm43xx_core_enabled(bcm))
+               bcm43xx_wireless_core_reset(bcm, 1);
+       if (!active_wlcore)
+               bcm43xx_wireless_core_mark_inactive(bcm);
+       err = bcm43xx_wireless_core_init(bcm, active_wlcore);
+       if (err)
+               goto out;
+       if (!active_wlcore)
+               bcm43xx_radio_turn_off(bcm);
+out:
+       return err;
+}
+
+/* Select and enable the "to be used" wireless core.
+ * Locking: bcm->mutex must be aquired before calling this.
+ *          bcm->irq_lock must not be aquired.
+ */
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+                                int phytype)
 {
        int i, err;
-       int connect_phy;
+       struct bcm43xx_coreinfo *active_core = NULL;
+       struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
+       struct bcm43xx_coreinfo *core;
+       struct bcm43xx_coreinfo_80211 *wlext;
+       int adjust_active_sbtmstatelow = 0;
 
        might_sleep();
 
-       bcm43xx_lock_noirq(bcm);
-       bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+       if (phytype < 0) {
+               /* If no phytype is requested, select the first core. */
+               assert(bcm->core_80211[0].available);
+               wlext = bcm->core_80211[0].priv;
+               phytype = wlext->phy.type;
+       }
+       /* Find the requested core. */
+       for (i = 0; i < bcm->nr_80211_available; i++) {
+               core = &(bcm->core_80211[i]);
+               wlext = core->priv;
+               if (wlext->phy.type == phytype) {
+                       active_core = core;
+                       active_wlext = wlext;
+                       break;
+               }
+       }
+       if (!active_core)
+               return -ESRCH; /* No such PHYTYPE on this board. */
+
+       if (bcm->active_80211_core) {
+               /* We already selected a wl core in the past.
+                * So first clean up everything.
+                */
+               dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
+               ieee80211softmac_stop(bcm->net_dev);
+               bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+               err = bcm43xx_disable_interrupts_sync(bcm);
+               assert(!err);
+               tasklet_enable(&bcm->isr_tasklet);
+               err = bcm43xx_shutdown_all_wireless_cores(bcm);
+               if (err)
+                       goto error;
+               /* Ok, everything down, continue to re-initialize. */
+               bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+       }
+
+       /* Reset all data structures. */
+       prepare_priv_for_init(bcm);
 
-       err = bcm43xx_pctl_set_crystal(bcm, 1);
-       if (err)
-               goto out;
-       err = bcm43xx_pctl_init(bcm);
-       if (err)
-               goto err_crystal_off;
        err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
        if (err)
-               goto err_crystal_off;
+               goto error;
 
-       tasklet_enable(&bcm->isr_tasklet);
+       /* Mark all unused cores "inactive". */
        for (i = 0; i < bcm->nr_80211_available; i++) {
-               err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
-               assert(err != -ENODEV);
-               if (err)
-                       goto err_80211_unwind;
+               core = &(bcm->core_80211[i]);
+               wlext = core->priv;
 
-               /* Enable the selected wireless core.
-                * Connect PHY only on the first core.
-                */
-               if (!bcm43xx_core_enabled(bcm)) {
-                       if (bcm->nr_80211_available == 1) {
-                               connect_phy = bcm43xx_current_phy(bcm)->connected;
-                       } else {
-                               if (i == 0)
-                                       connect_phy = 1;
-                               else
-                                       connect_phy = 0;
-                       }
-                       bcm43xx_wireless_core_reset(bcm, connect_phy);
+               if (core == active_core)
+                       continue;
+               err = bcm43xx_switch_core(bcm, core);
+               if (err) {
+                       dprintk(KERN_ERR PFX "Could not switch to inactive "
+                                            "802.11 core (%d)\n", err);
+                       goto error;
                }
+               err = wireless_core_up(bcm, 0);
+               if (err) {
+                       dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
+                                            "failed (%d)\n", err);
+                       goto error;
+               }
+               adjust_active_sbtmstatelow = 1;
+       }
 
-               if (i != 0)
-                       bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
-
-               err = bcm43xx_wireless_core_init(bcm);
-               if (err)
-                       goto err_80211_unwind;
+       /* Now initialize the active 802.11 core. */
+       err = bcm43xx_switch_core(bcm, active_core);
+       if (err) {
+               dprintk(KERN_ERR PFX "Could not switch to active "
+                                    "802.11 core (%d)\n", err);
+               goto error;
+       }
+       if (adjust_active_sbtmstatelow &&
+           active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
+               u32 sbtmstatelow;
 
-               if (i != 0) {
-                       bcm43xx_mac_suspend(bcm);
-                       bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-                       bcm43xx_radio_turn_off(bcm);
-               }
+               sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+               sbtmstatelow |= 0x20000000;
+               bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
        }
-       bcm->active_80211_core = &bcm->core_80211[0];
-       if (bcm->nr_80211_available >= 2) {
-               bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
-               bcm43xx_mac_enable(bcm);
+       err = wireless_core_up(bcm, 1);
+       if (err) {
+               dprintk(KERN_ERR PFX "core_up for active 802.11 core "
+                                    "failed (%d)\n", err);
+               goto error;
        }
-       err = bcm43xx_rng_init(bcm);
+       err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
        if (err)
-               goto err_80211_unwind;
+               goto error;
+       bcm->active_80211_core = active_core;
+
        bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
        bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
-       dprintk(KERN_INFO PFX "80211 cores initialized\n");
        bcm43xx_security_init(bcm);
-       bcm43xx_softmac_init(bcm);
+       ieee80211softmac_start(bcm->net_dev);
 
-       bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+       /* Let's go! Be careful after enabling the IRQs.
+        * Don't switch cores, for example.
+        */
+       bcm43xx_mac_enable(bcm);
+       bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+       err = bcm43xx_initialize_irq(bcm);
+       if (err)
+               goto error;
+       bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
 
-       if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
-               bcm43xx_mac_suspend(bcm);
-               bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
-               bcm43xx_mac_enable(bcm);
-       }
+       dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
+               active_wlext->phy.type);
 
-       /* Initialization of the board is done. Flag it as such. */
-       bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+       return 0;
+
+error:
+       bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+       bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+       return err;
+}
+
+static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+{
+       int err;
+
+       mutex_lock(&(bcm)->mutex);
+
+       tasklet_enable(&bcm->isr_tasklet);
+       err = bcm43xx_pctl_set_crystal(bcm, 1);
+       if (err)
+               goto err_tasklet;
+       err = bcm43xx_pctl_init(bcm);
+       if (err)
+               goto err_crystal_off;
+       err = bcm43xx_select_wireless_core(bcm, -1);
+       if (err)
+               goto err_crystal_off;
 
        bcm43xx_periodic_tasks_setup(bcm);
-       bcm43xx_sysfs_register(bcm);
-       //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
+       err = bcm43xx_sysfs_register(bcm);
+       if (err)
+               goto err_wlshutdown;
+       err = bcm43xx_rng_init(bcm);
+       if (err)
+               goto err_sysfs_unreg;
 
        /*FIXME: This should be handled by softmac instead. */
        schedule_work(&bcm->softmac->associnfo.work);
 
-       assert(err == 0);
 out:
-       bcm43xx_unlock_noirq(bcm);
+       mutex_unlock(&(bcm)->mutex);
 
        return err;
 
-err_80211_unwind:
-       tasklet_disable(&bcm->isr_tasklet);
-       /* unwind all 80211 initialization */
-       for (i = 0; i < bcm->nr_80211_available; i++) {
-               if (!bcm->core_80211[i].initialized)
-                       continue;
-               bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-               bcm43xx_wireless_core_cleanup(bcm);
-       }
+err_sysfs_unreg:
+       bcm43xx_sysfs_unregister(bcm);
+err_wlshutdown:
+       bcm43xx_shutdown_all_wireless_cores(bcm);
 err_crystal_off:
        bcm43xx_pctl_set_crystal(bcm, 0);
+err_tasklet:
+       tasklet_disable(&bcm->isr_tasklet);
        goto out;
 }
 
@@ -3647,7 +3807,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
        struct bcm43xx_radioinfo *radio;
        unsigned long flags;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
                bcm43xx_mac_suspend(bcm);
                bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -3656,7 +3817,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
                radio = bcm43xx_current_radio(bcm);
                radio->initial_channel = channel;
        }
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 }
 
 /* set_security() callback in struct ieee80211_device */
@@ -3670,7 +3832,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
        
        dprintk(KERN_INFO PFX "set security called");
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
 
        for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
                if (sec->flags & (1<<keyidx)) {
@@ -3739,7 +3902,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
                } else
                                bcm43xx_clear_keys(bcm);
        }
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 }
 
 /* hard_start_xmit() callback in struct ieee80211_device */
@@ -3751,12 +3915,14 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
        int err = -ENODEV;
        unsigned long flags;
 
-       bcm43xx_lock_irqonly(bcm, flags);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
                err = bcm43xx_tx(bcm, txb);
-       bcm43xx_unlock_irqonly(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
-       return err;
+       if (unlikely(err))
+               return NETDEV_TX_BUSY;
+       return NETDEV_TX_OK;
 }
 
 static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
@@ -3769,9 +3935,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        unsigned long flags;
 
-       bcm43xx_lock_irqonly(bcm, flags);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        bcm43xx_controller_restart(bcm, "TX timeout");
-       bcm43xx_unlock_irqonly(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3781,7 +3947,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev)
        unsigned long flags;
 
        local_irq_save(flags);
-       bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
+               bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
        local_irq_restore(flags);
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -3799,7 +3966,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
        int err;
 
        ieee80211softmac_stop(net_dev);
-       err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+       err = bcm43xx_disable_interrupts_sync(bcm);
        assert(!err);
        bcm43xx_free_board(bcm);
 
@@ -3818,10 +3985,12 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
        bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
 
        bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+       bcm->mac_suspended = 1;
        bcm->pci_dev = pci_dev;
        bcm->net_dev = net_dev;
        bcm->bad_frames_preempt = modparam_bad_frames_preempt;
        spin_lock_init(&bcm->irq_lock);
+       spin_lock_init(&bcm->leds_lock);
        mutex_init(&bcm->mutex);
        tasklet_init(&bcm->isr_tasklet,
                     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
@@ -3940,7 +4109,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
        bcm43xx_debugfs_remove_device(bcm);
        unregister_netdev(net_dev);
        bcm43xx_detach_board(bcm);
-       assert(bcm->ucode == NULL);
        free_ieee80211softmac(net_dev);
 }
 
@@ -3950,47 +4118,25 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
 static void bcm43xx_chip_reset(void *_bcm)
 {
        struct bcm43xx_private *bcm = _bcm;
-       struct net_device *net_dev = bcm->net_dev;
-       struct pci_dev *pci_dev = bcm->pci_dev;
+       struct bcm43xx_phyinfo *phy;
        int err;
-       int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
-       netif_stop_queue(bcm->net_dev);
-       tasklet_disable(&bcm->isr_tasklet);
+       mutex_lock(&(bcm)->mutex);
+       phy = bcm43xx_current_phy(bcm);
+       err = bcm43xx_select_wireless_core(bcm, phy->type);
+       mutex_unlock(&(bcm)->mutex);
 
-       bcm->firmware_norelease = 1;
-       if (was_initialized)
-               bcm43xx_free_board(bcm);
-       bcm->firmware_norelease = 0;
-       bcm43xx_detach_board(bcm);
-       err = bcm43xx_init_private(bcm, net_dev, pci_dev);
-       if (err)
-               goto failure;
-       err = bcm43xx_attach_board(bcm);
-       if (err)
-               goto failure;
-       if (was_initialized) {
-               err = bcm43xx_init_board(bcm);
-               if (err)
-                       goto failure;
-       }
-       netif_wake_queue(bcm->net_dev);
-       printk(KERN_INFO PFX "Controller restarted\n");
-
-       return;
-failure:
-       printk(KERN_ERR PFX "Controller restart failed\n");
+       printk(KERN_ERR PFX "Controller restart%s\n",
+              (err == 0) ? "ed" : " failed");
 }
 
 /* Hard-reset the chip.
  * This can be called from interrupt or process context.
- * Make sure to _not_ re-enable device interrupts after this has been called.
-*/
+ */
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
 {
+       assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
        bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
-       bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-       bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
        printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
        INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
        schedule_work(&bcm->restart_work);
@@ -4002,21 +4148,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *net_dev = pci_get_drvdata(pdev);
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
-       int try_to_shutdown = 0, err;
+       int err;
 
        dprintk(KERN_INFO PFX "Suspending...\n");
 
-       bcm43xx_lock_irqsafe(bcm, flags);
-       bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
-       if (bcm->was_initialized)
-               try_to_shutdown = 1;
-       bcm43xx_unlock_irqsafe(bcm, flags);
-
        netif_device_detach(net_dev);
-       if (try_to_shutdown) {
+       bcm->was_initialized = 0;
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+               bcm->was_initialized = 1;
                ieee80211softmac_stop(net_dev);
-               err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
+               err = bcm43xx_disable_interrupts_sync(bcm);
                if (unlikely(err)) {
                        dprintk(KERN_ERR PFX "Suspend failed.\n");
                        return -EAGAIN;
@@ -4049,17 +4190,14 @@ static int bcm43xx_resume(struct pci_dev *pdev)
        pci_restore_state(pdev);
 
        bcm43xx_chipset_attach(bcm);
-       if (bcm->was_initialized) {
-               bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+       if (bcm->was_initialized)
                err = bcm43xx_init_board(bcm);
-       }
        if (err) {
                printk(KERN_ERR PFX "Resume failed!\n");
                return err;
        }
-
        netif_device_attach(net_dev);
-       
+
        dprintk(KERN_INFO PFX "Device resumed.\n");
 
        return 0;
index 116493671f88f00e41701348f59f3e8c0dc621b1..505c86e2007a3312c9674099666ef54ae8438bd8 100644 (file)
@@ -133,6 +133,9 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
 
 int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
 
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+                                int phytype);
+
 void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
 
 void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
index f8200deecc8a68020dfee39f87b5952c86f00988..eafd0f6626862ab5916f8ddd9906fd2e0b3c2450 100644 (file)
@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table[] = {
 static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
 
 
+static inline
+void bcm43xx_voluntary_preempt(void)
+{
+       assert(!in_atomic() && !in_irq() &&
+              !in_interrupt() && !irqs_disabled());
+#ifndef CONFIG_PREEMPT
+       cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
 void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
 void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-       unsigned long flags;
 
        bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
        if (phy->calibrated)
                return;
        if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
-               /* We do not want to be preempted while calibrating
-                * the hardware.
-                */
-               local_irq_save(flags);
-
                bcm43xx_wireless_core_reset(bcm, 0);
                bcm43xx_phy_initg(bcm);
                bcm43xx_wireless_core_reset(bcm, 1);
-
-               local_irq_restore(flags);
        }
        phy->calibrated = 1;
 }
@@ -1299,7 +1301,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
 {
        int i;
        u16 ret = 0;
+       unsigned long flags;
 
+       local_irq_save(flags);
        for (i = 0; i < 10; i++){
                bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
                udelay(1);
@@ -1309,6 +1313,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
                udelay(40);
                ret += bcm43xx_phy_read(bcm, 0x002C);
        }
+       local_irq_restore(flags);
+       bcm43xx_voluntary_preempt();
 
        return ret;
 }
@@ -1435,6 +1441,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
        }
        ret = bcm43xx_phy_read(bcm, 0x002D);
        local_irq_restore(flags);
+       bcm43xx_voluntary_preempt();
 
        return ret;
 }
@@ -1760,6 +1767,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
                        bcm43xx_radio_write16(bcm, 0x43, i);
                        bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
                        udelay(10);
+                       bcm43xx_voluntary_preempt();
 
                        bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
 
@@ -1803,6 +1811,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
                                              radio->txctl2
                                              | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
                        udelay(10);
+                       bcm43xx_voluntary_preempt();
 
                        bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
 
@@ -1824,6 +1833,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
                udelay(2);
                bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
+               bcm43xx_voluntary_preempt();
        } else
                bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
        bcm43xx_phy_lo_adjust(bcm, is_initializing);
@@ -2188,12 +2198,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        int err = -ENODEV;
-       unsigned long flags;
-
-       /* We do not want to be preempted while calibrating
-        * the hardware.
-        */
-       local_irq_save(flags);
 
        switch (phy->type) {
        case BCM43xx_PHYTYPE_A:
@@ -2227,7 +2231,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
                err = 0;
                break;
        }
-       local_irq_restore(flags);
        if (err)
                printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
 
index 574085c461526927d97a1b896f2dbbb2f4df8b8e..c60c1743ea067d4b7535bc62ec331b1b63ba33fc 100644 (file)
@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d)
        int err;
        u16 txctl;
 
-       bcm43xx_lock_irqonly(bcm, flags);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
 
        if (queue->tx_frozen)
                goto out_unlock;
@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d)
                continue;
        }
 out_unlock:
-       bcm43xx_unlock_irqonly(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 static void setup_txqueues(struct bcm43xx_pioqueue *queue)
index 6a23bdc75412cf397a86cbffbe539be4efa924f8..ece335178f6a7483e81f142d2a24ef5128d0094d 100644 (file)
@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
                        GFP_KERNEL);
        if (!sprom)
                return -ENOMEM;
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        err = bcm43xx_sprom_read(bcm, sprom);
        if (!err)
                err = sprom2hex(sprom, buf, PAGE_SIZE);
        mmiowb();
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
        kfree(sprom);
 
        return err;
@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
        err = hex2sprom(sprom, buf, count);
        if (err)
                goto out_kfree;
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+       spin_lock(&bcm->leds_lock);
        err = bcm43xx_sprom_write(bcm, sprom);
        mmiowb();
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock(&bcm->leds_lock);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 out_kfree:
        kfree(sprom);
 
@@ -176,7 +182,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       bcm43xx_lock_noirq(bcm);
+       mutex_lock(&bcm->mutex);
 
        switch (bcm43xx_current_radio(bcm)->interfmode) {
        case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -193,7 +199,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
        }
        err = 0;
 
-       bcm43xx_unlock_noirq(bcm);
+       mutex_unlock(&bcm->mutex);
 
        return err ? err : count;
 
@@ -229,7 +235,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
                return -EINVAL;
        }
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
 
        err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
        if (err) {
@@ -237,7 +244,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
                                    "supported by device\n");
        }
        mmiowb();
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err ? err : count;
 }
@@ -257,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       bcm43xx_lock_noirq(bcm);
+       mutex_lock(&bcm->mutex);
 
        if (bcm->short_preamble)
                count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -265,7 +273,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
                count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
 
        err = 0;
-       bcm43xx_unlock_noirq(bcm);
+       mutex_unlock(&bcm->mutex);
 
        return err ? err : count;
 }
@@ -285,12 +293,14 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
        value = get_boolean(buf, count);
        if (value < 0)
                return value;
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
 
        bcm->short_preamble = !!value;
 
        err = 0;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err ? err : count;
 }
@@ -299,6 +309,70 @@ static DEVICE_ATTR(shortpreamble, 0644,
                   bcm43xx_attr_preamble_show,
                   bcm43xx_attr_preamble_store);
 
+static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
+{
+       struct bcm43xx_private *bcm = dev_to_bcm(dev);
+       int phytype;
+       int err = -EINVAL;
+
+       if (count < 1)
+               goto out;
+       switch (buf[0]) {
+       case 'a':  case 'A':
+               phytype = BCM43xx_PHYTYPE_A;
+               break;
+       case 'b':  case 'B':
+               phytype = BCM43xx_PHYTYPE_B;
+               break;
+       case 'g':  case 'G':
+               phytype = BCM43xx_PHYTYPE_G;
+               break;
+       default:
+               goto out;
+       }
+
+       mutex_lock(&(bcm)->mutex);
+       err = bcm43xx_select_wireless_core(bcm, phytype);
+       mutex_unlock(&(bcm)->mutex);
+       if (err == -ESRCH)
+               err = -ENODEV;
+
+out:
+       return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct bcm43xx_private *bcm = dev_to_bcm(dev);
+       ssize_t count = 0;
+
+       mutex_lock(&(bcm)->mutex);
+       switch (bcm43xx_current_phy(bcm)->type) {
+       case BCM43xx_PHYTYPE_A:
+               snprintf(buf, PAGE_SIZE, "A");
+               break;
+       case BCM43xx_PHYTYPE_B:
+               snprintf(buf, PAGE_SIZE, "B");
+               break;
+       case BCM43xx_PHYTYPE_G:
+               snprintf(buf, PAGE_SIZE, "G");
+               break;
+       default:
+               assert(0);
+       }
+       mutex_unlock(&(bcm)->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(phymode, 0644,
+                  bcm43xx_attr_phymode_show,
+                  bcm43xx_attr_phymode_store);
+
 int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
 {
        struct device *dev = &bcm->pci_dev->dev;
@@ -315,9 +389,14 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
        err = device_create_file(dev, &dev_attr_shortpreamble);
        if (err)
                goto err_remove_interfmode;
+       err = device_create_file(dev, &dev_attr_phymode);
+       if (err)
+               goto err_remove_shortpreamble;
 
 out:
        return err;
+err_remove_shortpreamble:
+       device_remove_file(dev, &dev_attr_shortpreamble);
 err_remove_interfmode:
        device_remove_file(dev, &dev_attr_interference);
 err_remove_sprom:
@@ -329,6 +408,7 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
 {
        struct device *dev = &bcm->pci_dev->dev;
 
+       device_remove_file(dev, &dev_attr_phymode);
        device_remove_file(dev, &dev_attr_shortpreamble);
        device_remove_file(dev, &dev_attr_interference);
        device_remove_file(dev, &dev_attr_sprom);
index 5c36e29efff7e1082af46c193bd9b2255479da7e..888077fc14c457b7082e706d503754efc9b46ab3 100644 (file)
@@ -47,6 +47,8 @@
 #define BCM43xx_WX_VERSION     18
 
 #define MAX_WX_STRING          80
+/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
+#define RX_RSSI_MAX            60
 
 
 static int bcm43xx_wx_get_name(struct net_device *net_dev,
@@ -56,12 +58,11 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        int i;
-       unsigned long flags;
        struct bcm43xx_phyinfo *phy;
        char suffix[7] = { 0 };
        int have_a = 0, have_b = 0, have_g = 0;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        for (i = 0; i < bcm->nr_80211_available; i++) {
                phy = &(bcm->core_80211_ext[i].phy);
                switch (phy->type) {
@@ -77,7 +78,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
                        assert(0);
                }
        }
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        i = 0;
        if (have_a) {
@@ -111,7 +112,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
        int freq;
        int err = -EINVAL;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+
        if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
                channel = data->freq.m;
                freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -131,7 +134,8 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
                err = 0;
        }
 out_unlock:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -143,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        struct bcm43xx_radioinfo *radio;
-       unsigned long flags;
        int err = -ENODEV;
        u16 channel;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        radio = bcm43xx_current_radio(bcm);
        channel = radio->channel;
        if (channel == 0xFF) {
@@ -162,7 +165,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
 
        err = 0;
 out_unlock:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -180,13 +183,15 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
        if (mode == IW_MODE_AUTO)
                mode = BCM43xx_INITIAL_IWMODE;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
                if (bcm->ieee->iw_mode != mode)
                        bcm43xx_set_iwmode(bcm, mode);
        } else
                bcm->ieee->iw_mode = mode;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -197,11 +202,10 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev,
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        data->mode = bcm->ieee->iw_mode;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -214,7 +218,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        struct iw_range *range = (struct iw_range *)extra;
        const struct ieee80211_geo *geo;
-       unsigned long flags;
        int i, j;
        struct bcm43xx_phyinfo *phy;
 
@@ -226,15 +229,14 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
        range->throughput = 27 * 1000 * 1000;
 
        range->max_qual.qual = 100;
-       /* TODO: Real max RSSI */
-       range->max_qual.level = 3;
-       range->max_qual.noise = 100;
-       range->max_qual.updated = 7;
+       range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
+       range->max_qual.noise = 146;
+       range->max_qual.updated = IW_QUAL_ALL_UPDATED;
 
-       range->avg_qual.qual = 70;
-       range->avg_qual.level = 2;
-       range->avg_qual.noise = 40;
-       range->avg_qual.updated = 7;
+       range->avg_qual.qual = 50;
+       range->avg_qual.level = 0;
+       range->avg_qual.noise = 0;
+       range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
 
        range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
        range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
@@ -254,7 +256,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
                          IW_ENC_CAPA_CIPHER_TKIP |
                          IW_ENC_CAPA_CIPHER_CCMP;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        phy = bcm43xx_current_phy(bcm);
 
        range->num_bitrates = 0;
@@ -301,7 +303,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
        }
        range->num_frequency = j;
 
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -314,11 +316,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev,
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        size_t len;
 
-       bcm43xx_lock_noirq(bcm);
+       mutex_lock(&bcm->mutex);
        len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
        memcpy(bcm->nick, extra, len);
        bcm->nick[len] = '\0';
-       bcm43xx_unlock_noirq(bcm);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -331,12 +333,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        size_t len;
 
-       bcm43xx_lock_noirq(bcm);
+       mutex_lock(&bcm->mutex);
        len = strlen(bcm->nick) + 1;
        memcpy(extra, bcm->nick, len);
        data->data.length = (__u16)len;
        data->data.flags = 1;
-       bcm43xx_unlock_noirq(bcm);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -350,7 +352,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
        unsigned long flags;
        int err = -EINVAL;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (data->rts.disabled) {
                bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
                err = 0;
@@ -361,7 +364,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
                        err = 0;
                }
        }
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -372,13 +376,12 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev,
                              char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        data->rts.value = bcm->rts_threshold;
        data->rts.fixed = 0;
        data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -392,7 +395,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
        unsigned long flags;
        int err = -EINVAL;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (data->frag.disabled) {
                bcm->ieee->fts = MAX_FRAG_THRESHOLD;
                err = 0;
@@ -403,7 +407,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
                        err = 0;
                }
        }
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -414,13 +419,12 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev,
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        data->frag.value = bcm->ieee->fts;
        data->frag.fixed = 0;
        data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -442,7 +446,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
                return -EOPNOTSUPP;
        }
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
                goto out_unlock;
        radio = bcm43xx_current_radio(bcm);
@@ -466,7 +471,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
        err = 0;
 
 out_unlock:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -478,10 +484,9 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        struct bcm43xx_radioinfo *radio;
-       unsigned long flags;
        int err = -ENODEV;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
                goto out_unlock;
        radio = bcm43xx_current_radio(bcm);
@@ -493,7 +498,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
 
        err = 0;
 out_unlock:
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -580,7 +585,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
                return -EINVAL;
        }
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
                err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
                if (err) {
@@ -595,7 +601,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
                } else
                        bcm43xx_current_radio(bcm)->interfmode = mode;
        }
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -606,12 +613,11 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
                                     char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        int mode;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        mode = bcm43xx_current_radio(bcm)->interfmode;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        switch (mode) {
        case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -641,9 +647,11 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
        int on;
 
        on = *((int *)extra);
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        bcm->short_preamble = !!on;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -654,12 +662,11 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
                                        char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        int on;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        on = bcm->short_preamble;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        if (on)
                strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -681,11 +688,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
        
        on = *((int *)extra);
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        bcm->ieee->host_encrypt = !!on;
        bcm->ieee->host_decrypt = !!on;
        bcm->ieee->host_build_iv = !on;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -696,12 +705,11 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
                                       char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        int on;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
        on = bcm->ieee->host_encrypt;
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        if (on)
                strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -764,11 +772,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
        if (!sprom)
                goto out;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        err = -ENODEV;
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
                err = bcm43xx_sprom_read(bcm, sprom);
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
        if (!err)
                data->data.length = sprom2hex(sprom, extra);
        kfree(sprom);
@@ -809,11 +819,15 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
        if (err)
                goto out_kfree;
 
-       bcm43xx_lock_irqsafe(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+       spin_lock(&bcm->leds_lock);
        err = -ENODEV;
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
                err = bcm43xx_sprom_write(bcm, sprom);
-       bcm43xx_unlock_irqsafe(bcm, flags);
+       spin_unlock(&bcm->leds_lock);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 out_kfree:
        kfree(sprom);
 out:
@@ -827,6 +841,10 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
        struct iw_statistics *wstats;
+       struct ieee80211_network *network = NULL;
+       static int tmp_level = 0;
+       static int tmp_qual = 0;
+       unsigned long flags;
 
        wstats = &bcm->stats.wstats;
        if (!mac->associated) {
@@ -844,16 +862,28 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
                wstats->qual.level = 0;
                wstats->qual.noise = 0;
                wstats->qual.updated = 7;
-               wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
-                       IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+               wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
                return wstats;
        }
        /* fill in the real statistics when iface associated */
-       wstats->qual.qual = 100;     // TODO: get the real signal quality
-       wstats->qual.level = 3 - bcm->stats.link_quality;
+       spin_lock_irqsave(&mac->ieee->lock, flags);
+       list_for_each_entry(network, &mac->ieee->network_list, list) {
+               if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
+                       if (!tmp_level) {       /* get initial values */
+                               tmp_level = network->stats.signal;
+                               tmp_qual = network->stats.rssi;
+                       } else {                /* smooth results */
+                               tmp_level = (15 * tmp_level + network->stats.signal)/16;
+                               tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
+                       }
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&mac->ieee->lock, flags);
+       wstats->qual.level = tmp_level;
+       wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
        wstats->qual.noise = bcm->stats.noise;
-       wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
-                       IW_QUAL_NOISE_UPDATED;
+       wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
        wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
        wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
        wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
index 6dbd855b3647b0f80163c5c48893d051b6ae19e5..c0efbfe605a5a20d3996a5f173a9e4657aac3dde 100644 (file)
@@ -492,16 +492,15 @@ int bcm43xx_rx(struct bcm43xx_private *bcm,
 
        memset(&stats, 0, sizeof(stats));
        stats.mac_time = le16_to_cpu(rxhdr->mactime);
-       stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
+       stats.rssi = rxhdr->rssi;
+       stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
                                              !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
                                              !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
-       stats.signal = rxhdr->signal_quality;   //FIXME
 //TODO stats.noise = 
        if (is_ofdm)
                stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
        else
                stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
-//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
        stats.received_channel = radio->channel;
 //TODO stats.control = 
        stats.mask = IEEE80211_STATMASK_SIGNAL |
index e955db435b30b4ef9e2c87106790ada253582fa6..5d5dab6a209c297a94e2be1fad17a3399acba46f 100644 (file)
@@ -6254,13 +6254,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
         * 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 */
-       mutex_lock(&priv->action_mutex);
        err = register_netdev(dev);
        if (err) {
                printk(KERN_WARNING DRV_NAME
                       "Error calling register_netdev.\n");
-               goto fail_unlock;
+               goto fail;
        }
+
+       mutex_lock(&priv->action_mutex);
        registered = 1;
 
        IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
index b3300ffe4eecb8dc888091255d4fbda501ce7efc..fa245f126c84c4bb44b523e575e36d8dff344075 100644 (file)
@@ -70,7 +70,7 @@
 #define VQ
 #endif
 
-#define IPW2200_VERSION "1.1.2" VK VD VM VP VR VQ
+#define IPW2200_VERSION "1.1.4" VK VD VM VP VR VQ
 #define DRV_DESCRIPTION        "Intel(R) PRO/Wireless 2200/2915 Network Driver"
 #define DRV_COPYRIGHT  "Copyright(c) 2003-2006 Intel Corporation"
 #define DRV_VERSION     IPW2200_VERSION
@@ -83,9 +83,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
 static int cmdlog = 0;
-#ifdef CONFIG_IPW2200_DEBUG
 static int debug = 0;
-#endif
 static int channel = 0;
 static int mode = 0;
 
@@ -567,7 +565,6 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv)
        spin_unlock_irqrestore(&priv->irq_lock, flags);
 }
 
-#ifdef CONFIG_IPW2200_DEBUG
 static char *ipw_error_desc(u32 val)
 {
        switch (val) {
@@ -634,7 +631,6 @@ static void ipw_dump_error_log(struct ipw_priv *priv,
                          error->log[i].time,
                          error->log[i].data, error->log[i].event);
 }
-#endif
 
 static inline int ipw_is_init(struct ipw_priv *priv)
 {
@@ -1435,9 +1431,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
                              const char *buf, size_t count)
 {
        struct ipw_priv *priv = dev_get_drvdata(d);
-#ifdef CONFIG_IPW2200_DEBUG
        struct net_device *dev = priv->net_dev;
-#endif
        char buffer[] = "00000000";
        unsigned long len =
            (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
@@ -1958,14 +1952,12 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
                IPW_WARNING("Firmware error detected.  Restarting.\n");
                if (priv->error) {
                        IPW_DEBUG_FW("Sysfs 'error' log already exists.\n");
-#ifdef CONFIG_IPW2200_DEBUG
                        if (ipw_debug_level & IPW_DL_FW_ERRORS) {
                                struct ipw_fw_error *error =
                                    ipw_alloc_error_log(priv);
                                ipw_dump_error_log(priv, error);
                                kfree(error);
                        }
-#endif
                } else {
                        priv->error = ipw_alloc_error_log(priv);
                        if (priv->error)
@@ -1973,10 +1965,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
                        else
                                IPW_DEBUG_FW("Error allocating sysfs 'error' "
                                             "log.\n");
-#ifdef CONFIG_IPW2200_DEBUG
                        if (ipw_debug_level & IPW_DL_FW_ERRORS)
                                ipw_dump_error_log(priv, priv->error);
-#endif
                }
 
                /* XXX: If hardware encryption is for WPA/WPA2,
@@ -2287,7 +2277,7 @@ static int ipw_send_scan_abort(struct ipw_priv *priv)
 static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
 {
        struct ipw_sensitivity_calib calib = {
-               .beacon_rssi_raw = sens,
+               .beacon_rssi_raw = cpu_to_le16(sens),
        };
 
        return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib),
@@ -2353,6 +2343,7 @@ static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
                return -1;
        }
 
+       phy_off = cpu_to_le32(phy_off);
        return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off),
                                &phy_off);
 }
@@ -2414,7 +2405,7 @@ static int ipw_set_tx_power(struct ipw_priv *priv)
 static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
 {
        struct ipw_rts_threshold rts_threshold = {
-               .rts_threshold = rts,
+               .rts_threshold = cpu_to_le16(rts),
        };
 
        if (!priv) {
@@ -2429,7 +2420,7 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
 static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
 {
        struct ipw_frag_threshold frag_threshold = {
-               .frag_threshold = frag,
+               .frag_threshold = cpu_to_le16(frag),
        };
 
        if (!priv) {
@@ -2464,6 +2455,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
                break;
        }
 
+       param = cpu_to_le32(mode);
        return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
                                &param);
 }
@@ -2667,7 +2659,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv)
 
        IPW_DEBUG_FW(">> :\n");
 
-       //set the Stop and Abort bit
+       /* set the Stop and Abort bit */
        control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
        ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
        priv->sram_desc.last_cb_index = 0;
@@ -3002,8 +2994,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
        if (rc < 0)
                return rc;
 
-//      spin_lock_irqsave(&priv->lock, flags);
-
        for (addr = IPW_SHARED_LOWER_BOUND;
             addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
                ipw_write32(priv, addr, 0);
@@ -3097,8 +3087,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
           firmware have problem getting alive resp. */
        ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
 
-//      spin_unlock_irqrestore(&priv->lock, flags);
-
        return rc;
 }
 
@@ -3919,7 +3907,6 @@ static const struct ipw_status_code ipw_status_codes[] = {
        {0x2E, "Cipher suite is rejected per security policy"},
 };
 
-#ifdef CONFIG_IPW2200_DEBUG
 static const char *ipw_get_status_code(u16 status)
 {
        int i;
@@ -3928,7 +3915,6 @@ static const char *ipw_get_status_code(u16 status)
                        return ipw_status_codes[i].reason;
        return "Unknown status value.";
 }
-#endif
 
 static void inline average_init(struct average *avg)
 {
@@ -4398,7 +4384,6 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                                        if (priv->
                                            status & (STATUS_ASSOCIATED |
                                                      STATUS_AUTH)) {
-#ifdef CONFIG_IPW2200_DEBUG
                                                struct notif_authenticate *auth
                                                    = &notif->u.auth;
                                                IPW_DEBUG(IPW_DL_NOTIF |
@@ -4416,7 +4401,6 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                                                          ipw_get_status_code
                                                          (ntohs
                                                           (auth->status)));
-#endif
 
                                                priv->status &=
                                                    ~(STATUS_ASSOCIATING |
@@ -5059,7 +5043,6 @@ static void ipw_rx_queue_replenish(void *data)
                }
                list_del(element);
 
-               rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data;
                rxb->dma_addr =
                    pci_map_single(priv->pci_dev, rxb->skb->data,
                                   IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -5838,8 +5821,8 @@ static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
        key.station_index = 0;  /* always 0 for BSS */
        key.flags = 0;
        /* 0 for new key; previous value of counter (after fatal error) */
-       key.tx_counter[0] = 0;
-       key.tx_counter[1] = 0;
+       key.tx_counter[0] = cpu_to_le32(0);
+       key.tx_counter[1] = cpu_to_le32(0);
 
        ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key);
 }
@@ -5973,7 +5956,6 @@ static void ipw_bg_adhoc_check(void *data)
        mutex_unlock(&priv->mutex);
 }
 
-#ifdef CONFIG_IPW2200_DEBUG
 static void ipw_debug_config(struct ipw_priv *priv)
 {
        IPW_DEBUG_INFO("Scan completed, no valid APs matched "
@@ -5998,9 +5980,6 @@ static void ipw_debug_config(struct ipw_priv *priv)
                IPW_DEBUG_INFO("PRIVACY off\n");
        IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
 }
-#else
-#define ipw_debug_config(x) do {} while (0)
-#endif
 
 static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
 {
@@ -6188,7 +6167,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
        }
 }
 
-static int ipw_request_scan(struct ipw_priv *priv)
+static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
 {
        struct ipw_scan_request_ext scan;
        int err = 0, scan_type;
@@ -6219,19 +6198,29 @@ static int ipw_request_scan(struct ipw_priv *priv)
        }
 
        memset(&scan, 0, sizeof(scan));
+       scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
 
-       if (priv->config & CFG_SPEED_SCAN)
+       if (type == IW_SCAN_TYPE_PASSIVE) {
+               IPW_DEBUG_WX("use passive scanning\n");
+               scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
+               scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
+                       cpu_to_le16(120);
+               ipw_add_scan_channels(priv, &scan, scan_type);
+               goto send_request;
+       }
+
+       /* Use active scan by default. */
+       if (priv->config & CFG_SPEED_SCAN)
                scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
-                   cpu_to_le16(30);
+                       cpu_to_le16(30);
        else
                scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
-                   cpu_to_le16(20);
+                       cpu_to_le16(20);
 
        scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
-           cpu_to_le16(20);
-       scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+               cpu_to_le16(20);
 
-       scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+       scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
 
 #ifdef CONFIG_IPW2200_MONITOR
        if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
@@ -6268,7 +6257,7 @@ static int ipw_request_scan(struct ipw_priv *priv)
                 *
                 * TODO: Move SPEED SCAN support to all modes and bands */
                scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
-                   cpu_to_le16(2000);
+                       cpu_to_le16(2000);
        } else {
 #endif                         /* CONFIG_IPW2200_MONITOR */
                /* If we are roaming, then make this a directed scan for the
@@ -6294,6 +6283,7 @@ static int ipw_request_scan(struct ipw_priv *priv)
        }
 #endif
 
+send_request:
        err = ipw_send_scan_request_ext(priv, &scan);
        if (err) {
                IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
@@ -6304,11 +6294,19 @@ static int ipw_request_scan(struct ipw_priv *priv)
        priv->status &= ~STATUS_SCAN_PENDING;
        queue_delayed_work(priv->workqueue, &priv->scan_check,
                           IPW_SCAN_CHECK_WATCHDOG);
-      done:
+done:
        mutex_unlock(&priv->mutex);
        return err;
 }
 
+static int ipw_request_passive_scan(struct ipw_priv *priv) {
+       return ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE);
+}
+
+static int ipw_request_scan(struct ipw_priv *priv) {
+       return ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE);
+}
+
 static void ipw_bg_abort_scan(void *data)
 {
        struct ipw_priv *priv = data;
@@ -6387,13 +6385,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
            (wrqu->data.length && extra == NULL))
                return -EINVAL;
 
-       //mutex_lock(&priv->mutex);
-
-       //if (!ieee->wpa_enabled) {
-       //      err = -EOPNOTSUPP;
-       //      goto out;
-       //}
-
        if (wrqu->data.length) {
                buf = kmalloc(wrqu->data.length, GFP_KERNEL);
                if (buf == NULL) {
@@ -6413,7 +6404,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
 
        ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
       out:
-       //mutex_unlock(&priv->mutex);
        return err;
 }
 
@@ -6426,13 +6416,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
        struct ieee80211_device *ieee = priv->ieee;
        int err = 0;
 
-       //mutex_lock(&priv->mutex);
-
-       //if (!ieee->wpa_enabled) {
-       //      err = -EOPNOTSUPP;
-       //      goto out;
-       //}
-
        if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
                wrqu->data.length = 0;
                goto out;
@@ -6447,7 +6430,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
        memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
 
       out:
-       //mutex_unlock(&priv->mutex);
        return err;
 }
 
@@ -6558,7 +6540,6 @@ static int ipw_wx_set_auth(struct net_device *dev,
                ieee->ieee802_1x = param->value;
                break;
 
-               //case IW_AUTH_ROAMING_CONTROL:
        case IW_AUTH_PRIVACY_INVOKED:
                ieee->privacy_invoked = param->value;
                break;
@@ -6680,7 +6661,7 @@ static int ipw_wx_set_mlme(struct net_device *dev,
 
        switch (mlme->cmd) {
        case IW_MLME_DEAUTH:
-               // silently ignore
+               /* silently ignore */
                break;
 
        case IW_MLME_DISASSOC:
@@ -6811,7 +6792,7 @@ static int ipw_qos_activate(struct ipw_priv *priv,
                burst_duration = ipw_qos_get_burst_duration(priv);
                for (i = 0; i < QOS_QUEUE_NUM; i++)
                        qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
-                           (u16) burst_duration;
+                           (u16)burst_duration;
        } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
                if (type == IEEE_B) {
                        IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n",
@@ -6843,11 +6824,20 @@ static int ipw_qos_activate(struct ipw_priv *priv,
                        burst_duration = ipw_qos_get_burst_duration(priv);
                        for (i = 0; i < QOS_QUEUE_NUM; i++)
                                qos_parameters[QOS_PARAM_SET_ACTIVE].
-                                   tx_op_limit[i] = (u16) burst_duration;
+                                   tx_op_limit[i] = (u16)burst_duration;
                }
        }
 
        IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
+       for (i = 0; i < 3; i++) {
+               int j;
+               for (j = 0; j < QOS_QUEUE_NUM; j++) {
+                       qos_parameters[i].cw_min[j] = cpu_to_le16(qos_parameters[i].cw_min[j]);
+                       qos_parameters[i].cw_max[j] = cpu_to_le16(qos_parameters[i].cw_max[j]);
+                       qos_parameters[i].tx_op_limit[j] = cpu_to_le16(qos_parameters[i].tx_op_limit[j]);
+               }
+       }
+
        err = ipw_send_qos_params_command(priv,
                                          (struct ieee80211_qos_parameters *)
                                          &(qos_parameters[0]));
@@ -7086,7 +7076,7 @@ static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
 
        if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) {
                tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
-               tfd->tfd.tfd_26.mchdr.qos_ctrl |= CTRL_QOS_NO_ACK;
+               tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK);
        }
        return 0;
 }
@@ -7667,7 +7657,6 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
        /* Big bitfield of all the fields we provide in radiotap */
        ipw_rt->rt_hdr.it_present =
            ((1 << IEEE80211_RADIOTAP_FLAGS) |
-            (1 << IEEE80211_RADIOTAP_TSFT) |
             (1 << IEEE80211_RADIOTAP_RATE) |
             (1 << IEEE80211_RADIOTAP_CHANNEL) |
             (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
@@ -7676,6 +7665,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
 
        /* Zero the flags, we'll add to them as we go */
        ipw_rt->rt_flags = 0;
+       ipw_rt->rt_tsf = 0ULL;
 
        /* Convert signal to DBM */
        ipw_rt->rt_dbmsignal = antsignal;
@@ -7794,7 +7784,6 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
        s8 noise = frame->noise;
        u8 rate = frame->rate;
        short len = le16_to_cpu(pkt->u.frame.length);
-       u64 tsf = 0;
        struct sk_buff *skb;
        int hdr_only = 0;
        u16 filter = priv->prom_priv->filter;
@@ -7829,17 +7818,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
        }
 
        hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
-       if (ieee80211_is_management(hdr->frame_ctl)) {
+       if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
                if (filter & IPW_PROM_NO_MGMT)
                        return;
                if (filter & IPW_PROM_MGMT_HEADER_ONLY)
                        hdr_only = 1;
-       } else if (ieee80211_is_control(hdr->frame_ctl)) {
+       } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
                if (filter & IPW_PROM_NO_CTL)
                        return;
                if (filter & IPW_PROM_CTL_HEADER_ONLY)
                        hdr_only = 1;
-       } else if (ieee80211_is_data(hdr->frame_ctl)) {
+       } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
                if (filter & IPW_PROM_NO_DATA)
                        return;
                if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -7857,7 +7846,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
        ipw_rt = (void *)skb->data;
 
        if (hdr_only)
-               len = ieee80211_get_hdrlen(hdr->frame_ctl);
+               len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
 
        memcpy(ipw_rt->payload, hdr, len);
 
@@ -7880,7 +7869,6 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
        /* Big bitfield of all the fields we provide in radiotap */
        ipw_rt->rt_hdr.it_present =
            ((1 << IEEE80211_RADIOTAP_FLAGS) |
-            (1 << IEEE80211_RADIOTAP_TSFT) |
             (1 << IEEE80211_RADIOTAP_RATE) |
             (1 << IEEE80211_RADIOTAP_CHANNEL) |
             (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
@@ -7889,8 +7877,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
 
        /* Zero the flags, we'll add to them as we go */
        ipw_rt->rt_flags = 0;
-
-       ipw_rt->rt_tsf = tsf;
+       ipw_rt->rt_tsf = 0ULL;
 
        /* Convert to DBM */
        ipw_rt->rt_dbmsignal = signal;
@@ -8163,8 +8150,7 @@ static void ipw_rx(struct ipw_priv *priv)
                switch (pkt->header.message_type) {
                case RX_FRAME_TYPE:     /* 802.11 frame */  {
                                struct ieee80211_rx_stats stats = {
-                                       .rssi =
-                                           le16_to_cpu(pkt->u.frame.rssi_dbm) -
+                                       .rssi = pkt->u.frame.rssi_dbm -
                                            IPW_RSSI_TO_DBM,
                                        .signal =
                                            le16_to_cpu(pkt->u.frame.rssi_dbm) -
@@ -8599,9 +8585,26 @@ static int ipw_wx_get_freq(struct net_device *dev,
         * configured CHANNEL then return that; otherwise return ANY */
        mutex_lock(&priv->mutex);
        if (priv->config & CFG_STATIC_CHANNEL ||
-           priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
-               wrqu->freq.m = priv->channel;
-       else
+           priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) {
+               int i;
+
+               i = ieee80211_channel_to_index(priv->ieee, priv->channel);
+               BUG_ON(i == -1);
+               wrqu->freq.e = 1;
+
+               switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
+               case IEEE80211_52GHZ_BAND:
+                       wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000;
+                       break;
+
+               case IEEE80211_24GHZ_BAND:
+                       wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000;
+                       break;
+
+               default:
+                       BUG();
+               }
+       } else
                wrqu->freq.m = 0;
 
        mutex_unlock(&priv->mutex);
@@ -8857,42 +8860,38 @@ static int ipw_wx_set_essid(struct net_device *dev,
                            union iwreq_data *wrqu, char *extra)
 {
        struct ipw_priv *priv = ieee80211_priv(dev);
-       char *essid = "";       /* ANY */
-       int length = 0;
-       mutex_lock(&priv->mutex);
-       if (wrqu->essid.flags && wrqu->essid.length) {
-               length = wrqu->essid.length - 1;
-               essid = extra;
-       }
-       if (length == 0) {
-               IPW_DEBUG_WX("Setting ESSID to ANY\n");
-               if ((priv->config & CFG_STATIC_ESSID) &&
-                   !(priv->status & (STATUS_ASSOCIATED |
-                                     STATUS_ASSOCIATING))) {
-                       IPW_DEBUG_ASSOC("Attempting to associate with new "
-                                       "parameters.\n");
-                       priv->config &= ~CFG_STATIC_ESSID;
-                       ipw_associate(priv);
-               }
-               mutex_unlock(&priv->mutex);
-               return 0;
-       }
+        int length;
 
-       length = min(length, IW_ESSID_MAX_SIZE);
+        mutex_lock(&priv->mutex);
+
+        if (!wrqu->essid.flags)
+        {
+                IPW_DEBUG_WX("Setting ESSID to ANY\n");
+                ipw_disassociate(priv);
+                priv->config &= ~CFG_STATIC_ESSID;
+                ipw_associate(priv);
+                mutex_unlock(&priv->mutex);
+                return 0;
+        }
+
+       length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
+       if (!extra[length - 1])
+               length--;
 
        priv->config |= CFG_STATIC_ESSID;
 
-       if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
+       if (priv->essid_len == length && !memcmp(priv->essid, extra, length)
+           && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) {
                IPW_DEBUG_WX("ESSID set to current ESSID.\n");
                mutex_unlock(&priv->mutex);
                return 0;
        }
 
-       IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
+       IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length),
                     length);
 
        priv->essid_len = length;
-       memcpy(priv->essid, essid, priv->essid_len);
+       memcpy(priv->essid, extra, priv->essid_len);
 
        /* Network configuration changed -- force [re]association */
        IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
@@ -9273,7 +9272,7 @@ static int ipw_wx_set_retry(struct net_device *dev,
        if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
                return 0;
 
-       if (wrqu->retry.value < 0 || wrqu->retry.value > 255)
+       if (wrqu->retry.value < 0 || wrqu->retry.value >= 255)
                return -EINVAL;
 
        mutex_lock(&priv->mutex);
@@ -9396,15 +9395,19 @@ static int ipw_wx_set_scan(struct net_device *dev,
                           union iwreq_data *wrqu, char *extra)
 {
        struct ipw_priv *priv = ieee80211_priv(dev);
-       struct iw_scan_req *req = NULL;
-       if (wrqu->data.length
-           && wrqu->data.length == sizeof(struct iw_scan_req)) {
-               req = (struct iw_scan_req *)extra;
+       struct iw_scan_req *req = (struct iw_scan_req *)extra;
+
+       if (wrqu->data.length == sizeof(struct iw_scan_req)) {
                if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
                        ipw_request_direct_scan(priv, req->essid,
                                                req->essid_len);
                        return 0;
                }
+               if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
+                       queue_work(priv->workqueue,
+                                  &priv->request_passive_scan);
+                       return 0;
+               }
        }
 
        IPW_DEBUG_WX("Start scan\n");
@@ -9766,7 +9769,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
        return 0;
 }
 
-#endif                         // CONFIG_IPW2200_MONITOR
+#endif                         /* CONFIG_IPW2200_MONITOR */
 
 static int ipw_wx_reset(struct net_device *dev,
                        struct iw_request_info *info,
@@ -10009,7 +10012,7 @@ static  void init_sys_config(struct ipw_sys_config *sys_config)
        sys_config->dot11g_auto_detection = 0;
        sys_config->enable_cts_to_self = 0;
        sys_config->bt_coexist_collision_thr = 0;
-       sys_config->pass_noise_stats_to_host = 1;       //1 -- fix for 256
+       sys_config->pass_noise_stats_to_host = 1;       /* 1 -- fix for 256 */
        sys_config->silence_threshold = 0x1e;
 }
 
@@ -10113,7 +10116,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
                switch (priv->ieee->sec.level) {
                case SEC_LEVEL_3:
                        tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
-                           IEEE80211_FCTL_PROTECTED;
+                           cpu_to_le16(IEEE80211_FCTL_PROTECTED);
                        /* XXX: ACK flag must be set for CCMP even if it
                         * is a multicast/broadcast packet, because CCMP
                         * group communication encrypted by GTK is
@@ -10128,14 +10131,14 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
                        break;
                case SEC_LEVEL_2:
                        tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
-                           IEEE80211_FCTL_PROTECTED;
+                           cpu_to_le16(IEEE80211_FCTL_PROTECTED);
                        tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
                        tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP;
                        tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE;
                        break;
                case SEC_LEVEL_1:
                        tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
-                           IEEE80211_FCTL_PROTECTED;
+                           cpu_to_le16(IEEE80211_FCTL_PROTECTED);
                        tfd->u.data.key_index = priv->ieee->tx_keyidx;
                        if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <=
                            40)
@@ -10267,17 +10270,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
 
        /* Filtering of fragment chains is done agains the first fragment */
        hdr = (void *)txb->fragments[0]->data;
-       if (ieee80211_is_management(hdr->frame_ctl)) {
+       if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
                if (filter & IPW_PROM_NO_MGMT)
                        return;
                if (filter & IPW_PROM_MGMT_HEADER_ONLY)
                        hdr_only = 1;
-       } else if (ieee80211_is_control(hdr->frame_ctl)) {
+       } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
                if (filter & IPW_PROM_NO_CTL)
                        return;
                if (filter & IPW_PROM_CTL_HEADER_ONLY)
                        hdr_only = 1;
-       } else if (ieee80211_is_data(hdr->frame_ctl)) {
+       } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
                if (filter & IPW_PROM_NO_DATA)
                        return;
                if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -10292,7 +10295,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
 
                if (hdr_only) {
                        hdr = (void *)src->data;
-                       len = ieee80211_get_hdrlen(hdr->frame_ctl);
+                       len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
                } else
                        len = src->len;
 
@@ -10636,6 +10639,8 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv)
        INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv);
        INIT_WORK(&priv->request_scan,
                  (void (*)(void *))ipw_request_scan, priv);
+       INIT_WORK(&priv->request_passive_scan,
+                 (void (*)(void *))ipw_request_passive_scan, priv);
        INIT_WORK(&priv->gather_stats,
                  (void (*)(void *))ipw_bg_gather_stats, priv);
        INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv);
@@ -11488,9 +11493,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        priv->net_dev = net_dev;
        priv->pci_dev = pdev;
-#ifdef CONFIG_IPW2200_DEBUG
        ipw_debug_level = debug;
-#endif
        spin_lock_init(&priv->irq_lock);
        spin_lock_init(&priv->lock);
        for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
@@ -11755,6 +11758,16 @@ static int ipw_pci_resume(struct pci_dev *pdev)
 }
 #endif
 
+static void ipw_pci_shutdown(struct pci_dev *pdev)
+{
+       struct ipw_priv *priv = pci_get_drvdata(pdev);
+
+       /* Take down the device; powers it off, etc. */
+       ipw_down(priv);
+
+       pci_disable_device(pdev);
+}
+
 /* driver initialization stuff */
 static struct pci_driver ipw_driver = {
        .name = DRV_NAME,
@@ -11765,6 +11778,7 @@ static struct pci_driver ipw_driver = {
        .suspend = ipw_pci_suspend,
        .resume = ipw_pci_resume,
 #endif
+       .shutdown = ipw_pci_shutdown,
 };
 
 static int __init ipw_init(void)
@@ -11808,10 +11822,8 @@ MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
 module_param(led, int, 0444);
 MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n");
 
-#ifdef CONFIG_IPW2200_DEBUG
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
-#endif
 
 module_param(channel, int, 0444);
 MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
index 8b1cd7c749a4e537e434d9d44d3ba0658d4f0efc..dad5eedefbf1c828c20b1c43a755c2c370044ca0 100644 (file)
@@ -713,7 +713,6 @@ struct ipw_rx_packet {
 
 struct ipw_rx_mem_buffer {
        dma_addr_t dma_addr;
-       struct ipw_rx_buffer *rxb;
        struct sk_buff *skb;
        struct list_head list;
 };                             /* Not transferred over network, so not  __attribute__ ((packed)) */
@@ -1297,6 +1296,7 @@ struct ipw_priv {
        struct work_struct system_config;
        struct work_struct rx_replenish;
        struct work_struct request_scan;
+       struct work_struct request_passive_scan;
        struct work_struct adapter_restart;
        struct work_struct rf_kill;
        struct work_struct up;
@@ -1381,13 +1381,18 @@ BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\
 BIT_ARG16(x)
 
 
-#ifdef CONFIG_IPW2200_DEBUG
 #define IPW_DEBUG(level, fmt, args...) \
+do { if (ipw_debug_level & (level)) \
+  printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
+         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#ifdef CONFIG_IPW2200_DEBUG
+#define IPW_LL_DEBUG(level, fmt, args...) \
 do { if (ipw_debug_level & (level)) \
   printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
          in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
 #else
-#define IPW_DEBUG(level, fmt, args...) do {} while (0)
+#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0)
 #endif                         /* CONFIG_IPW2200_DEBUG */
 
 /*
@@ -1457,28 +1462,27 @@ do { if (ipw_debug_level & (level)) \
 
 #define IPW_DEBUG_WX(f, a...)     IPW_DEBUG(IPW_DL_WX, f, ## a)
 #define IPW_DEBUG_SCAN(f, a...)   IPW_DEBUG(IPW_DL_SCAN, f, ## a)
-#define IPW_DEBUG_STATUS(f, a...) IPW_DEBUG(IPW_DL_STATUS, f, ## a)
-#define IPW_DEBUG_TRACE(f, a...)  IPW_DEBUG(IPW_DL_TRACE, f, ## a)
-#define IPW_DEBUG_RX(f, a...)     IPW_DEBUG(IPW_DL_RX, f, ## a)
-#define IPW_DEBUG_TX(f, a...)     IPW_DEBUG(IPW_DL_TX, f, ## a)
-#define IPW_DEBUG_ISR(f, a...)    IPW_DEBUG(IPW_DL_ISR, f, ## a)
+#define IPW_DEBUG_TRACE(f, a...)  IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a)
+#define IPW_DEBUG_RX(f, a...)     IPW_LL_DEBUG(IPW_DL_RX, f, ## a)
+#define IPW_DEBUG_TX(f, a...)     IPW_LL_DEBUG(IPW_DL_TX, f, ## a)
+#define IPW_DEBUG_ISR(f, a...)    IPW_LL_DEBUG(IPW_DL_ISR, f, ## a)
 #define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
-#define IPW_DEBUG_LED(f, a...) IPW_DEBUG(IPW_DL_LED, f, ## a)
-#define IPW_DEBUG_WEP(f, a...)    IPW_DEBUG(IPW_DL_WEP, f, ## a)
-#define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
-#define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a)
-#define IPW_DEBUG_FW(f, a...) IPW_DEBUG(IPW_DL_FW, f, ## a)
+#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a)
+#define IPW_DEBUG_WEP(f, a...)    IPW_LL_DEBUG(IPW_DL_WEP, f, ## a)
+#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
+#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a)
+#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a)
 #define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
 #define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
-#define IPW_DEBUG_IO(f, a...) IPW_DEBUG(IPW_DL_IO, f, ## a)
-#define IPW_DEBUG_ORD(f, a...) IPW_DEBUG(IPW_DL_ORD, f, ## a)
-#define IPW_DEBUG_FW_INFO(f, a...) IPW_DEBUG(IPW_DL_FW_INFO, f, ## a)
+#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a)
+#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a)
+#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a)
 #define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
 #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
 #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a)
-#define IPW_DEBUG_MERGE(f, a...) IPW_DEBUG(IPW_DL_MERGE, f, ## a)
-#define IPW_DEBUG_QOS(f, a...)   IPW_DEBUG(IPW_DL_QOS, f, ## a)
+#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a)
+#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a)
+#define IPW_DEBUG_QOS(f, a...)   IPW_LL_DEBUG(IPW_DL_QOS, f, ## a)
 
 #include <linux/ctype.h>
 
@@ -1947,10 +1951,17 @@ struct host_cmd {
        u32 *param;
 } __attribute__ ((packed));
 
+struct cmdlog_host_cmd {
+       u8 cmd;
+       u8 len;
+       u16 reserved;
+       char param[124];
+} __attribute__ ((packed));
+
 struct ipw_cmd_log {
        unsigned long jiffies;
        int retcode;
-       struct host_cmd cmd;
+       struct cmdlog_host_cmd cmd;
 };
 
 /* SysConfig command parameters ... */
index 317ace7f9aae3af7191323c45953f9416875ed3b..1174ff53e025819b7edb24a20275ddb2cd511498 100644 (file)
@@ -82,6 +82,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
index 16db3e14b7d2d5a115e8572543b7322593d9ed02..fb5700d6c454b8e2cc54d74de8db72c560550a14 100644 (file)
@@ -134,11 +134,7 @@ extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *reg
 /* Locking and synchronization functions                            */
 /********************************************************************/
 
-/* These functions *must* be inline or they will break horribly on
- * SPARC, due to its weird semantics for save/restore flags. extern
- * inline should prevent the kernel from linking or module from
- * loading if they are not inlined. */
-extern inline int orinoco_lock(struct orinoco_private *priv,
+static inline int orinoco_lock(struct orinoco_private *priv,
                               unsigned long *flags)
 {
        spin_lock_irqsave(&priv->lock, *flags);
@@ -151,7 +147,7 @@ extern inline int orinoco_lock(struct orinoco_private *priv,
        return 0;
 }
 
-extern inline void orinoco_unlock(struct orinoco_private *priv,
+static inline void orinoco_unlock(struct orinoco_private *priv,
                                  unsigned long *flags)
 {
        spin_unlock_irqrestore(&priv->lock, *flags);
index 989599ad33ef076e875ad944e41df82345ae19df..0c30fe7e8f7fed8289036584a015f7293315da72 100644 (file)
 
 #include <net/iw_handler.h>    /* New driver API */
 
+#define KEY_SIZE_WEP104 13     /* 104/128-bit WEP keys */
+#define KEY_SIZE_WEP40  5      /* 40/64-bit WEP keys */
+/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
+#define KEY_SIZE_TKIP   32     /* TKIP keys */
 
-static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
                                u8 *wpa_ie, size_t wpa_ie_len);
-static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
 static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
                                __u32 *, char *);
 
@@ -468,6 +472,9 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
        range->event_capa[1] = IW_EVENT_CAPA_K_1;
        range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
 
+       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+               IW_ENC_CAPA_CIPHER_TKIP;
+
        if (islpci_get_state(priv) < PRV_STATE_INIT)
                return 0;
 
@@ -567,6 +574,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
        struct iw_event iwe;    /* Temporary buffer */
        short cap;
        islpci_private *priv = netdev_priv(ndev);
+       u8 wpa_ie[MAX_WPA_IE_LEN];
+       size_t wpa_ie_len;
 
        /* The first entry must be the MAC address */
        memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
@@ -627,27 +636,13 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
        current_ev =
            iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
-       if (priv->wpa) {
-               u8 wpa_ie[MAX_WPA_IE_LEN];
-               char *buf, *p;
-               size_t wpa_ie_len;
-               int i;
-
-               wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
-               if (wpa_ie_len > 0 &&
-                   (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
-                       p = buf;
-                       p += sprintf(p, "wpa_ie=");
-                       for (i = 0; i < wpa_ie_len; i++) {
-                               p += sprintf(p, "%02x", wpa_ie[i]);
-                       }
-                       memset(&iwe, 0, sizeof (iwe));
-                       iwe.cmd = IWEVCUSTOM;
-                       iwe.u.data.length = strlen(buf);
-                       current_ev = iwe_stream_add_point(current_ev, end_buf,
-                                                         &iwe, buf);
-                       kfree(buf);
-               }
+       /* Add WPA/RSN Information Element, if any */
+       wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
+       if (wpa_ie_len > 0) {
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
+               current_ev = iwe_stream_add_point(current_ev, end_buf,
+                               &iwe, wpa_ie);
        }
        return current_ev;
 }
@@ -1051,12 +1046,24 @@ prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
                current_index = r.u;
                /* Verify that the key is not marked as invalid */
                if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
-                       key.length = dwrq->length > sizeof (key.key) ?
-                           sizeof (key.key) : dwrq->length;
-                       memcpy(key.key, extra, key.length);
-                       if (key.length == 32)
-                               /* we want WPA-PSK */
+                       if (dwrq->length > KEY_SIZE_TKIP) {
+                               /* User-provided key data too big */
+                               return -EINVAL;
+                       }
+                       if (dwrq->length > KEY_SIZE_WEP104) {
+                               /* WPA-PSK TKIP */
                                key.type = DOT11_PRIV_TKIP;
+                               key.length = KEY_SIZE_TKIP;
+                       } else if (dwrq->length > KEY_SIZE_WEP40) {
+                               /* WEP 104/128 */
+                               key.length = KEY_SIZE_WEP104;
+                       } else {
+                               /* WEP 40/64 */
+                               key.length = KEY_SIZE_WEP40;
+                       }
+                       memset(key.key, 0, sizeof (key.key));
+                       memcpy(key.key, extra, dwrq->length);
+
                        if ((index < 0) || (index > 3))
                                /* no index provided use the current one */
                                index = current_index;
@@ -1210,6 +1217,489 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
        }
 }
 
+static int prism54_set_genie(struct net_device *ndev,
+                            struct iw_request_info *info,
+                            struct iw_point *data, char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       int alen, ret = 0;
+       struct obj_attachment *attach;
+
+       if (data->length > MAX_WPA_IE_LEN ||
+           (data->length && extra == NULL))
+               return -EINVAL;
+
+       memcpy(priv->wpa_ie, extra, data->length);
+       priv->wpa_ie_len = data->length;
+
+       alen = sizeof(*attach) + priv->wpa_ie_len;
+       attach = kzalloc(alen, GFP_KERNEL);
+       if (attach == NULL)
+               return -ENOMEM;
+
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+       /* Note: endianness is covered by mgt_set_varlen */
+       attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+               (WLAN_FC_STYPE_ASSOC_REQ << 4);
+       attach->id = -1;
+       attach->size = priv->wpa_ie_len;
+       memcpy(attach->data, extra, priv->wpa_ie_len);
+
+       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+               priv->wpa_ie_len);
+       if (ret == 0) {
+               attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+                       (WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+               ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+                       priv->wpa_ie_len);
+               if (ret == 0)
+                       printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+                               ndev->name);
+       }
+
+       kfree(attach);
+       return ret;
+}
+
+
+static int prism54_get_genie(struct net_device *ndev,
+                            struct iw_request_info *info,
+                            struct iw_point *data, char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       int len = priv->wpa_ie_len;
+
+       if (len <= 0) {
+               data->length = 0;
+               return 0;
+       }
+
+       if (data->length < len)
+               return -E2BIG;
+
+       data->length = len;
+       memcpy(extra, priv->wpa_ie, len);
+
+       return 0;
+}
+
+static int prism54_set_auth(struct net_device *ndev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       struct iw_param *param = &wrqu->param;
+       u32 mlmelevel = 0, authen = 0, dot1x = 0;
+       u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
+       u32 old_wpa;
+       int ret = 0;
+       union oid_res_t r;
+
+       if (islpci_get_state(priv) < PRV_STATE_INIT)
+               return 0;
+
+       /* first get the flags */
+       down_write(&priv->mib_sem);
+       wpa = old_wpa = priv->wpa;
+       up_write(&priv->mib_sem);
+       ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+       authen = r.u;
+       ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+       privinvoked = r.u;
+       ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+       exunencrypt = r.u;
+       ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+       dot1x = r.u;
+       ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
+       mlmelevel = r.u;
+
+       if (ret < 0)
+               goto out;
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_KEY_MGMT:
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               /* Do the same thing as IW_AUTH_WPA_VERSION */
+               if (param->value) {
+                       wpa = 1;
+                       privinvoked = 1; /* For privacy invoked */
+                       exunencrypt = 1; /* Filter out all unencrypted frames */
+                       dot1x = 0x01; /* To enable eap filter */
+                       mlmelevel = DOT11_MLME_EXTENDED;
+                       authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+               } else {
+                       wpa = 0;
+                       privinvoked = 0;
+                       exunencrypt = 0; /* Do not filter un-encrypted data */
+                       dot1x = 0;
+                       mlmelevel = DOT11_MLME_AUTO;
+               }
+               break;
+
+       case IW_AUTH_WPA_VERSION:
+               if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
+                       wpa = 0;
+                       privinvoked = 0;
+                       exunencrypt = 0; /* Do not filter un-encrypted data */
+                       dot1x = 0;
+                       mlmelevel = DOT11_MLME_AUTO;
+               } else {
+                       if (param->value & IW_AUTH_WPA_VERSION_WPA)
+                               wpa = 1;
+                       else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
+                               wpa = 2;
+                       privinvoked = 1; /* For privacy invoked */
+                       exunencrypt = 1; /* Filter out all unencrypted frames */
+                       dot1x = 0x01; /* To enable eap filter */
+                       mlmelevel = DOT11_MLME_EXTENDED;
+                       authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+               }
+               break;
+
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+               dot1x = param->value ? 1 : 0;
+               break;
+
+       case IW_AUTH_PRIVACY_INVOKED:
+               privinvoked = param->value ? 1 : 0;
+
+       case IW_AUTH_DROP_UNENCRYPTED:
+               exunencrypt = param->value ? 1 : 0;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+                       /* Only WEP uses _SK and _BOTH */
+                       if (wpa > 0) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       authen = DOT11_AUTH_SK;
+               } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+                       authen = DOT11_AUTH_OS;
+               } else {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       /* Set all the values */
+       down_write(&priv->mib_sem);
+       priv->wpa = wpa;
+       up_write(&priv->mib_sem);
+       mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+       mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
+       mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
+       mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+       mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
+
+out:
+       return ret;
+}
+
+static int prism54_get_auth(struct net_device *ndev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu, char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       struct iw_param *param = &wrqu->param;
+       u32 wpa = 0;
+       int ret = 0;
+       union oid_res_t r;
+
+       if (islpci_get_state(priv) < PRV_STATE_INIT)
+               return 0;
+
+       /* first get the flags */
+       down_write(&priv->mib_sem);
+       wpa = priv->wpa;
+       up_write(&priv->mib_sem);
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_KEY_MGMT:
+               /*
+                * wpa_supplicant will control these internally
+                */
+               ret = -EOPNOTSUPP;
+               break;
+
+       case IW_AUTH_WPA_VERSION:
+               switch (wpa) {
+               case 1:
+                       param->value = IW_AUTH_WPA_VERSION_WPA;
+                       break;
+               case 2:
+                       param->value = IW_AUTH_WPA_VERSION_WPA2;
+                       break;
+               case 0:
+               default:
+                       param->value = IW_AUTH_WPA_VERSION_DISABLED;
+                       break;
+               }
+               break;
+
+       case IW_AUTH_DROP_UNENCRYPTED:
+               ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+               if (ret >= 0)
+                       param->value = r.u > 0 ? 1 : 0;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+               if (ret >= 0) {
+                       switch (r.u) {
+                       case DOT11_AUTH_OS:
+                               param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+                               break;
+                       case DOT11_AUTH_BOTH:
+                       case DOT11_AUTH_SK:
+                               param->value = IW_AUTH_ALG_SHARED_KEY;
+                       case DOT11_AUTH_NONE:
+                       default:
+                               param->value = 0;
+                               break;
+                       }
+               }
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               param->value = wpa > 0 ? 1 : 0;
+               break;
+
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+               ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+               if (ret >= 0)
+                       param->value = r.u > 0 ? 1 : 0;
+               break;
+
+       case IW_AUTH_PRIVACY_INVOKED:
+               ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+               if (ret >= 0)
+                       param->value = r.u > 0 ? 1 : 0;
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return ret;
+}
+
+static int prism54_set_encodeext(struct net_device *ndev,
+                                struct iw_request_info *info,
+                                union iwreq_data *wrqu,
+                                char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int idx, alg = ext->alg, set_key = 1;
+       union oid_res_t r;
+       int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+       int ret = 0;
+
+       if (islpci_get_state(priv) < PRV_STATE_INIT)
+               return 0;
+
+       /* Determine and validate the key index */
+       idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+       if (idx) {
+               if (idx < 0 || idx > 3)
+                       return -EINVAL;
+       } else {
+               ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+               if (ret < 0)
+                       goto out;
+               idx = r.u;
+       }
+
+       if (encoding->flags & IW_ENCODE_DISABLED)
+               alg = IW_ENCODE_ALG_NONE;
+
+       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+               /* Only set transmit key index here, actual
+                * key is set below if needed.
+                */
+               ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
+               set_key = ext->key_len > 0 ? 1 : 0;
+       }
+
+       if (set_key) {
+               struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
+               switch (alg) {
+               case IW_ENCODE_ALG_NONE:
+                       break;
+               case IW_ENCODE_ALG_WEP:
+                       if (ext->key_len > KEY_SIZE_WEP104) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       if (ext->key_len > KEY_SIZE_WEP40)
+                               key.length = KEY_SIZE_WEP104;
+                       else
+                               key.length = KEY_SIZE_WEP40;
+                       break;
+               case IW_ENCODE_ALG_TKIP:
+                       if (ext->key_len > KEY_SIZE_TKIP) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       key.type = DOT11_PRIV_TKIP;
+                       key.length = KEY_SIZE_TKIP;
+               default:
+                       return -EINVAL;
+               }
+
+               if (key.length) {
+                       memset(key.key, 0, sizeof(key.key));
+                       memcpy(key.key, ext->key, ext->key_len);
+                       ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
+                                           &key);
+                       if (ret < 0)
+                               goto out;
+               }
+       }
+
+       /* Read the flags */
+       if (encoding->flags & IW_ENCODE_DISABLED) {
+               /* Encoding disabled,
+                * authen = DOT11_AUTH_OS;
+                * invoke = 0;
+                * exunencrypt = 0; */
+       }
+       if (encoding->flags & IW_ENCODE_OPEN) {
+               /* Encode but accept non-encoded packets. No auth */
+               invoke = 1;
+       }
+       if (encoding->flags & IW_ENCODE_RESTRICTED) {
+               /* Refuse non-encoded packets. Auth */
+               authen = DOT11_AUTH_BOTH;
+               invoke = 1;
+               exunencrypt = 1;
+       }
+
+       /* do the change if requested  */
+       if (encoding->flags & IW_ENCODE_MODE) {
+               ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
+                                     &authen);
+               ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
+                                     &invoke);
+               ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+                                     &exunencrypt);
+       }
+
+out:
+       return ret;
+}
+
+
+static int prism54_get_encodeext(struct net_device *ndev,
+                                struct iw_request_info *info,
+                                union iwreq_data *wrqu,
+                                char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int idx, max_key_len;
+       union oid_res_t r;
+       int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
+       int ret = 0;
+
+       if (islpci_get_state(priv) < PRV_STATE_INIT)
+               return 0;
+
+       /* first get the flags */
+       ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+       authen = r.u;
+       ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+       invoke = r.u;
+       ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+       exunencrypt = r.u;
+       if (ret < 0)
+               goto out;
+
+       max_key_len = encoding->length - sizeof(*ext);
+       if (max_key_len < 0)
+               return -EINVAL;
+
+       idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+       if (idx) {
+               if (idx < 0 || idx > 3)
+                       return -EINVAL;
+       } else {
+               ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+               if (ret < 0)
+                       goto out;
+               idx = r.u;
+       }
+
+       encoding->flags = idx + 1;
+       memset(ext, 0, sizeof(*ext));
+
+       switch (authen) {
+       case DOT11_AUTH_BOTH:
+       case DOT11_AUTH_SK:
+               wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
+       case DOT11_AUTH_OS:
+       default:
+               wrqu->encoding.flags |= IW_ENCODE_OPEN;
+               break;
+       }
+
+       down_write(&priv->mib_sem);
+       wpa = priv->wpa;
+       up_write(&priv->mib_sem);
+
+       if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
+               /* No encryption */
+               ext->alg = IW_ENCODE_ALG_NONE;
+               ext->key_len = 0;
+               wrqu->encoding.flags |= IW_ENCODE_DISABLED;
+       } else {
+               struct obj_key *key;
+
+               ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
+               if (ret < 0)
+                       goto out;
+               key = r.ptr;
+               if (max_key_len < key->length) {
+                       ret = -E2BIG;
+                       goto out;
+               }
+               memcpy(ext->key, key->key, key->length);
+               ext->key_len = key->length;
+
+               switch (key->type) {
+               case DOT11_PRIV_TKIP:
+                       ext->alg = IW_ENCODE_ALG_TKIP;
+                       break;
+               default:
+               case DOT11_PRIV_WEP:
+                       ext->alg = IW_ENCODE_ALG_WEP;
+                       break;
+               }
+               wrqu->encoding.flags |= IW_ENCODE_ENABLED;
+       }
+
+out:
+       return ret;
+}
+
+
 static int
 prism54_reset(struct net_device *ndev, struct iw_request_info *info,
              __u32 * uwrq, char *extra)
@@ -1591,8 +2081,8 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 
 static void
-prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
-                  u8 *wpa_ie, size_t wpa_ie_len)
+prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
+                      u8 *wpa_ie, size_t wpa_ie_len)
 {
        struct list_head *ptr;
        struct islpci_bss_wpa_ie *bss = NULL;
@@ -1658,7 +2148,7 @@ prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
 }
 
 static size_t
-prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
 {
        struct list_head *ptr;
        struct islpci_bss_wpa_ie *bss = NULL;
@@ -1683,14 +2173,14 @@ prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
 }
 
 void
-prism54_wpa_ie_init(islpci_private *priv)
+prism54_wpa_bss_ie_init(islpci_private *priv)
 {
        INIT_LIST_HEAD(&priv->bss_wpa_list);
        sema_init(&priv->wpa_sem, 1);
 }
 
 void
-prism54_wpa_ie_clean(islpci_private *priv)
+prism54_wpa_bss_ie_clean(islpci_private *priv)
 {
        struct list_head *ptr, *n;
 
@@ -1722,7 +2212,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
                }
                if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
                    memcmp(pos + 2, wpa_oid, 4) == 0) {
-                       prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
+                       prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
                        return;
                }
                pos += 2 + pos[1];
@@ -1879,7 +2369,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
                send_formatted_event(priv, "Associate request (ex)", mlme, 1);
 
                if (priv->iw_mode != IW_MODE_MASTER 
-                               && mlmeex->state != DOT11_STATE_AUTHING)
+                               && mlmeex->state != DOT11_STATE_ASSOCING)
                        break;
                
                confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
@@ -1893,7 +2383,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
                confirm->state = 0; /* not used */
                confirm->code = 0;
 
-               wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+               wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
                if (!wpa_ie_len) {
                        printk(KERN_DEBUG "No WPA IE found from "
@@ -1937,7 +2427,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
                confirm->state = 0; /* not used */
                confirm->code = 0;
 
-               wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+               wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
                if (!wpa_ie_len) {
                        printk(KERN_DEBUG "No WPA IE found from "
@@ -2553,6 +3043,15 @@ static const iw_handler prism54_handler[] = {
        (iw_handler) prism54_get_encode,        /* SIOCGIWENCODE */
        (iw_handler) NULL,      /* SIOCSIWPOWER */
        (iw_handler) NULL,      /* SIOCGIWPOWER */
+       NULL,                   /* -- hole -- */
+       NULL,                   /* -- hole -- */
+       (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */
+       (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */
+       (iw_handler) prism54_set_auth,  /* SIOCSIWAUTH */
+       (iw_handler) prism54_get_auth,  /* SIOCGIWAUTH */
+       (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
+       (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
+       NULL,                   /* SIOCSIWPMKSA */
 };
 
 /* The low order bit identify a SET (0) or a GET (1) ioctl.  */
index 46d5cde80c85e7f738c3e73ccaedf7b9c52224ca..65f33acd0a4275ffd6402f492dc3722ba36b42d8 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <net/iw_handler.h>    /* New driver API */
 
-#define SUPPORTED_WIRELESS_EXT                  16
+#define SUPPORTED_WIRELESS_EXT                  19
 
 void prism54_mib_init(islpci_private *);
 
@@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl *);
 
 void prism54_process_trap(void *);
 
-void prism54_wpa_ie_init(islpci_private *priv);
-void prism54_wpa_ie_clean(islpci_private *priv);
+void prism54_wpa_bss_ie_init(islpci_private *priv);
+void prism54_wpa_bss_ie_clean(islpci_private *priv);
 
 int prism54_set_mac_address(struct net_device *, void *);
 
index 5ddf295990321b4bb466241e73481947ccab9897..ab3c5a27efd902515854f2f3dbf1f6e7945cc596 100644 (file)
@@ -715,7 +715,7 @@ islpci_alloc_memory(islpci_private *priv)
        }
 
        prism54_acl_init(&priv->acl);
-       prism54_wpa_ie_init(priv);
+       prism54_wpa_bss_ie_init(priv);
        if (mgt_init(priv)) 
                goto out_free;
 
@@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv)
 
        /* Free the acces control list and the WPA list */
        prism54_acl_clean(&priv->acl);
-       prism54_wpa_ie_clean(priv);
+       prism54_wpa_bss_ie_clean(priv);
        mgt_clean(priv);
 
        return 0;
index 07053165e4c587b121bcdcfa5cfe9bed1a877c22..5049f37455b1606fd1240f55f08134900359d09a 100644 (file)
@@ -179,6 +179,8 @@ typedef struct {
        struct list_head bss_wpa_list;
        int num_bss_wpa;
        struct semaphore wpa_sem;
+       u8 wpa_ie[MAX_WPA_IE_LEN];
+       size_t wpa_ie_len;
 
        struct work_struct reset_task;
        int reset_task_pending;
index 61b83a5e737a719719646d37a4ff76d03b9fd949..8e112d139e297417548bf5cd7801509504d2104e 100644 (file)
@@ -52,8 +52,8 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/mem_op.h>
 
-#include <net/ieee80211.h>
 #include <linux/wireless.h>
+#include <net/iw_handler.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
index 500314fc74d2abdf68d6af9cfa0614ce2cb436ec..6603ad5be63d09a3752913775034ce570c141797 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o
 zd1211rw-objs := zd_chip.o zd_ieee80211.o \
                zd_mac.o zd_netdev.o \
                zd_rf_al2230.o zd_rf_rf2959.o \
+               zd_rf_al7230b.o \
                zd_rf.o zd_usb.o zd_util.o
 
 ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
index da9d06bdb818a22089f623650e094a8e74c63b53..58419985e00fa156eb1e37623b711a6b69d68428 100644 (file)
@@ -42,12 +42,11 @@ void zd_chip_init(struct zd_chip *chip,
 
 void zd_chip_clear(struct zd_chip *chip)
 {
-       mutex_lock(&chip->mutex);
+       ZD_ASSERT(!mutex_is_locked(&chip->mutex));
        zd_usb_clear(&chip->usb);
        zd_rf_clear(&chip->rf);
-       mutex_unlock(&chip->mutex);
        mutex_destroy(&chip->mutex);
-       memset(chip, 0, sizeof(*chip));
+       ZD_MEMCLEAR(chip, sizeof(*chip));
 }
 
 static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
@@ -68,10 +67,11 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
        i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
        i += scnprintf(buffer+i, size-i, " ");
        i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
-       i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c", chip->pa_type,
+       i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
                chip->patch_cck_gain ? 'g' : '-',
                chip->patch_cr157 ? '7' : '-',
-               chip->patch_6m_band_edge ? '6' : '-');
+               chip->patch_6m_band_edge ? '6' : '-',
+               chip->new_phy_layout ? 'N' : '-');
        return i;
 }
 
@@ -330,13 +330,14 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type)
        chip->patch_cck_gain = (value >> 8) & 0x1;
        chip->patch_cr157 = (value >> 13) & 0x1;
        chip->patch_6m_band_edge = (value >> 21) & 0x1;
+       chip->new_phy_layout = (value >> 31) & 0x1;
 
        dev_dbg_f(zd_chip_dev(chip),
                "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
-               "patch 6M %d\n",
+               "patch 6M %d new PHY %d\n",
                zd_rf_name(*rf_type), *rf_type,
                chip->pa_type, chip->patch_cck_gain,
-               chip->patch_cr157, chip->patch_6m_band_edge);
+               chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout);
        return 0;
 error:
        *rf_type = 0;
@@ -344,6 +345,7 @@ error:
        chip->patch_cck_gain = 0;
        chip->patch_cr157 = 0;
        chip->patch_6m_band_edge = 0;
+       chip->new_phy_layout = 0;
        return r;
 }
 
@@ -717,7 +719,7 @@ static int zd1211b_hw_reset_phy(struct zd_chip *chip)
                { CR21,  0x0e }, { CR22,  0x23 }, { CR23,  0x90 },
                { CR24,  0x14 }, { CR25,  0x40 }, { CR26,  0x10 },
                { CR27,  0x10 }, { CR28,  0x7f }, { CR29,  0x80 },
-               { CR30,  0x49 }, /* jointly decoder, no ASIC */
+               { CR30,  0x4b }, /* ASIC/FWT, no jointly decoder */
                { CR31,  0x60 }, { CR32,  0x43 }, { CR33,  0x08 },
                { CR34,  0x06 }, { CR35,  0x0a }, { CR36,  0x00 },
                { CR37,  0x00 }, { CR38,  0x38 }, { CR39,  0x0c },
@@ -807,7 +809,6 @@ static int zd1211_hw_init_hmac(struct zd_chip *chip)
                { CR_ACK_TIMEOUT_EXT,           0x80 },
                { CR_ADDA_PWR_DWN,              0x00 },
                { CR_ACK_TIME_80211,            0x100 },
-               { CR_IFS_VALUE,                 0x547c032 },
                { CR_RX_PE_DELAY,               0x70 },
                { CR_PS_CTRL,                   0x10000000 },
                { CR_RTS_CTS_RATE,              0x02030203 },
@@ -854,11 +855,10 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
                { CR_ACK_TIMEOUT_EXT,           0x80 },
                { CR_ADDA_PWR_DWN,              0x00 },
                { CR_ACK_TIME_80211,            0x100 },
-               { CR_IFS_VALUE,                 0x547c032 },
                { CR_RX_PE_DELAY,               0x70 },
                { CR_PS_CTRL,                   0x10000000 },
                { CR_RTS_CTS_RATE,              0x02030203 },
-               { CR_RX_THRESHOLD,              0x000c0640 },
+               { CR_RX_THRESHOLD,              0x000c0eff, },
                { CR_AFTER_PNP,                 0x1 },
                { CR_WEP_PROTECT,               0x114 },
        };
@@ -970,10 +970,15 @@ static int hw_init(struct zd_chip *chip)
        r = hw_init_hmac(chip);
        if (r)
                return r;
-       r = set_beacon_interval(chip, 100);
+
+       /* Although the vendor driver defaults to a different value during
+        * init, it overwrites the IFS value with the following every time
+        * the channel changes. We should aim to be more intelligent... */
+       r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
        if (r)
                return r;
-       return 0;
+
+       return set_beacon_interval(chip, 100);
 }
 
 #ifdef DEBUG
@@ -1613,3 +1618,34 @@ int zd_rfwritev_locked(struct zd_chip *chip,
 
        return 0;
 }
+
+/*
+ * We can optionally program the RF directly through CR regs, if supported by
+ * the hardware. This is much faster than the older method.
+ */
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
+{
+       struct zd_ioreq16 ioreqs[] = {
+               { CR244, (value >> 16) & 0xff },
+               { CR243, (value >>  8) & 0xff },
+               { CR242,  value        & 0xff },
+       };
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+                         const u32 *values, unsigned int count)
+{
+       int r;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               r = zd_rfwrite_cr_locked(chip, values[i]);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
index 069d2b467339828d1213748cd591b4c3f0aa49a0..4b12508598972a65040a44987e43531912a71003 100644 (file)
 
 #define CR_ACK_TIMEOUT_EXT             CTL_REG(0x0690)
 #define CR_BCN_FIFO_SEMAPHORE          CTL_REG(0x0694)
+
 #define CR_IFS_VALUE                   CTL_REG(0x0698)
+#define IFS_VALUE_DIFS_SH              0
+#define IFS_VALUE_EIFS_SH              12
+#define IFS_VALUE_SIFS_SH              24
+#define IFS_VALUE_DEFAULT              ((  50 << IFS_VALUE_DIFS_SH) | \
+                                        (1148 << IFS_VALUE_EIFS_SH) | \
+                                        (  10 << IFS_VALUE_SIFS_SH))
+
 #define CR_RX_TIME_OUT                 CTL_REG(0x069C)
 #define CR_TOTAL_RX_FRM                        CTL_REG(0x06A0)
 #define CR_CRC32_CNT                   CTL_REG(0x06A4)
@@ -630,6 +638,7 @@ enum {
        LOAD_CODE_SIZE                  = 0xe, /* words */
        LOAD_VECT_SIZE                  = 0x10000 - 0xfff7, /* words */
        EEPROM_REGS_OFFSET              = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+       EEPROM_REGS_SIZE                = 0x7e, /* words */
        E2P_BASE_OFFSET                 = EEPROM_START_OFFSET +
                                          EEPROM_REGS_OFFSET,
 };
@@ -655,7 +664,7 @@ struct zd_chip {
        /* SetPointOFDM in the vendor driver */
        u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
        u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
-          is_zd1211b:1;
+          new_phy_layout:1, is_zd1211b:1;
 };
 
 static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
@@ -739,8 +748,12 @@ static inline int zd_rfwrite_locked(struct zd_chip *chip, u32 value, u8 bits)
        return zd_usb_rfwrite(&chip->usb, value, bits);
 }
 
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value);
+
 int zd_rfwritev_locked(struct zd_chip *chip,
                       const u32* values, unsigned int count, u8 bits);
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+                         const u32* values, unsigned int count);
 
 /* Locking functions for reading and writing registers.
  * The different parameters are intentional.
index 465906812fc436b12f23c7d00c52c5bdde5dc19e..a13ec72eb3041ab8e8a4bc802f53ef9cde2d311d 100644 (file)
@@ -45,4 +45,10 @@ do { \
 #  define ZD_ASSERT(x) do { } while (0)
 #endif
 
+#ifdef DEBUG
+#  define ZD_MEMCLEAR(pointer, size) memset((pointer), 0xff, (size))
+#else
+#  define ZD_MEMCLEAR(pointer, size) do { } while (0)
+#endif
+
 #endif /* _ZD_DEF_H */
index d6f3e02a0b54e5925e67b08a3039ffdcb9136ccc..0eda534a648cf30ef2129a81985f1929fbfd22a5 100644 (file)
@@ -127,11 +127,9 @@ out:
 
 void zd_mac_clear(struct zd_mac *mac)
 {
-       /* Aquire the lock. */
-       spin_lock(&mac->lock);
-       spin_unlock(&mac->lock);
        zd_chip_clear(&mac->chip);
-       memset(mac, 0, sizeof(*mac));
+       ZD_ASSERT(!spin_is_locked(&mac->lock));
+       ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
 }
 
 static int reset_mode(struct zd_mac *mac)
index 71e382c589ee5ce473d0b69ec95e3cad5b4f309b..082bcf8ec8dc6fd5d69ad4911892b75397a45c34 100644 (file)
@@ -121,9 +121,9 @@ enum mac_flags {
 };
 
 struct zd_mac {
-       struct net_device *netdev;
        struct zd_chip chip;
        spinlock_t lock;
+       struct net_device *netdev;
        /* Unlocked reading possible */
        struct iw_statistics iw_stats;
        u8 qual_average;
index 9df232c2c86311ada4a7fb60dad6d10714a40136..440ef24b5fd10a445c525093bf799a65c6d348c4 100644 (file)
@@ -72,10 +72,18 @@ static int iw_get_name(struct net_device *netdev,
                       struct iw_request_info *info,
                       union iwreq_data *req, char *extra)
 {
-       /* FIXME: check whether 802.11a will also supported, add also
-        *        zd1211B, if we support it.
-        */
-       strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
+       /* FIXME: check whether 802.11a will also supported */
+       strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
+       return 0;
+}
+
+static int iw_get_nick(struct net_device *netdev,
+                      struct iw_request_info *info,
+                      union iwreq_data *req, char *extra)
+{
+       strcpy(extra, "zd1211");
+       req->data.length = strlen(extra) + 1;
+       req->data.flags = 1;
        return 0;
 }
 
@@ -181,6 +189,7 @@ static int iw_get_encodeext(struct net_device *netdev,
 
 static const iw_handler zd_standard_iw_handlers[] = {
        WX(SIOCGIWNAME)         = iw_get_name,
+       WX(SIOCGIWNICKN)        = iw_get_nick,
        WX(SIOCSIWFREQ)         = iw_set_freq,
        WX(SIOCGIWFREQ)         = iw_get_freq,
        WX(SIOCSIWMODE)         = iw_set_mode,
index d3770d2c61bca32bd40ca6b7f7e27fc51613714a..f50cff3db9164e26658b34302295f9cecbf70abe 100644 (file)
@@ -56,7 +56,7 @@ void zd_rf_init(struct zd_rf *rf)
 
 void zd_rf_clear(struct zd_rf *rf)
 {
-       memset(rf, 0, sizeof(*rf));
+       ZD_MEMCLEAR(rf, sizeof(*rf));
 }
 
 int zd_rf_init_hw(struct zd_rf *rf, u8 type)
@@ -76,6 +76,11 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
                if (r)
                        return r;
                break;
+       case AL7230B_RF:
+               r = zd_rf_init_al7230b(rf);
+               if (r)
+                       return r;
+               break;
        default:
                dev_err(zd_chip_dev(chip),
                        "RF %s %#x is not supported\n", zd_rf_name(type), type);
index ea30f693fcc8690512b7d25c4431c58ae3fe66d9..676b3734f1edd96e673a4aa7efbbd9269d0c78e5 100644 (file)
@@ -78,5 +78,6 @@ int zd_switch_radio_off(struct zd_rf *rf);
 
 int zd_rf_init_rf2959(struct zd_rf *rf);
 int zd_rf_init_al2230(struct zd_rf *rf);
+int zd_rf_init_al7230b(struct zd_rf *rf);
 
 #endif /* _ZD_RF_H */
index 0948b25f660d44e91277ad226ab4e7d25779f097..25323a13a3dbe97e2967ab253e8c1f01900135b3 100644 (file)
@@ -21,7 +21,7 @@
 #include "zd_usb.h"
 #include "zd_chip.h"
 
-static const u32 al2230_table[][3] = {
+static const u32 zd1211_al2230_table[][3] = {
        RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
        RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
        RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
@@ -38,6 +38,53 @@ static const u32 al2230_table[][3] = {
        RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
 };
 
+static const u32 zd1211b_al2230_table[][3] = {
+       RF_CHANNEL( 1) = { 0x09efc0, 0x8cccc0, 0xb00000, },
+       RF_CHANNEL( 2) = { 0x09efc0, 0x8cccd0, 0xb00000, },
+       RF_CHANNEL( 3) = { 0x09e7c0, 0x8cccc0, 0xb00000, },
+       RF_CHANNEL( 4) = { 0x09e7c0, 0x8cccd0, 0xb00000, },
+       RF_CHANNEL( 5) = { 0x05efc0, 0x8cccc0, 0xb00000, },
+       RF_CHANNEL( 6) = { 0x05efc0, 0x8cccd0, 0xb00000, },
+       RF_CHANNEL( 7) = { 0x05e7c0, 0x8cccc0, 0xb00000, },
+       RF_CHANNEL( 8) = { 0x05e7c0, 0x8cccd0, 0xb00000, },
+       RF_CHANNEL( 9) = { 0x0defc0, 0x8cccc0, 0xb00000, },
+       RF_CHANNEL(10) = { 0x0defc0, 0x8cccd0, 0xb00000, },
+       RF_CHANNEL(11) = { 0x0de7c0, 0x8cccc0, 0xb00000, },
+       RF_CHANNEL(12) = { 0x0de7c0, 0x8cccd0, 0xb00000, },
+       RF_CHANNEL(13) = { 0x03efc0, 0x8cccc0, 0xb00000, },
+       RF_CHANNEL(14) = { 0x03e7c0, 0x866660, 0xb00000, },
+};
+
+static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
+       { CR240, 0x57 }, { CR9,   0xe0 },
+};
+
+static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
+{
+       int r;
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
+               { CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
+               { CR203, 0x06 },
+               { },
+
+               { CR240, 0x80 },
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               return r;
+
+       /* related to antenna selection? */
+       if (chip->new_phy_layout) {
+               r = zd_iowrite16_locked(chip, 0xe1, CR9);
+               if (r)
+                       return r;
+       }
+
+       return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
 static int zd1211_al2230_init_hw(struct zd_rf *rf)
 {
        int r;
@@ -139,7 +186,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
                { CR47,  0x1e },
 
                /* ZD1211B 05.06.10 */
-               { CR48,  0x00 }, { CR49,  0x00 }, { CR51,  0x01 },
+               { CR48,  0x06 }, { CR49,  0xf9 }, { CR51,  0x01 },
                { CR52,  0x80 }, { CR53,  0x7e }, { CR65,  0x00 },
                { CR66,  0x00 }, { CR67,  0x00 }, { CR68,  0x00 },
                { CR69,  0x28 },
@@ -172,79 +219,78 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
                { CR137, 0x50 }, /* 5614 */
                { CR138, 0xa8 },
                { CR144, 0xac }, /* 5621 */
-               { CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
+               { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 },
        };
 
        static const u32 rv1[] = {
-               /* channel 1 */
-               0x03f790,
-               0x033331,
-               0x00000d,
-
-               0x0b3331,
-               0x03b812,
-               0x00fff3,
-               0x0005a4,
-               0x0f4dc5, /* fix freq shift 0x044dc5 */
-               0x0805b6,
-               0x0146c7,
-               0x000688,
-               0x0403b9, /* External control TX power (CR31) */
-               0x00dbba,
-               0x00099b,
-               0x0bdffc,
-               0x00000d,
-               0x00580f,
+               0x8cccd0,
+               0x481dc0,
+               0xcfff00,
+               0x25a000,
+
+               /* To improve AL2230 yield, improve phase noise, 4713 */
+               0x25a000,
+               0xa3b2f0,
+
+               0x6da010, /* Reg6 update for MP versio */
+               0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */
+               0x116000,
+               0x9dc020, /* External control TX power (CR31) */
+               0x5ddb00, /* RegA update for MP version */
+               0xd99000, /* RegB update for MP version */
+               0x3ffbd0, /* RegC update for MP version */
+               0xb00000, /* RegD update for MP version */
+
+               /* improve phase noise and remove phase calibration,4713 */
+               0xf01a00,
        };
 
        static const struct zd_ioreq16 ioreqs2[] = {
-               { CR47,  0x1e }, { CR_RFCFG, 0x03 },
+               { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
+               { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
        };
 
        static const u32 rv2[] = {
-               0x00880f,
-               0x00080f,
+               /* To improve AL2230 yield, 4713 */
+               0xf01b00,
+               0xf01e00,
+               0xf01a00,
        };
 
        static const struct zd_ioreq16 ioreqs3[] = {
-               { CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
-       };
-
-       static const u32 rv3[] = {
-               0x00d80f,
-               0x00780f,
-               0x00580f,
-       };
-
-       static const struct zd_ioreq16 ioreqs4[] = {
-               { CR138, 0x28 }, { CR203, 0x06 },
+               /* related to 6M band edge patching, happens unconditionally */
+               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
        };
 
+       r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+               ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+       if (r)
+               return r;
        r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
        if (r)
                return r;
-       r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+       r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
        if (r)
                return r;
-       r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+       r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
        if (r)
                return r;
-       r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+       r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
        if (r)
                return r;
-       r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+       r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
        if (r)
                return r;
-       r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
+       r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
        if (r)
                return r;
-       return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
+       return zd1211b_al2230_finalize_rf(chip);
 }
 
-static int al2230_set_channel(struct zd_rf *rf, u8 channel)
+static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel)
 {
        int r;
-       const u32 *rv = al2230_table[channel-1];
+       const u32 *rv = zd1211_al2230_table[channel-1];
        struct zd_chip *chip = zd_rf_to_chip(rf);
        static const struct zd_ioreq16 ioreqs[] = {
                { CR138, 0x28 },
@@ -257,6 +303,24 @@ static int al2230_set_channel(struct zd_rf *rf, u8 channel)
        return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
+static int zd1211b_al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+       int r;
+       const u32 *rv = zd1211b_al2230_table[channel-1];
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+               ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+       if (r)
+               return r;
+
+       r = zd_rfwritev_cr_locked(chip, rv, 3);
+       if (r)
+               return r;
+
+       return zd1211b_al2230_finalize_rf(chip);
+}
+
 static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
 {
        struct zd_chip *chip = zd_rf_to_chip(rf);
@@ -294,13 +358,14 @@ int zd_rf_init_al2230(struct zd_rf *rf)
 {
        struct zd_chip *chip = zd_rf_to_chip(rf);
 
-       rf->set_channel = al2230_set_channel;
        rf->switch_radio_off = al2230_switch_radio_off;
        if (chip->is_zd1211b) {
                rf->init_hw = zd1211b_al2230_init_hw;
+               rf->set_channel = zd1211b_al2230_set_channel;
                rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
        } else {
                rf->init_hw = zd1211_al2230_init_hw;
+               rf->set_channel = zd1211_al2230_set_channel;
                rf->switch_radio_on = zd1211_al2230_switch_radio_on;
        }
        rf->patch_6m_band_edge = 1;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
new file mode 100644 (file)
index 0000000..a289f95
--- /dev/null
@@ -0,0 +1,274 @@
+/* zd_rf_al7230b.c: Functions for the AL7230B RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 chan_rv[][2] = {
+       RF_CHANNEL( 1) = { 0x09ec00, 0x8cccc8 },
+       RF_CHANNEL( 2) = { 0x09ec00, 0x8cccd8 },
+       RF_CHANNEL( 3) = { 0x09ec00, 0x8cccc0 },
+       RF_CHANNEL( 4) = { 0x09ec00, 0x8cccd0 },
+       RF_CHANNEL( 5) = { 0x05ec00, 0x8cccc8 },
+       RF_CHANNEL( 6) = { 0x05ec00, 0x8cccd8 },
+       RF_CHANNEL( 7) = { 0x05ec00, 0x8cccc0 },
+       RF_CHANNEL( 8) = { 0x05ec00, 0x8cccd0 },
+       RF_CHANNEL( 9) = { 0x0dec00, 0x8cccc8 },
+       RF_CHANNEL(10) = { 0x0dec00, 0x8cccd8 },
+       RF_CHANNEL(11) = { 0x0dec00, 0x8cccc0 },
+       RF_CHANNEL(12) = { 0x0dec00, 0x8cccd0 },
+       RF_CHANNEL(13) = { 0x03ec00, 0x8cccc8 },
+       RF_CHANNEL(14) = { 0x03ec00, 0x866660 },
+};
+
+static const u32 std_rv[] = {
+       0x4ff821,
+       0xc5fbfc,
+       0x21ebfe,
+       0xafd401, /* freq shift 0xaad401 */
+       0x6cf56a,
+       0xe04073,
+       0x193d76,
+       0x9dd844,
+       0x500007,
+       0xd8c010,
+};
+
+static int al7230b_init_hw(struct zd_rf *rf)
+{
+       int i, r;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       /* All of these writes are identical to AL2230 unless otherwise
+        * specified */
+       static const struct zd_ioreq16 ioreqs_1[] = {
+               /* This one is 7230-specific, and happens before the rest */
+               { CR240,  0x57 },
+               { },
+
+               { CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
+               { CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
+               { CR44,   0x33 },
+               /* This value is different for 7230 (was: 0x2a) */
+               { CR106,  0x22 },
+               { CR107,  0x1a }, { CR109,  0x09 }, { CR110,  0x27 },
+               { CR111,  0x2b }, { CR112,  0x2b }, { CR119,  0x0a },
+               /* This happened further down in AL2230,
+                * and the value changed (was: 0xe0) */
+               { CR122,  0xfc },
+               { CR10,   0x89 },
+               /* for newest (3rd cut) AL2300 */
+               { CR17,   0x28 },
+               { CR26,   0x93 }, { CR34,   0x30 },
+               /* for newest (3rd cut) AL2300 */
+               { CR35,   0x3e },
+               { CR41,   0x24 }, { CR44,   0x32 },
+               /* for newest (3rd cut) AL2300 */
+               { CR46,   0x96 },
+               { CR47,   0x1e }, { CR79,   0x58 }, { CR80,  0x30 },
+               { CR81,   0x30 }, { CR87,   0x0a }, { CR89,  0x04 },
+               { CR92,   0x0a }, { CR99,   0x28 },
+               /* This value is different for 7230 (was: 0x00) */
+               { CR100,  0x02 },
+               { CR101,  0x13 }, { CR102,  0x27 },
+               /* This value is different for 7230 (was: 0x24) */
+               { CR106,  0x22 },
+               /* This value is different for 7230 (was: 0x2a) */
+               { CR107,  0x3f },
+               { CR109,  0x09 },
+               /* This value is different for 7230 (was: 0x13) */
+               { CR110,  0x1f },
+               { CR111,  0x1f }, { CR112,  0x1f }, { CR113, 0x27 },
+               { CR114,  0x27 },
+               /* for newest (3rd cut) AL2300 */
+               { CR115,  0x24 },
+               /* This value is different for 7230 (was: 0x24) */
+               { CR116,  0x3f },
+               /* This value is different for 7230 (was: 0xf4) */
+               { CR117,  0xfa },
+               { CR118,  0xfc }, { CR119,  0x10 }, { CR120, 0x4f },
+               { CR121,  0x77 }, { CR137,  0x88 },
+               /* This one is 7230-specific */
+               { CR138,  0xa8 },
+               /* This value is different for 7230 (was: 0xff) */
+               { CR252,  0x34 },
+               /* This value is different for 7230 (was: 0xff) */
+               { CR253,  0x34 },
+
+               /* PLL_OFF */
+               { CR251, 0x2f },
+       };
+
+       static const struct zd_ioreq16 ioreqs_2[] = {
+               /* PLL_ON */
+               { CR251, 0x3f },
+               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+               { CR38, 0x38 }, { CR136, 0xdf },
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+       if (r)
+               return r;
+
+       r = zd_rfwrite_cr_locked(chip, 0x09ec04);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+       if (r)
+               return r;
+
+       for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+               r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+               if (r)
+                       return r;
+       }
+
+       r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0x700000);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+       if (r)
+               return r;
+
+       r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+       if (r)
+               return r;
+
+       r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+       if (r)
+               return r;
+
+       r = zd_iowrite16_locked(chip, 0x06, CR203);
+       if (r)
+               return r;
+       r = zd_iowrite16_locked(chip, 0x80, CR240);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+       int i, r;
+       const u32 *rv = chan_rv[channel-1];
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       struct zd_ioreq16 ioreqs_1[] = {
+               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+               { CR38,  0x38 }, { CR136, 0xdf },
+       };
+
+       struct zd_ioreq16 ioreqs_2[] = {
+               /* PLL_ON */
+               { CR251, 0x3f },
+               { CR203, 0x06 }, { CR240, 0x08 },
+       };
+
+       r = zd_iowrite16_locked(chip, 0x57, CR240);
+       if (r)
+               return r;
+
+       /* PLL_OFF */
+       r = zd_iowrite16_locked(chip, 0x2f, CR251);
+       if (r)
+               return r;
+
+       for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+               r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+               if (r)
+                       return r;
+       }
+
+       r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+       if (r)
+               return r;
+       r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+       if (r)
+               return r;
+
+       r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+       if (r)
+               return r;
+
+       for (i = 0; i < 2; i++) {
+               r = zd_rfwrite_cr_locked(chip, rv[i]);
+               if (r)
+                       return r;
+       }
+
+       r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+       if (r)
+               return r;
+
+       return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+}
+
+static int al7230b_switch_radio_on(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x00 },
+               { CR251, 0x3f },
+       };
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al7230b_switch_radio_off(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x04 },
+               { CR251, 0x2f },
+       };
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al7230b(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       if (chip->is_zd1211b) {
+               dev_err(zd_chip_dev(chip), "AL7230B is currently not "
+                       "supported for ZD1211B devices\n");
+               return -ENODEV;
+       }
+
+       rf->init_hw = al7230b_init_hw;
+       rf->set_channel = al7230b_set_channel;
+       rf->switch_radio_on = al7230b_switch_radio_on;
+       rf->switch_radio_off = al7230b_switch_radio_off;
+       rf->patch_6m_band_edge = 1;
+       return 0;
+}
index 6320984126c73adf63acf2cd55aee078b4f6f7da..47489fe8ab52a9fd202e2416a0540dc2e40d1242 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <asm/unaligned.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/firmware.h>
@@ -39,9 +40,17 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
        /* ZD1211B */
        { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+       /* "Driverless" devices that need ejecting */
+       { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
        {}
 };
 
@@ -263,6 +272,39 @@ static char *get_fw_name(char *buffer, size_t size, u8 device_type,
        return buffer;
 }
 
+static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
+       const struct firmware *ub_fw)
+{
+       const struct firmware *ur_fw = NULL;
+       int offset;
+       int r = 0;
+       char fw_name[128];
+
+       r = request_fw_file(&ur_fw,
+               get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
+               &udev->dev);
+       if (r)
+               goto error;
+
+       r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
+               REBOOT);
+       if (r)
+               goto error;
+
+       offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+       r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
+               E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+
+       /* At this point, the vendor driver downloads the whole firmware
+        * image, hacks around with version IDs, and uploads it again,
+        * completely overwriting the boot code. We do not do this here as
+        * it is not required on any tested devices, and it is suspected to
+        * cause problems. */
+error:
+       release_firmware(ur_fw);
+       return r;
+}
+
 static int upload_firmware(struct usb_device *udev, u8 device_type)
 {
        int r;
@@ -282,15 +324,17 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
 
        fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
 
-       /* FIXME: do we have any reason to perform the kludge that the vendor
-        * driver does when there is a version mismatch? (their driver uploads
-        * different firmwares and stuff)
-        */
        if (fw_bcdDevice != bcdDevice) {
                dev_info(&udev->dev,
-                       "firmware device id %#06x and actual device id "
-                       "%#06x differ, continuing anyway\n",
-                       fw_bcdDevice, bcdDevice);
+                       "firmware version %#06x and device bootcode version "
+                       "%#06x differ\n", fw_bcdDevice, bcdDevice);
+               if (bcdDevice <= 0x4313)
+                       dev_warn(&udev->dev, "device has old bootcode, please "
+                               "report success or failure\n");
+
+               r = handle_version_mismatch(udev, device_type, ub_fw);
+               if (r)
+                       goto error;
        } else {
                dev_dbg_f(&udev->dev,
                        "firmware device id %#06x is equal to the "
@@ -620,7 +664,7 @@ resubmit:
        usb_submit_urb(urb, GFP_ATOMIC);
 }
 
-struct urb *alloc_urb(struct zd_usb *usb)
+static struct urb *alloc_urb(struct zd_usb *usb)
 {
        struct usb_device *udev = zd_usb_to_usbdev(usb);
        struct urb *urb;
@@ -644,7 +688,7 @@ struct urb *alloc_urb(struct zd_usb *usb)
        return urb;
 }
 
-void free_urb(struct urb *urb)
+static void free_urb(struct urb *urb)
 {
        if (!urb)
                return;
@@ -864,7 +908,7 @@ void zd_usb_clear(struct zd_usb *usb)
 {
        usb_set_intfdata(usb->intf, NULL);
        usb_put_intf(usb->intf);
-       memset(usb, 0, sizeof(*usb));
+       ZD_MEMCLEAR(usb, sizeof(*usb));
        /* FIXME: usb_interrupt, usb_tx, usb_rx? */
 }
 
@@ -910,6 +954,55 @@ static void print_id(struct usb_device *udev)
 #define print_id(udev) do { } while (0)
 #endif
 
+static int eject_installer(struct usb_interface *intf)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct usb_host_interface *iface_desc = &intf->altsetting[0];
+       struct usb_endpoint_descriptor *endpoint;
+       unsigned char *cmd;
+       u8 bulk_out_ep;
+       int r;
+
+       /* Find bulk out endpoint */
+       endpoint = &iface_desc->endpoint[1].desc;
+       if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
+           (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+           USB_ENDPOINT_XFER_BULK) {
+               bulk_out_ep = endpoint->bEndpointAddress;
+       } else {
+               dev_err(&udev->dev,
+                       "zd1211rw: Could not find bulk out endpoint\n");
+               return -ENODEV;
+       }
+
+       cmd = kzalloc(31, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENODEV;
+
+       /* USB bulk command block */
+       cmd[0] = 0x55;  /* bulk command signature */
+       cmd[1] = 0x53;  /* bulk command signature */
+       cmd[2] = 0x42;  /* bulk command signature */
+       cmd[3] = 0x43;  /* bulk command signature */
+       cmd[14] = 6;    /* command length */
+
+       cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
+       cmd[19] = 0x2;  /* eject disc */
+
+       dev_info(&udev->dev, "Ejecting virtual installer media...\n");
+       r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
+               cmd, 31, NULL, 2000);
+       kfree(cmd);
+       if (r)
+               return r;
+
+       /* At this point, the device disconnects and reconnects with the real
+        * ID numbers. */
+
+       usb_set_intfdata(intf, NULL);
+       return 0;
+}
+
 static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        int r;
@@ -918,6 +1011,9 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        print_id(udev);
 
+       if (id->driver_info & DEVICE_INSTALLER)
+               return eject_installer(intf);
+
        switch (udev->speed) {
        case USB_SPEED_LOW:
        case USB_SPEED_FULL:
@@ -983,6 +1079,11 @@ static void disconnect(struct usb_interface *intf)
        struct zd_mac *mac = zd_netdev_mac(netdev);
        struct zd_usb *usb = &mac->chip.usb;
 
+       /* Either something really bad happened, or we're just dealing with
+        * a DEVICE_INSTALLER. */
+       if (netdev == NULL)
+               return;
+
        dev_dbg_f(zd_usb_dev(usb), "\n");
 
        zd_netdev_disconnect(netdev);
@@ -998,7 +1099,6 @@ static void disconnect(struct usb_interface *intf)
         */
        usb_reset_device(interface_to_usbdev(intf));
 
-       /* If somebody still waits on this lock now, this is an error. */
        zd_netdev_free(netdev);
        dev_dbg(&intf->dev, "disconnected\n");
 }
index d6420283bd5ad031933370598e1623d2a886e2df..92746f76239aa1eab312e481e3a6cafafa5a338e 100644 (file)
@@ -30,6 +30,7 @@
 enum devicetype {
        DEVICE_ZD1211  = 0,
        DEVICE_ZD1211B = 1,
+       DEVICE_INSTALLER = 2,
 };
 
 enum endpoints {
index ecc42864b001a400a5c8fe32a6de6a3feac92f81..b174ebb277a96668f058e469b0753503c34f164b 100644 (file)
@@ -240,6 +240,11 @@ struct ieee80211_snap_hdr {
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
 
+/* 802.11g ERP information element */
+#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
+#define WLAN_ERP_USE_PROTECTION (1<<1)
+#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
+
 /* Status codes */
 enum ieee80211_statuscode {
        WLAN_STATUS_SUCCESS = 0,
@@ -747,6 +752,8 @@ struct ieee80211_txb {
 #define NETWORK_HAS_IBSS_DFS            (1<<8)
 #define NETWORK_HAS_TPC_REPORT          (1<<9)
 
+#define NETWORK_HAS_ERP_VALUE           (1<<10)
+
 #define QOS_QUEUE_NUM                   4
 #define QOS_OUI_LEN                     3
 #define QOS_OUI_TYPE                    2
@@ -1252,6 +1259,8 @@ extern int ieee80211_tx_frame(struct ieee80211_device *ieee,
                              int total_len, int encrypt_mpdu);
 
 /* ieee80211_rx.c */
+extern void ieee80211_rx_any(struct ieee80211_device *ieee,
+                    struct sk_buff *skb, struct ieee80211_rx_stats *stats);
 extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                        struct ieee80211_rx_stats *rx_stats);
 /* make sure to set stats->len */
index 00ad810eb883090add39c82b60fd130cf97452c0..425b3a57ac74a01d12f8f3d714b66cd9d7dbcb04 100644 (file)
@@ -86,9 +86,6 @@ struct ieee80211softmac_assoc_info {
        
        /* BSSID we're trying to associate to */
        char bssid[ETH_ALEN];
-
-       /* Rates supported by the network */
-       struct ieee80211softmac_ratesinfo supported_rates;
        
        /* some flags.
         * static_essid is valid if the essid is constant,
@@ -103,6 +100,7 @@ struct ieee80211softmac_assoc_info {
         * bssfixed is used for SIOCSIWAP.
         */
        u8 static_essid:1,
+          short_preamble_available:1,
           associating:1,
           assoc_wait:1,
           bssvalid:1,
@@ -115,6 +113,19 @@ struct ieee80211softmac_assoc_info {
        struct work_struct timeout;
 };
 
+struct ieee80211softmac_bss_info {
+       /* Rates supported by the network */
+       struct ieee80211softmac_ratesinfo supported_rates;
+
+       /* This indicates whether frames can currently be transmitted with
+        * short preamble (only use this variable during TX at CCK rates) */
+       u8 short_preamble:1;
+
+       /* This indicates whether protection (e.g. self-CTS) should be used
+        * when transmitting with OFDM modulation */
+       u8 use_protection:1;
+};
+
 enum {
        IEEE80211SOFTMAC_AUTH_OPEN_REQUEST      = 1,
        IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE     = 2,
@@ -157,6 +168,10 @@ struct ieee80211softmac_txrates {
 #define IEEE80211SOFTMAC_TXRATECHG_MCAST               (1 << 2) /* mcast_rate */
 #define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST           (1 << 3) /* mgt_mcast_rate */
 
+#define IEEE80211SOFTMAC_BSSINFOCHG_RATES              (1 << 0) /* supported_rates */
+#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE     (1 << 1) /* short_preamble */
+#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION         (1 << 2) /* use_protection */
+
 struct ieee80211softmac_device {
        /* 802.11 structure for data stuff */
        struct ieee80211_device *ieee;
@@ -200,10 +215,16 @@ struct ieee80211softmac_device {
         * The driver just needs to read them.
         */
        struct ieee80211softmac_txrates txrates;
-       /* If the driver needs to do stuff on TX rate changes, assign this callback. */
+
+       /* If the driver needs to do stuff on TX rate changes, assign this
+        * callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */
        void (*txrates_change)(struct net_device *dev,
-                              u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */
-                              const struct ieee80211softmac_txrates *rates_before_change);
+                              u32 changes);
+
+       /* If the driver needs to do stuff when BSS properties change, assign
+        * this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */
+       void (*bssinfo_change)(struct net_device *dev,
+                              u32 changes);
 
        /* private stuff follows */
        /* this lock protects this structure */
@@ -216,6 +237,7 @@ struct ieee80211softmac_device {
        
        struct ieee80211softmac_scaninfo *scaninfo;
        struct ieee80211softmac_assoc_info associnfo;
+       struct ieee80211softmac_bss_info bssinfo;
 
        struct list_head auth_queue;
        struct list_head events;
@@ -257,6 +279,14 @@ extern void ieee80211softmac_fragment_lost(struct net_device *dev,
  * Note that the rates need to be sorted. */
 extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
 
+/* Finds the highest rate which is:
+ *  1. Present in ri (optionally a basic rate)
+ *  2. Supported by the device
+ *  3. Less than or equal to the user-defined rate
+ */
+extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
+       struct ieee80211softmac_ratesinfo *ri, int basic_only);
+
 /* Helper function which advises you the rate at which a frame should be
  * transmitted at. */
 static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
@@ -279,6 +309,24 @@ static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device
                return txrates->mcast_rate;
 }
 
+/* Helper function which advises you when it is safe to transmit with short
+ * preamble.
+ * You should only call this function when transmitting at CCK rates. */
+static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac,
+                                                   int is_multicast,
+                                                   int is_mgt)
+{
+       return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble;
+}
+
+/* Helper function which advises you whether protection (e.g. self-CTS) is
+ * needed. 1 = protection needed, 0 = no protection needed
+ * Only use this function when transmitting with OFDM modulation. */
+static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac)
+{
+       return mac->bssinfo.use_protection;
+}
+
 /* Start the SoftMAC. Call this after you initialized the device
  * and it is ready to run.
  */
index ed90a8af1444937c5d9cfc066321f8d7311d2564..098c66846339a94c5bc69b490f478c0bea27713c 100644 (file)
@@ -271,6 +271,27 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        return 0;
 }
 
+/*
+ * deal with seq counter wrapping correctly.
+ * refer to timer_after() for jiffies wrapping handling
+ */
+static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
+{
+       u32 iv32_n, iv16_n;
+       u32 iv32_o, iv16_o;
+
+       iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3];
+       iv16_n = (pn_n[4] << 8) | pn_n[5];
+
+       iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3];
+       iv16_o = (pn_o[4] << 8) | pn_o[5];
+
+       if ((s32)iv32_n - (s32)iv32_o < 0 ||
+           (iv32_n == iv32_o && iv16_n <= iv16_o))
+               return 1;
+       return 0;
+}
+
 static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
        struct ieee80211_ccmp_data *key = priv;
@@ -323,7 +344,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        pn[5] = pos[0];
        pos += 8;
 
-       if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
+       if (ccmp_replay_check(pn, key->rx_pn)) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
                               " previous PN %02x%02x%02x%02x%02x%02x "
index 34dba0ba545de66e55737d56390d673789d21c99..f2df2f5b3e4cc4e448ca9bd6e26b5f051428d23e 100644 (file)
@@ -52,8 +52,10 @@ struct ieee80211_tkip_data {
 
        int key_idx;
 
-       struct crypto_tfm *tfm_arc4;
-       struct crypto_tfm *tfm_michael;
+       struct crypto_tfm *tx_tfm_arc4;
+       struct crypto_tfm *tx_tfm_michael;
+       struct crypto_tfm *rx_tfm_arc4;
+       struct crypto_tfm *rx_tfm_michael;
 
        /* scratch buffers for virt_to_page() (crypto API) */
        u8 rx_hdr[16], tx_hdr[16];
@@ -85,15 +87,29 @@ static void *ieee80211_tkip_init(int key_idx)
 
        priv->key_idx = key_idx;
 
-       priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0);
-       if (priv->tfm_arc4 == NULL) {
+       priv->tx_tfm_arc4 = crypto_alloc_tfm("arc4", 0);
+       if (priv->tx_tfm_arc4 == NULL) {
                printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
                       "crypto API arc4\n");
                goto fail;
        }
 
-       priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0);
-       if (priv->tfm_michael == NULL) {
+       priv->tx_tfm_michael = crypto_alloc_tfm("michael_mic", 0);
+       if (priv->tx_tfm_michael == NULL) {
+               printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+                      "crypto API michael_mic\n");
+               goto fail;
+       }
+
+       priv->rx_tfm_arc4 = crypto_alloc_tfm("arc4", 0);
+       if (priv->rx_tfm_arc4 == NULL) {
+               printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+                      "crypto API arc4\n");
+               goto fail;
+       }
+
+       priv->rx_tfm_michael = crypto_alloc_tfm("michael_mic", 0);
+       if (priv->rx_tfm_michael == NULL) {
                printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
                       "crypto API michael_mic\n");
                goto fail;
@@ -103,10 +119,14 @@ static void *ieee80211_tkip_init(int key_idx)
 
       fail:
        if (priv) {
-               if (priv->tfm_michael)
-                       crypto_free_tfm(priv->tfm_michael);
-               if (priv->tfm_arc4)
-                       crypto_free_tfm(priv->tfm_arc4);
+               if (priv->tx_tfm_michael)
+                       crypto_free_tfm(priv->tx_tfm_michael);
+               if (priv->tx_tfm_arc4)
+                       crypto_free_tfm(priv->tx_tfm_arc4);
+               if (priv->rx_tfm_michael)
+                       crypto_free_tfm(priv->rx_tfm_michael);
+               if (priv->rx_tfm_arc4)
+                       crypto_free_tfm(priv->rx_tfm_arc4);
                kfree(priv);
        }
 
@@ -116,10 +136,16 @@ static void *ieee80211_tkip_init(int key_idx)
 static void ieee80211_tkip_deinit(void *priv)
 {
        struct ieee80211_tkip_data *_priv = priv;
-       if (_priv && _priv->tfm_michael)
-               crypto_free_tfm(_priv->tfm_michael);
-       if (_priv && _priv->tfm_arc4)
-               crypto_free_tfm(_priv->tfm_arc4);
+       if (_priv) {
+               if (_priv->tx_tfm_michael)
+                       crypto_free_tfm(_priv->tx_tfm_michael);
+               if (_priv->tx_tfm_arc4)
+                       crypto_free_tfm(_priv->tx_tfm_arc4);
+               if (_priv->rx_tfm_michael)
+                       crypto_free_tfm(_priv->rx_tfm_michael);
+               if (_priv->rx_tfm_arc4)
+                       crypto_free_tfm(_priv->rx_tfm_arc4);
+       }
        kfree(priv);
 }
 
@@ -351,12 +377,25 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        icv[2] = crc >> 16;
        icv[3] = crc >> 24;
 
-       crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+       crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
        sg.page = virt_to_page(pos);
        sg.offset = offset_in_page(pos);
        sg.length = len + 4;
-       crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
+       crypto_cipher_encrypt(tkey->tx_tfm_arc4, &sg, &sg, len + 4);
+
+       return 0;
+}
 
+/*
+ * deal with seq counter wrapping correctly.
+ * refer to timer_after() for jiffies wrapping handling
+ */
+static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
+                                   u32 iv32_o, u16 iv16_o)
+{
+       if ((s32)iv32_n - (s32)iv32_o < 0 ||
+           (iv32_n == iv32_o && iv16_n <= iv16_o))
+               return 1;
        return 0;
 }
 
@@ -414,8 +453,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
        pos += 8;
 
-       if (iv32 < tkey->rx_iv32 ||
-           (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
+       if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
                               " previous TSC %08x%04x received TSC "
@@ -434,11 +472,11 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 
        plen = skb->len - hdr_len - 12;
 
-       crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
+       crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
        sg.page = virt_to_page(pos);
        sg.offset = offset_in_page(pos);
        sg.length = plen + 4;
-       crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4);
+       crypto_cipher_decrypt(tkey->rx_tfm_arc4, &sg, &sg, plen + 4);
 
        crc = ~crc32_le(~0, pos, plen);
        icv[0] = crc;
@@ -472,12 +510,12 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        return keyidx;
 }
 
-static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
+static int michael_mic(struct crypto_tfm *tfm_michael, u8 * key, u8 * hdr,
                       u8 * data, size_t data_len, u8 * mic)
 {
        struct scatterlist sg[2];
 
-       if (tkey->tfm_michael == NULL) {
+       if (tfm_michael == NULL) {
                printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
                return -1;
        }
@@ -489,10 +527,10 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
        sg[1].offset = offset_in_page(data);
        sg[1].length = data_len;
 
-       crypto_digest_init(tkey->tfm_michael);
-       crypto_digest_setkey(tkey->tfm_michael, key, 8);
-       crypto_digest_update(tkey->tfm_michael, sg, 2);
-       crypto_digest_final(tkey->tfm_michael, mic);
+       crypto_digest_init(tfm_michael);
+       crypto_digest_setkey(tfm_michael, key, 8);
+       crypto_digest_update(tfm_michael, sg, 2);
+       crypto_digest_final(tfm_michael, mic);
 
        return 0;
 }
@@ -528,7 +566,7 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
        if (stype & IEEE80211_STYPE_QOS_DATA) {
                const struct ieee80211_hdr_3addrqos *qoshdr =
                        (struct ieee80211_hdr_3addrqos *)skb->data;
-               hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID;
+               hdr[12] = qoshdr->qos_ctl & cpu_to_le16(IEEE80211_QCTL_TID);
        } else
                hdr[12] = 0;            /* priority */
 
@@ -550,7 +588,7 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
 
        michael_mic_hdr(skb, tkey->tx_hdr);
        pos = skb_put(skb, 8);
-       if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr,
+       if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
                        skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
                return -1;
 
@@ -588,7 +626,7 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
                return -1;
 
        michael_mic_hdr(skb, tkey->rx_hdr);
-       if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr,
+       if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
                        skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
                return -1;
        if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
@@ -618,14 +656,18 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
 {
        struct ieee80211_tkip_data *tkey = priv;
        int keyidx;
-       struct crypto_tfm *tfm = tkey->tfm_michael;
-       struct crypto_tfm *tfm2 = tkey->tfm_arc4;
+       struct crypto_tfm *tfm = tkey->tx_tfm_michael;
+       struct crypto_tfm *tfm2 = tkey->tx_tfm_arc4;
+       struct crypto_tfm *tfm3 = tkey->rx_tfm_michael;
+       struct crypto_tfm *tfm4 = tkey->rx_tfm_arc4;
 
        keyidx = tkey->key_idx;
        memset(tkey, 0, sizeof(*tkey));
        tkey->key_idx = keyidx;
-       tkey->tfm_michael = tfm;
-       tkey->tfm_arc4 = tfm2;
+       tkey->tx_tfm_michael = tfm;
+       tkey->tx_tfm_arc4 = tfm2;
+       tkey->rx_tfm_michael = tfm3;
+       tkey->rx_tfm_arc4 = tfm4;
        if (len == TKIP_KEY_LEN) {
                memcpy(tkey->key, key, TKIP_KEY_LEN);
                tkey->key_set = 1;
index 0ebf235f693932e4c09241b7402658bd14d6620a..b435b28857edec3c16b201a65c620483670a0d6b 100644 (file)
@@ -32,7 +32,8 @@ struct prism2_wep_data {
        u8 key[WEP_KEY_LEN + 1];
        u8 key_len;
        u8 key_idx;
-       struct crypto_tfm *tfm;
+       struct crypto_tfm *tx_tfm;
+       struct crypto_tfm *rx_tfm;
 };
 
 static void *prism2_wep_init(int keyidx)
@@ -44,13 +45,19 @@ static void *prism2_wep_init(int keyidx)
                goto fail;
        priv->key_idx = keyidx;
 
-       priv->tfm = crypto_alloc_tfm("arc4", 0);
-       if (priv->tfm == NULL) {
+       priv->tx_tfm = crypto_alloc_tfm("arc4", 0);
+       if (priv->tx_tfm == NULL) {
                printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
                       "crypto API arc4\n");
                goto fail;
        }
 
+       priv->rx_tfm = crypto_alloc_tfm("arc4", 0);
+       if (priv->rx_tfm == NULL) {
+               printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
+                      "crypto API arc4\n");
+               goto fail;
+       }
        /* start WEP IV from a random value */
        get_random_bytes(&priv->iv, 4);
 
@@ -58,8 +65,10 @@ static void *prism2_wep_init(int keyidx)
 
       fail:
        if (priv) {
-               if (priv->tfm)
-                       crypto_free_tfm(priv->tfm);
+               if (priv->tx_tfm)
+                       crypto_free_tfm(priv->tx_tfm);
+               if (priv->rx_tfm)
+                       crypto_free_tfm(priv->rx_tfm);
                kfree(priv);
        }
        return NULL;
@@ -68,8 +77,12 @@ static void *prism2_wep_init(int keyidx)
 static void prism2_wep_deinit(void *priv)
 {
        struct prism2_wep_data *_priv = priv;
-       if (_priv && _priv->tfm)
-               crypto_free_tfm(_priv->tfm);
+       if (_priv) {
+               if (_priv->tx_tfm)
+                       crypto_free_tfm(_priv->tx_tfm);
+               if (_priv->rx_tfm)
+                       crypto_free_tfm(_priv->rx_tfm);
+       }
        kfree(priv);
 }
 
@@ -151,11 +164,11 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        icv[2] = crc >> 16;
        icv[3] = crc >> 24;
 
-       crypto_cipher_setkey(wep->tfm, key, klen);
+       crypto_cipher_setkey(wep->tx_tfm, key, klen);
        sg.page = virt_to_page(pos);
        sg.offset = offset_in_page(pos);
        sg.length = len + 4;
-       crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
+       crypto_cipher_encrypt(wep->tx_tfm, &sg, &sg, len + 4);
 
        return 0;
 }
@@ -194,11 +207,11 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        /* Apply RC4 to data and compute CRC32 over decrypted data */
        plen = skb->len - hdr_len - 8;
 
-       crypto_cipher_setkey(wep->tfm, key, klen);
+       crypto_cipher_setkey(wep->rx_tfm, key, klen);
        sg.page = virt_to_page(pos);
        sg.offset = offset_in_page(pos);
        sg.length = plen + 4;
-       crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
+       crypto_cipher_decrypt(wep->rx_tfm, &sg, &sg, plen + 4);
 
        crc = ~crc32_le(~0, pos, plen);
        icv[0] = crc;
index 72d4d4e04d426b26d8f323f4522432337f4691e7..770704183a1bd0f21f27d9bc8683618bab67230f 100644 (file)
@@ -779,33 +779,44 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        return 0;
 }
 
-/* Filter out unrelated packets, call ieee80211_rx[_mgt] */
-int ieee80211_rx_any(struct ieee80211_device *ieee,
+/* Filter out unrelated packets, call ieee80211_rx[_mgt]
+ * This function takes over the skb, it should not be used again after calling
+ * this function. */
+void ieee80211_rx_any(struct ieee80211_device *ieee,
                     struct sk_buff *skb, struct ieee80211_rx_stats *stats)
 {
        struct ieee80211_hdr_4addr *hdr;
        int is_packet_for_us;
        u16 fc;
 
-       if (ieee->iw_mode == IW_MODE_MONITOR)
-               return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL;
+       if (ieee->iw_mode == IW_MODE_MONITOR) {
+               if (!ieee80211_rx(ieee, skb, stats))
+                       dev_kfree_skb_irq(skb);
+               return;
+       }
+
+       if (skb->len < sizeof(struct ieee80211_hdr))
+               goto drop_free;
 
        hdr = (struct ieee80211_hdr_4addr *)skb->data;
        fc = le16_to_cpu(hdr->frame_ctl);
 
        if ((fc & IEEE80211_FCTL_VERS) != 0)
-               return -EINVAL;
+               goto drop_free;
                
        switch (fc & IEEE80211_FCTL_FTYPE) {
        case IEEE80211_FTYPE_MGMT:
+               if (skb->len < sizeof(struct ieee80211_hdr_3addr))
+                       goto drop_free;
                ieee80211_rx_mgt(ieee, hdr, stats);
-               return 0;
+               dev_kfree_skb_irq(skb);
+               return;
        case IEEE80211_FTYPE_DATA:
                break;
        case IEEE80211_FTYPE_CTL:
-               return 0;
+               return;
        default:
-               return -EINVAL;
+               return;
        }
 
        is_packet_for_us = 0;
@@ -849,8 +860,14 @@ int ieee80211_rx_any(struct ieee80211_device *ieee,
        }
 
        if (is_packet_for_us)
-               return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL);
-       return 0;
+               if (!ieee80211_rx(ieee, skb, stats))
+                       dev_kfree_skb_irq(skb);
+       return;
+
+drop_free:
+       dev_kfree_skb_irq(skb);
+       ieee->stats.rx_dropped++;
+       return;
 }
 
 #define MGMT_FRAME_FIXED_PART_LENGTH           0x24
@@ -1061,13 +1078,16 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
 
        while (length >= sizeof(*info_element)) {
                if (sizeof(*info_element) + info_element->len > length) {
-                       IEEE80211_DEBUG_MGMT("Info elem: parse failed: "
-                                            "info_element->len + 2 > left : "
-                                            "info_element->len+2=%zd left=%d, id=%d.\n",
-                                            info_element->len +
-                                            sizeof(*info_element),
-                                            length, info_element->id);
-                       return 1;
+                       IEEE80211_ERROR("Info elem: parse failed: "
+                                       "info_element->len + 2 > left : "
+                                       "info_element->len+2=%zd left=%d, id=%d.\n",
+                                       info_element->len +
+                                       sizeof(*info_element),
+                                       length, info_element->id);
+                       /* We stop processing but don't return an error here
+                        * because some misbehaviour APs break this rule. ie.
+                        * Orinoco AP1000. */
+                       break;
                }
 
                switch (info_element->id) {
@@ -1166,6 +1186,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
 
                case MFIE_TYPE_ERP_INFO:
                        network->erp_value = info_element->data[0];
+                       network->flags |= NETWORK_HAS_ERP_VALUE;
                        IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
                                             network->erp_value);
                        break;
@@ -1729,5 +1750,6 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
        }
 }
 
+EXPORT_SYMBOL_GPL(ieee80211_rx_any);
 EXPORT_SYMBOL(ieee80211_rx_mgt);
 EXPORT_SYMBOL(ieee80211_rx);
index bf042139c7ab97e16d811d51eff27e2c1b8d030b..ae254497ba3d8dac57a3521fab214936f6847e2a 100644 (file)
@@ -337,7 +337,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                hdr_len += 2;
 
                skb->priority = ieee80211_classify(skb);
-               header.qos_ctl |= skb->priority & IEEE80211_QCTL_TID;
+               header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID);
        }
        header.frame_ctl = cpu_to_le16(fc);
 
@@ -532,13 +532,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                        return 0;
                }
 
-               if (ret == NETDEV_TX_BUSY) {
-                       printk(KERN_ERR "%s: NETDEV_TX_BUSY returned; "
-                              "driver should report queue full via "
-                              "ieee_device->is_queue_full.\n",
-                              ieee->dev->name);
-               }
-
                ieee80211_txb_free(txb);
        }
 
index 44215ce64d4e9db3c9abb54edbfd35c154590bfd..589f6d2c548a7ba0167598def59daab5b7eb13c4 100644 (file)
@@ -96,7 +96,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
        mac->associated = 0;
        mac->associnfo.bssvalid = 0;
        mac->associnfo.associating = 0;
-       ieee80211softmac_init_txrates(mac);
+       ieee80211softmac_init_bss(mac);
        ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
        spin_unlock_irqrestore(&mac->lock, flags);
 }
@@ -334,11 +334,19 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
        struct ieee80211_assoc_response * resp,
        struct ieee80211softmac_network *net)
 {
+       u16 cap = le16_to_cpu(resp->capability);
+       u8 erp_value = net->erp_value;
+
        mac->associnfo.associating = 0;
-       mac->associnfo.supported_rates = net->supported_rates;
+       mac->bssinfo.supported_rates = net->supported_rates;
        ieee80211softmac_recalc_txrates(mac);
 
        mac->associated = 1;
+
+       mac->associnfo.short_preamble_available =
+               (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
+       ieee80211softmac_process_erp(mac, erp_value);
+
        if (mac->set_bssid_filter)
                mac->set_bssid_filter(mac->dev, net->bssid);
        memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
@@ -351,9 +359,9 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
 int
 ieee80211softmac_handle_assoc_response(struct net_device * dev,
                                       struct ieee80211_assoc_response * resp,
-                                      struct ieee80211_network * _ieee80211_network_do_not_use)
+                                      struct ieee80211_network * _ieee80211_network)
 {
-       /* NOTE: the network parameter has to be ignored by
+       /* NOTE: the network parameter has to be mostly ignored by
         *       this code because it is the ieee80211's pointer
         *       to the struct, not ours (we made a copy)
         */
@@ -385,6 +393,11 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev,
        /* now that we know it was for us, we can cancel the timeout */
        cancel_delayed_work(&mac->associnfo.timeout);
 
+       /* if the association response included an ERP IE, update our saved
+        * copy */
+       if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
+               network->erp_value = _ieee80211_network->erp_value;
+
        switch (status) {
                case 0:
                        dprintk(KERN_INFO PFX "associated!\n");
index 6ae5a1dc79564742f1bfd024ae9e2b37058fb4c0..82bfddbf33a28e999b944d86660f21560206438b 100644 (file)
@@ -467,3 +467,17 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
        kfree(pkt);
        return 0;
 }
+
+/* Beacon handling */
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+       struct ieee80211_beacon *beacon,
+       struct ieee80211_network *network)
+{
+       struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+
+       if (mac->associated && memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
+               ieee80211softmac_process_erp(mac, network->erp_value);
+
+       return 0;
+}
+
index 4b2e57d12418a901185b6124ac3104dbd0e8d69a..addea1cf73ae3f5ba9f2787af8503bb354b97778 100644 (file)
@@ -44,6 +44,7 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv)
        softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
        softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
        softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
+       softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
        softmac->scaninfo = NULL;
 
        softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
@@ -178,21 +179,14 @@ int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo
        return 0;
 }
 
-/* Finds the highest rate which is:
- *  1. Present in ri (optionally a basic rate)
- *  2. Supported by the device
- *  3. Less than or equal to the user-defined rate
- */
-static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
+u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
        struct ieee80211softmac_ratesinfo *ri, int basic_only)
 {
        u8 user_rate = mac->txrates.user_rate;
        int i;
 
-       if (ri->count == 0) {
-               dprintk(KERN_ERR PFX "empty ratesinfo?\n");
+       if (ri->count == 0)
                return IEEE80211_CCK_RATE_1MB;
-       }
 
        for (i = ri->count - 1; i >= 0; i--) {
                u8 rate = ri->rates[i];
@@ -208,36 +202,61 @@ static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
        /* If we haven't found a suitable rate by now, just trust the user */
        return user_rate;
 }
+EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
+
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+       u8 erp_value)
+{
+       int use_protection;
+       int short_preamble;
+       u32 changes = 0;
+
+       /* Barker preamble mode */
+       short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
+                         && mac->associnfo.short_preamble_available) ? 1 : 0;
+
+       /* Protection needed? */
+       use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+
+       if (mac->bssinfo.short_preamble != short_preamble) {
+               changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+               mac->bssinfo.short_preamble = short_preamble;
+       }
+
+       if (mac->bssinfo.use_protection != use_protection) {
+               changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+               mac->bssinfo.use_protection = use_protection;
+       }
+
+       if (mac->bssinfo_change && changes)
+               mac->bssinfo_change(mac->dev, changes);
+}
 
 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
 {
        struct ieee80211softmac_txrates *txrates = &mac->txrates;
-       struct ieee80211softmac_txrates oldrates;
        u32 change = 0;
 
-       if (mac->txrates_change)
-               oldrates = mac->txrates;
-
        change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-       txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
+       txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
 
        change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
        txrates->default_fallback = lower_rate(mac, txrates->default_rate);
 
        change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
-       txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
+       txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
 
        if (mac->txrates_change)
-               mac->txrates_change(mac->dev, change, &oldrates);
+               mac->txrates_change(mac->dev, change);
 
 }
 
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
 {
        struct ieee80211_device *ieee = mac->ieee;
        u32 change = 0;
        struct ieee80211softmac_txrates *txrates = &mac->txrates;
-       struct ieee80211softmac_txrates oldrates;
+       struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
 
        /* TODO: We need some kind of state machine to lower the default rates
         *       if we loose too many packets.
@@ -245,8 +264,6 @@ void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
        /* Change the default txrate to the highest possible value.
         * The txrate machine will lower it, if it is too high.
         */
-       if (mac->txrates_change)
-               oldrates = mac->txrates;
        /* FIXME: We don't correctly handle backing down to lower
           rates, so 801.11g devices start off at 11M for now. People
           can manually change it if they really need to, but 11M is
@@ -272,7 +289,23 @@ void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
        change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
 
        if (mac->txrates_change)
-               mac->txrates_change(mac->dev, change, &oldrates);
+               mac->txrates_change(mac->dev, change);
+
+       change = 0;
+
+       bssinfo->supported_rates.count = 0;
+       memset(bssinfo->supported_rates.rates, 0,
+               sizeof(bssinfo->supported_rates.rates));
+       change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
+
+       bssinfo->short_preamble = 0;
+       change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+
+       bssinfo->use_protection = 0;
+       change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+
+       if (mac->bssinfo_change)
+               mac->bssinfo_change(mac->dev, change);
 
        mac->running = 1;
 }
@@ -282,7 +315,7 @@ void ieee80211softmac_start(struct net_device *dev)
        struct ieee80211softmac_device *mac = ieee80211_priv(dev);
 
        ieee80211softmac_start_check_rates(mac);
-       ieee80211softmac_init_txrates(mac);
+       ieee80211softmac_init_bss(mac);
 }
 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
 
@@ -335,7 +368,6 @@ u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rat
 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
                                                 int amount)
 {
-       struct ieee80211softmac_txrates oldrates;
        u8 default_rate = mac->txrates.default_rate;
        u8 default_fallback = mac->txrates.default_fallback;
        u32 changes = 0;
@@ -348,8 +380,6 @@ printk("badness %d\n", mac->txrate_badness);
        mac->txrate_badness += amount;
        if (mac->txrate_badness <= -1000) {
                /* Very small badness. Try a faster bitrate. */
-               if (mac->txrates_change)
-                       memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
                default_rate = raise_rate(mac, default_rate);
                changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
                default_fallback = get_fallback_rate(mac, default_rate);
@@ -358,8 +388,6 @@ printk("badness %d\n", mac->txrate_badness);
 printk("Bitrate raised to %u\n", default_rate);
        } else if (mac->txrate_badness >= 10000) {
                /* Very high badness. Try a slower bitrate. */
-               if (mac->txrates_change)
-                       memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
                default_rate = lower_rate(mac, default_rate);
                changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
                default_fallback = get_fallback_rate(mac, default_rate);
@@ -372,7 +400,7 @@ printk("Bitrate lowered to %u\n", default_rate);
        mac->txrates.default_fallback = default_fallback;
 
        if (changes && mac->txrates_change)
-               mac->txrates_change(mac->dev, changes, &oldrates);
+               mac->txrates_change(mac->dev, changes);
 }
 
 void ieee80211softmac_fragment_lost(struct net_device *dev,
@@ -416,7 +444,11 @@ ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
        memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
        softnet->supported_rates.count += net->rates_ex_len;
        sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
-       
+
+       /* we save the ERP value because it is needed at association time, and
+        * many AP's do not include an ERP IE in the association response. */
+       softnet->erp_value = net->erp_value;
+
        softnet->capabilities = net->capability;
        return softnet;
 }
index fa1f8e3acfc07f0370567e026bef2d4379eeeedc..0642e090b8a7a177ce0bf63a56a3692e2e57c0a8 100644 (file)
@@ -116,9 +116,11 @@ ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
        struct ieee80211softmac_essid *essid);
 
 /* Rates related */
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+       u8 erp_value);
 int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
 static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
        return ieee80211softmac_lower_rate_delta(mac, rate, 1);
@@ -133,6 +135,9 @@ static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
 /*** prototypes from _io.c */
 int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
        void* ptrarg, u32 type, u32 arg);
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+       struct ieee80211_beacon *beacon,
+       struct ieee80211_network *network);
 
 /*** prototypes from _auth.c */
 /* do these have to go into the public header? */
@@ -189,6 +194,7 @@ struct ieee80211softmac_network {
            authenticated:1,
            auth_desynced_once:1;
 
+       u8 erp_value;                           /* Saved ERP value */
        u16 capabilities;                       /* Capabilities bitfield */
        u8 challenge_len;                       /* Auth Challenge length */
        char *challenge;                        /* Challenge Text */