Ok, I'm back with a completely rewritten version of the
"preemptible periodic work" patch.
For this I had to completely redesign driver locking. We have
two different locks now. One for general purpose and one
to protect against IRQ concurrency.
(Yes, the final patch will be splitted, but for now I have
a convenient all-in-one patch here)
As we don't take the IRQ lock while executing preemptible
periodic work (We don't need to, as IRQs are disabled), we
can not deadlock anymore.

I am currently stressing the patch on one of my machines and
it seems to work as expected here.
I also wrote a dscape patch and also stressed that.
(I will publish the dscape patch later, if nobody is able
to find a regression in the softmac patch ;) )

So, here we go. Preemptible Periodic Work for bcm43xx-softmac.
Please stress-test with all methods which come to your minds.

Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx.h    2006-06-03 
21:04:17.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx.h 2006-06-03 
21:15:23.000000000 +0200
@@ -647,9 +647,9 @@
        void __iomem *mmio_addr;
        unsigned int mmio_len;
 
-       /* Do not use the lock directly. Use the bcm43xx_lock* helper
-        * functions, to be MMIO-safe. */
-       spinlock_t _lock;
+       /* Locking, see "theory of locking" text below. */
+       spinlock_t irq_lock;
+       struct mutex mutex;
 
        /* Driver status flags. */
        u32 initialized:1,              /* init_board() succeed */
@@ -722,7 +722,7 @@
        struct tasklet_struct isr_tasklet;
 
        /* Periodic tasks */
-       struct timer_list periodic_tasks;
+       struct work_struct periodic_work;
        unsigned int periodic_state;
 
        struct work_struct restart_work;
@@ -747,21 +747,55 @@
 #endif
 };
 
-/* bcm43xx_(un)lock() protect struct bcm43xx_private.
- * Note that _NO_ MMIO writes are allowed. If you want to
- * write to the device through MMIO in the critical section, use
- * the *_mmio lock functions.
- * MMIO read-access is allowed, though.
- */
-#define bcm43xx_lock(bcm, flags)       spin_lock_irqsave(&(bcm)->_lock, flags)
-#define bcm43xx_unlock(bcm, flags)     spin_unlock_irqrestore(&(bcm)->_lock, 
flags)
-/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
- * MMIO write-access to the device is allowed.
- * All MMIO writes are flushed on unlock, so it is guaranteed to not
- * interfere with other threads writing MMIO registers.
+
+/*    *** 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.
  */
-#define bcm43xx_lock_mmio(bcm, flags)  bcm43xx_lock(bcm, flags)
-#define bcm43xx_unlock_mmio(bcm, flags)        do { mmiowb(); 
bcm43xx_unlock(bcm, flags); } while (0)
+
+/* 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)
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c    
2006-04-28 16:13:40.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c 2006-06-03 
21:15:23.000000000 +0200
@@ -77,7 +77,7 @@
 
        down(&big_buffer_sem);
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (!bcm->initialized) {
                fappend("Board not initialized.\n");
                goto out;
@@ -121,7 +121,7 @@
        fappend("\n");
 
 out:
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
        up(&big_buffer_sem);
        return res;
@@ -159,7 +159,7 @@
        unsigned long flags;
 
        down(&big_buffer_sem);
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (!bcm->initialized) {
                fappend("Board not initialized.\n");
                goto out;
@@ -169,7 +169,7 @@
        fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
 
 out:
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
        up(&big_buffer_sem);
        return res;
@@ -188,7 +188,7 @@
        u64 tsf;
 
        down(&big_buffer_sem);
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (!bcm->initialized) {
                fappend("Board not initialized.\n");
                goto out;
@@ -199,7 +199,7 @@
                (unsigned int)(tsf & 0xFFFFFFFFULL));
 
 out:
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
        up(&big_buffer_sem);
        return res;
@@ -221,7 +221,7 @@
                res = -EFAULT;
                goto out_up;
        }
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (!bcm->initialized) {
                printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
                res = -EFAULT;
@@ -233,10 +233,11 @@
                goto out_unlock;
        }
        bcm43xx_tsf_write(bcm, tsf);
+       mmiowb();
        res = buf_size;
        
 out_unlock:
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 out_up:
        up(&big_buffer_sem);
        return res;
@@ -257,7 +258,7 @@
        int i, cnt, j = 0;
 
        down(&big_buffer_sem);
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
 
        fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
                BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -293,14 +294,14 @@
                        i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
        }
 
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
        res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (*ppos == pos) {
                /* Done. Drop the copied data. */
                e->xmitstatus_printing = 0;
        }
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
        up(&big_buffer_sem);
        return res;
 }
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_leds.c       
2006-04-11 06:00:00.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_leds.c    2006-06-03 
21:15:23.000000000 +0200
@@ -51,12 +51,12 @@
        struct bcm43xx_private *bcm = led->bcm;
        unsigned long flags;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqonly(bcm, flags);
        if (led->blink_interval) {
                bcm43xx_led_changestate(led);
                mod_timer(&led->blink_timer, jiffies + led->blink_interval);
        }
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_main.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c       
2006-06-03 21:04:17.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_main.c    2006-06-04 
21:10:41.000000000 +0200
@@ -496,22 +496,35 @@
        return old_mask;
 }
 
