This patch is supposed to heavily increase overall system
vitality. It reduces the time periodic work in the bcm43xx driver
is run, with IRQs disabled, from several msecs to a few usecs.

I am not sure, if we still want to have this in 2.6.17, as
it is not a crash fix or something. But it fixes "lost interrupt"
problems for some people.

I would like to get this into wireless-2.6, but before that
happens I would like to have a few regression tests by people.
Please apply this and run high network traffic for 10-15 minutes.
Please enable kernel spinlock lockup and recursion detection
while testing.

--


Enable local CPU IRQs while executing periodic work handlers.
Periodic work handlers may take a long time to execute,
so disabling IRQs for the whole time is a bad idea.

This patch disables and synchronizes all bcm43xx IRQs on
periodic work entry and re-enables CPU IRQs afterwards.
It still tempoarly disables CPU IRQs while measuring the
deviation value, as I have the feeling that this is time
critical and may not be interrupted. This causes IRQs to be
disabled for about 35usecs. I hope that does not hurt.

This is an attempt to reduce system IRQ pressure and avoid
lost IRQs in other devices.

Signed-off-by: Michael Buesch <[EMAIL PROTECTED]>

Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx.h    2006-05-22 
13:32:34.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx.h 2006-05-22 
14:14:18.000000000 +0200
@@ -647,9 +647,7 @@
        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;
+       spinlock_t lock;
 
        /* Driver status flags. */
        u32 initialized:1,              /* init_board() succeed */
@@ -753,8 +751,8 @@
  * 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)
+#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
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_main.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c       
2006-05-22 13:32:34.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_main.c    2006-05-22 
14:40:08.000000000 +0200
@@ -496,20 +496,34 @@
        return old_mask;
 }
 
-/* Make sure we don't receive more data from the device. */
+/* Disable IRQs on the device and make sure no IRQ handler
+ * (or tasklet) is running on return.
+ */
 static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 
*oldstate)
 {
        u32 old;
        unsigned long flags;
+       unsigned int irq;
 
        bcm43xx_lock_mmio(bcm, flags);
-       if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
+       if (unlikely(bcm43xx_is_initializing(bcm) ||
+                    bcm->shutting_down)) {
                bcm43xx_unlock_mmio(bcm, flags);
                return -EBUSY;
        }
+       irq = bcm->irq;
        old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-       tasklet_disable(&bcm->isr_tasklet);
+
+       /* Unlock, so running IRQ handlers or tasklets can return
+        * and don't deadlock.
+        * The access of isr_tasklet after unlocking is Ok, because
+        * it can not race after synchronizing IRQ.
+        */
        bcm43xx_unlock_mmio(bcm, flags);
+
+       synchronize_irq(irq);
+       tasklet_disable(&bcm->isr_tasklet);
+
        if (oldstate)
                *oldstate = old;
 
@@ -1860,7 +1874,7 @@
        if (!bcm)
                return IRQ_NONE;
 
-       spin_lock(&bcm->_lock);
+       spin_lock(&bcm->lock);
 
        reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
        if (reason == 0xffffffff) {
@@ -1899,7 +1913,7 @@
 
 out:
        mmiowb();
-       spin_unlock(&bcm->_lock);
+       spin_unlock(&bcm->lock);
 
        return ret;
 }
@@ -3101,8 +3115,19 @@
        struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
        unsigned long flags;
        unsigned int state;
+       u32 savedirqs;
+       int err;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       err = bcm43xx_disable_interrupts_sync(bcm, &savedirqs);
+       assert(!err);
+       /* Periodic work can take a long time so we don't want
+        * to disable IRQs on the CPU.
+        * spin_lock() is deadlock safe here, because we previously
+        * disabled and synced IRQs on the device. No IRQ is supposed
+        * to happen before bcm43xx_interrupt_enable(), so it
+        * can't deadlock with the spin_lock in the IRQ handler.
+        */
+       spin_lock(&bcm->lock);
 
        assert(bcm->initialized);
        state = bcm->periodic_state;
@@ -3117,7 +3142,12 @@
 
        mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
 
-       bcm43xx_unlock_mmio(bcm, flags);
+       local_irq_save(flags);
+       bcm43xx_interrupt_enable(bcm, savedirqs);
+       tasklet_enable(&bcm->isr_tasklet);
+       mmiowb();
+       spin_unlock(&bcm->lock);
+       local_irq_restore(flags);
 }
 
 static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
@@ -3678,9 +3708,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;
@@ -3700,7 +3732,7 @@
        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->lock);
        tasklet_init(&bcm->isr_tasklet,
                     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
                     (unsigned long)bcm);
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_phy.c        
2006-05-22 13:32:34.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_phy.c     2006-05-22 
14:20:57.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)
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to