+static void disable_irqs_sync_tophalf(struct bcm43xx_private *bcm, u32 
*oldstate)
+{
+       u32 old;
+
+       old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+       if (oldstate)
+               *oldstate = old;
+}
+
+static void disable_irqs_sync_bottomhalf(struct bcm43xx_private *bcm)
+{
+       synchronize_irq();
+       tasklet_disable(&bcm->isr_tasklet);
+}
+
 /* Make sure we don't receive more data from the device. */
 static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 
*oldstate)
 {
-       u32 old;
        unsigned long flags;
 
-       bcm43xx_lock_mmio(bcm, flags);
-       if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
-               bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_lock_irqonly(bcm, flags);
+       if (unlikely(bcm43xx_is_initializing(bcm) ||
+                    bcm->shutting_down)) {
+               bcm43xx_unlock_irqonly(bcm, flags);
                return -EBUSY;
        }
-       old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-       tasklet_disable(&bcm->isr_tasklet);
-       bcm43xx_unlock_mmio(bcm, flags);
-       if (oldstate)
-               *oldstate = old;
+       disable_irqs_sync_tophalf(bcm, oldstate);
+       bcm43xx_unlock_irqonly(bcm, flags);
+       disable_irqs_sync_bottomhalf(bcm);
 
        return 0;
 }
@@ -1707,7 +1720,7 @@
 # define bcmirq_handled(irq)   do { /* nothing */ } while (0)
 #endif /* CONFIG_BCM43XX_DEBUG*/
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqonly(bcm, flags);
        reason = bcm->irq_reason;
        dma_reason[0] = bcm->dma_reason[0];
        dma_reason[1] = bcm->dma_reason[1];
@@ -1732,7 +1745,8 @@
                        dma_reason[0], dma_reason[1],
                        dma_reason[2], dma_reason[3]);
                bcm43xx_controller_restart(bcm, "DMA error");
-               bcm43xx_unlock_mmio(bcm, flags);
+               mmiowb();
+               bcm43xx_unlock_irqonly(bcm, flags);
                return;
        }
        if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1819,7 +1833,8 @@
        if (!modparam_noleds)
                bcm43xx_leds_update(bcm, activity);
        bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
-       bcm43xx_unlock_mmio(bcm, flags);
+       mmiowb();
+       bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1868,7 +1883,7 @@
        if (!bcm)
                return IRQ_NONE;
 
-       spin_lock(&bcm->_lock);
+       spin_lock(&bcm->irq_lock);
 
        reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
        if (reason == 0xffffffff) {
@@ -1907,7 +1922,7 @@
 
 out:
        mmiowb();
-       spin_unlock(&bcm->_lock);
+       spin_unlock(&bcm->irq_lock);
 
        return ret;
 }
@@ -3104,15 +3119,10 @@
        //TODO for APHY (temperature?)
 }
 
-static void bcm43xx_periodic_task_handler(unsigned long d)
+static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-       struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
-       unsigned long flags;
        unsigned int state;
 
-       bcm43xx_lock_mmio(bcm, flags);
-
-       assert(bcm->initialized);
        state = bcm->periodic_state;
        if (state % 8 == 0)
                bcm43xx_periodic_every120sec(bcm);
@@ -3120,29 +3130,91 @@
                bcm43xx_periodic_every60sec(bcm);
        if (state % 2 == 0)
                bcm43xx_periodic_every30sec(bcm);
-       bcm43xx_periodic_every15sec(bcm);
+       if (state % 1 == 0)
+               bcm43xx_periodic_every15sec(bcm);
        bcm->periodic_state = state + 1;
 
-       mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
+       schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+}
 
-       bcm43xx_unlock_mmio(bcm, flags);
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+       int badness = 0;
+
+       if (state % 8 == 0) /* 120 sec */
+               badness += 10;
+       if (state % 4 == 0) /* 60 sec */
+               badness += 5;
+       if (state % 2 == 0) /* 30 sec */
+               badness += 1;
+       if (state % 1 == 0) /* 15 sec */
+               badness += 1;
+
+#define BADNESS_LIMIT  4
+       return badness;
+}
+
+static void bcm43xx_periodic_work_handler(void *d)
+{
+       struct bcm43xx_private *bcm = d;
+       unsigned long flags;
+       u32 savedirqs;
+       int badness;
+
+       badness = estimate_periodic_work_badness(bcm->periodic_state);
+       if (badness > BADNESS_LIMIT) {
+               /* Periodic work can take a long time, so we want it to
+                * be preemtible.
+                */
+               bcm43xx_lock_irqonly(bcm, flags);
+               netif_stop_queue(bcm->net_dev);
+               if (bcm43xx_using_pio(bcm))
+                       bcm43xx_pio_freeze_txqueues(bcm);
+               disable_irqs_sync_tophalf(bcm, &savedirqs);
+               bcm43xx_unlock_irqonly(bcm, flags);
+               disable_irqs_sync_bottomhalf(bcm);
+               bcm43xx_lock_noirq(bcm);
+       } else {
+               /* Periodic work should take short time, so we want low
+                * locking overhead.
+                */
+               bcm43xx_lock_irqsafe(bcm, flags);
+       }
+
+       do_periodic_work(bcm);
+
+       if (badness > BADNESS_LIMIT) {
+               bcm43xx_lock_irqonly(bcm, flags);
+               tasklet_enable(&bcm->isr_tasklet);
+               bcm43xx_interrupt_enable(bcm, savedirqs);
+               if (bcm43xx_using_pio(bcm))
+                       bcm43xx_pio_thaw_txqueues(bcm);
+               netif_wake_queue(bcm->net_dev);
+               mmiowb();
+               bcm43xx_unlock_irqonly(bcm, flags);
+               bcm43xx_unlock_noirq(bcm);
+       } else {
+               mmiowb();
+               bcm43xx_unlock_irqsafe(bcm, flags);
+       }
 }
 
 static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
 {
-       del_timer_sync(&bcm->periodic_tasks);
+       cancel_rearming_delayed_work(&bcm->periodic_work);
 }
 
 static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
 {
-       struct timer_list *timer = &(bcm->periodic_tasks);
+       struct work_struct *work = &(bcm->periodic_work);
 
        assert(bcm->initialized);
-       setup_timer(timer,
-                   bcm43xx_periodic_task_handler,
-                   (unsigned long)bcm);
-       timer->expires = jiffies;
-       add_timer(timer);
+       INIT_WORK(work, bcm43xx_periodic_work_handler, bcm);
+       schedule_work(work);
 }
 
 static void bcm43xx_security_init(struct bcm43xx_private *bcm)
@@ -3162,10 +3234,10 @@
 
        bcm43xx_periodic_tasks_delete(bcm);
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm->initialized = 0;
        bcm->shutting_down = 1;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
                if (!bcm->core_80211[i].available)
@@ -3180,9 +3252,9 @@
 
        bcm43xx_pctl_set_crystal(bcm, 0);
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm->shutting_down = 0;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 static int bcm43xx_init_board(struct bcm43xx_private *bcm)
@@ -3193,10 +3265,10 @@
 
        might_sleep();
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm->initialized = 0;
        bcm->shutting_down = 0;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        err = bcm43xx_pctl_set_crystal(bcm, 1);
        if (err)
@@ -3263,9 +3335,9 @@
        }
 
        /* Initialization of the board is done. Flag it as such. */
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm->initialized = 1;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        bcm43xx_periodic_tasks_setup(bcm);
        bcm43xx_sysfs_register(bcm);
@@ -3544,7 +3616,7 @@
        struct bcm43xx_radioinfo *radio;
        unsigned long flags;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (bcm->initialized) {
                bcm43xx_mac_suspend(bcm);
                bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -3553,7 +3625,7 @@
                radio = bcm43xx_current_radio(bcm);
                radio->initial_channel = channel;
        }
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 /* set_security() callback in struct ieee80211_device */
@@ -3567,7 +3639,7 @@
        
        dprintk(KERN_INFO PFX "set security called\n");
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
 
        for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
                if (sec->flags & (1<<keyidx)) {
@@ -3630,7 +3702,7 @@
                } else
                                bcm43xx_clear_keys(bcm);
        }
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 /* hard_start_xmit() callback in struct ieee80211_device */
@@ -3642,10 +3714,10 @@
        int err = -ENODEV;
        unsigned long flags;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqonly(bcm, flags);
        if (likely(bcm->initialized))
                err = bcm43xx_tx(bcm, txb);
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqonly(bcm, flags);
 
        return err;
 }
@@ -3660,9 +3732,9 @@
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        unsigned long flags;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm43xx_controller_restart(bcm, "TX timeout");
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3687,9 +3759,11 @@
 static int bcm43xx_net_stop(struct net_device *net_dev)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+       int err;
 
        ieee80211softmac_stop(net_dev);
-       bcm43xx_disable_interrupts_sync(bcm, NULL);
+       err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+       assert(!err);
        bcm43xx_free_board(bcm);
 
        return 0;
@@ -3709,7 +3783,8 @@
        bcm->pci_dev = pci_dev;
        bcm->net_dev = net_dev;
        bcm->bad_frames_preempt = modparam_bad_frames_preempt;
-       spin_lock_init(&bcm->_lock);
+       spin_lock_init(&bcm->irq_lock);
+       mutex_init(&bcm->mutex);
        tasklet_init(&bcm->isr_tasklet,
                     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
                     (unsigned long)bcm);
@@ -3893,11 +3968,11 @@
 
        dprintk(KERN_INFO PFX "Suspending...\n");
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm->was_initialized = bcm->initialized;
        if (bcm->initialized)
                try_to_shutdown = 1;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        netif_device_detach(net_dev);
        if (try_to_shutdown) {
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_pio.c        
2006-04-28 16:13:40.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_pio.c     2006-06-04 
20:56:47.000000000 +0200
@@ -262,8 +262,10 @@
        int err;
        u16 txctl;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqonly(bcm, flags);
 
+       if (queue->tx_frozen)
+               goto out_unlock;
        txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
        if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
                goto out_unlock;
@@ -298,7 +300,7 @@
                continue;
        }
 out_unlock:
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void setup_txqueues(struct bcm43xx_pioqueue *queue)
@@ -484,6 +486,38 @@
        return 0;
 }
 
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+       struct bcm43xx_pio *pio;
+
+       assert(bcm43xx_using_pio(bcm));
+       pio = bcm43xx_current_pio(bcm);
+       pio->queue0->tx_frozen = 1;
+       pio->queue1->tx_frozen = 1;
+       pio->queue2->tx_frozen = 1;
+       pio->queue3->tx_frozen = 1;
+}
+
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+       struct bcm43xx_pio *pio;
+
+       assert(bcm43xx_using_pio(bcm));
+       pio = bcm43xx_current_pio(bcm);
+       pio->queue0->tx_frozen = 0;
+       pio->queue1->tx_frozen = 0;
+       pio->queue2->tx_frozen = 0;
+       pio->queue3->tx_frozen = 0;
+       if (!list_empty(&pio->queue0->txqueue))
+               tasklet_schedule(&pio->queue0->txtask);
+       if (!list_empty(&pio->queue1->txqueue))
+               tasklet_schedule(&pio->queue1->txtask);
+       if (!list_empty(&pio->queue2->txqueue))
+               tasklet_schedule(&pio->queue2->txtask);
+       if (!list_empty(&pio->queue3->txqueue))
+               tasklet_schedule(&pio->queue3->txtask);
+}
+
 void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
                                   struct bcm43xx_xmitstatus *status)
 {
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c      
2006-04-28 16:13:40.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c   2006-06-03 
21:15:23.000000000 +0200
@@ -120,12 +120,13 @@
                        GFP_KERNEL);
        if (!sprom)
                return -ENOMEM;
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        assert(bcm->initialized);
        err = bcm43xx_sprom_read(bcm, sprom);
        if (!err)
                err = sprom2hex(sprom, buf, PAGE_SIZE);
-       bcm43xx_unlock_mmio(bcm, flags);
+       mmiowb();
+       bcm43xx_unlock_irqsafe(bcm, flags);
        kfree(sprom);
 
        return err;
@@ -150,10 +151,11 @@
        err = hex2sprom(sprom, buf, count);
        if (err)
                goto out_kfree;
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        assert(bcm->initialized);
        err = bcm43xx_sprom_write(bcm, sprom);
-       bcm43xx_unlock_mmio(bcm, flags);
+       mmiowb();
+       bcm43xx_unlock_irqsafe(bcm, flags);
 out_kfree:
        kfree(sprom);
 
@@ -170,14 +172,13 @@
                                            char *buf)
 {
        struct bcm43xx_private *bcm = dev_to_bcm(dev);
-       unsigned long flags;
        int err;
        ssize_t count = 0;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_noirq(bcm);
        assert(bcm->initialized);
 
        switch (bcm43xx_current_radio(bcm)->interfmode) {
@@ -195,7 +196,7 @@
        }
        err = 0;
 
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_noirq(bcm);
 
        return err ? err : count;
 
@@ -231,7 +232,7 @@
                return -EINVAL;
        }
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        assert(bcm->initialized);
 
        err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
@@ -239,8 +240,8 @@
                printk(KERN_ERR PFX "Interference Mitigation not "
                                    "supported by device\n");
        }
-
-       bcm43xx_unlock_mmio(bcm, flags);
+       mmiowb();
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err ? err : count;
 }
@@ -254,14 +255,13 @@
                                          char *buf)
 {
        struct bcm43xx_private *bcm = dev_to_bcm(dev);
-       unsigned long flags;
        int err;
        ssize_t count;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_noirq(bcm);
        assert(bcm->initialized);
 
        if (bcm->short_preamble)
@@ -270,7 +270,7 @@
                count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble 
disabled)\n");
 
        err = 0;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_noirq(bcm);
 
        return err ? err : count;
 }
@@ -290,13 +290,13 @@
        value = get_boolean(buf, count);
        if (value < 0)
                return value;
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        assert(bcm->initialized);
 
        bcm->short_preamble = !!value;
 
        err = 0;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err ? err : count;
 }
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_wx.c 2006-05-25 
20:54:02.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_wx.c      2006-06-04 
20:49:46.000000000 +0200
@@ -55,13 +55,13 @@
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        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(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        for (i = 0; i < bcm->nr_80211_available; i++) {
                phy = &(bcm->core_80211_ext[i].phy);
                switch (phy->type) {
@@ -77,7 +77,7 @@
                        assert(0);
                }
        }
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        i = 0;
        if (have_a) {
@@ -111,7 +111,7 @@
        int freq;
        int err = -EINVAL;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
                channel = data->freq.m;
                freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -131,7 +131,7 @@
                err = 0;
        }
 out_unlock:
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err;
 }
@@ -147,7 +147,7 @@
        int err = -ENODEV;
        u16 channel;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        radio = bcm43xx_current_radio(bcm);
        channel = radio->channel;
        if (channel == 0xFF) {
@@ -163,7 +163,7 @@
 
        err = 0;
 out_unlock:
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err;
 }
@@ -181,13 +181,13 @@
        if (mode == IW_MODE_AUTO)
                mode = BCM43xx_INITIAL_IWMODE;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (bcm->initialized) {
                if (bcm->ieee->iw_mode != mode)
                        bcm43xx_set_iwmode(bcm, mode);
        } else
                bcm->ieee->iw_mode = mode;
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return 0;
 }
@@ -200,9 +200,9 @@
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        unsigned long flags;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        data->mode = bcm->ieee->iw_mode;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return 0;
 }
@@ -255,7 +255,7 @@
                          IW_ENC_CAPA_CIPHER_TKIP |
                          IW_ENC_CAPA_CIPHER_CCMP;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        phy = bcm43xx_current_phy(bcm);
 
        range->num_bitrates = 0;
@@ -302,7 +302,7 @@
        }
        range->num_frequency = j;
 
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return 0;
 }
@@ -313,14 +313,13 @@
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        size_t len;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_noirq(bcm);
        len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
        memcpy(bcm->nick, extra, len);
        bcm->nick[len] = '\0';
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_noirq(bcm);
 
        return 0;
 }
@@ -331,15 +330,14 @@
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        size_t len;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_noirq(bcm);
        len = strlen(bcm->nick) + 1;
        memcpy(extra, bcm->nick, len);
        data->data.length = (__u16)len;
        data->data.flags = 1;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_noirq(bcm);
 
        return 0;
 }
@@ -353,7 +351,7 @@
        unsigned long flags;
        int err = -EINVAL;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (data->rts.disabled) {
                bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
                err = 0;
@@ -364,7 +362,7 @@
                        err = 0;
                }
        }
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err;
 }
@@ -377,11 +375,11 @@
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        unsigned long flags;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        data->rts.value = bcm->rts_threshold;
        data->rts.fixed = 0;
        data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return 0;
 }
@@ -395,7 +393,7 @@
        unsigned long flags;
        int err = -EINVAL;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (data->frag.disabled) {
                bcm->ieee->fts = MAX_FRAG_THRESHOLD;
                err = 0;
@@ -406,7 +404,7 @@
                        err = 0;
                }
        }
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err;
 }
@@ -419,11 +417,11 @@
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        unsigned long flags;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        data->frag.value = bcm->ieee->fts;
        data->frag.fixed = 0;
        data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return 0;
 }
@@ -445,7 +443,7 @@
                return -EOPNOTSUPP;
        }
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (!bcm->initialized)
                goto out_unlock;
        radio = bcm43xx_current_radio(bcm);
@@ -469,7 +467,7 @@
        err = 0;
 
 out_unlock:
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err;
 }
@@ -484,7 +482,7 @@
        unsigned long flags;
        int err = -ENODEV;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (!bcm->initialized)
                goto out_unlock;
        radio = bcm43xx_current_radio(bcm);
@@ -496,7 +494,7 @@
 
        err = 0;
 out_unlock:
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err;
 }
@@ -583,7 +581,7 @@
                return -EINVAL;
        }
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        if (bcm->initialized) {
                err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
                if (err) {
@@ -598,7 +596,7 @@
                } else
                        bcm43xx_current_radio(bcm)->interfmode = mode;
        }
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return err;
 }
@@ -612,9 +610,9 @@
        unsigned long flags;
        int mode;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        mode = bcm43xx_current_radio(bcm)->interfmode;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        switch (mode) {
        case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -644,9 +642,9 @@
        int on;
 
        on = *((int *)extra);
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm->short_preamble = !!on;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return 0;
 }
@@ -660,9 +658,9 @@
        unsigned long flags;
        int on;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        on = bcm->short_preamble;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        if (on)
                strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -684,11 +682,11 @@
        
        on = *((int *)extra);
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        bcm->ieee->host_encrypt = !!on;
        bcm->ieee->host_decrypt = !!on;
        bcm->ieee->host_build_iv = !on;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        return 0;
 }
@@ -702,9 +700,9 @@
        unsigned long flags;
        int on;
 
-       bcm43xx_lock(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        on = bcm->ieee->host_encrypt;
-       bcm43xx_unlock(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 
        if (on)
                strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -767,11 +765,11 @@
        if (!sprom)
                goto out;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        err = -ENODEV;
        if (bcm->initialized)
                err = bcm43xx_sprom_read(bcm, sprom);
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
        if (!err)
                data->data.length = sprom2hex(sprom, extra);
        kfree(sprom);
@@ -812,11 +810,11 @@
        if (err)
                goto out_kfree;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       bcm43xx_lock_irqsafe(bcm, flags);
        err = -ENODEV;
        if (bcm->initialized)
                err = bcm43xx_sprom_write(bcm, sprom);
-       bcm43xx_unlock_mmio(bcm, flags);
+       bcm43xx_unlock_irqsafe(bcm, flags);
 out_kfree:
        kfree(sprom);
 out:
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_phy.c        
2006-06-03 21:04:17.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_phy.c     2006-06-04 
20:51:38.000000000 +0200
@@ -1410,7 +1410,10 @@
 u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+       u16 ret;
+       unsigned long flags;
 
+       local_irq_save(flags);
        if (phy->connected) {
                bcm43xx_phy_write(bcm, 0x15, 0xE300);
                control <<= 8;
@@ -1430,8 +1433,10 @@
                bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
                udelay(8);
        }
+       ret = bcm43xx_phy_read(bcm, 0x002D);
+       local_irq_restore(flags);
 
-       return bcm43xx_phy_read(bcm, 0x002D);
+       return ret;
 }
 
 static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 
control)
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_pio.h        
2006-04-28 16:13:40.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_pio.h     2006-06-04 
20:55:53.000000000 +0200
@@ -54,6 +54,7 @@
        u16 mmio_base;
 
        u8 tx_suspended:1,
+          tx_frozen:1,
           need_workarounds:1; /* Workarounds needed for core.rev < 3 */
 
        /* Adjusted size of the device internal TX buffer. */
@@ -104,6 +105,8 @@
 
 int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
                   struct ieee80211_txb *txb);
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm);
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm);
 void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
                                   struct bcm43xx_xmitstatus *status);
 void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
@@ -129,6 +132,14 @@
        return 0;
 }
 static inline
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+}
+static inline
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+}
+static inline
 void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
                                   struct bcm43xx_xmitstatus *status)
 {


-- 
Greetings Michael.
_______________________________________________
Bcm43xx-dev mailing list
[email protected]
http://lists.berlios.de/mailman/listinfo/bcm43xx-dev

Reply via email to