Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[powerpc.git] / drivers / net / wireless / bcm43xx / bcm43xx_main.c
index a94c6d8..a1b7838 100644 (file)
@@ -746,7 +746,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
        if (err)
                goto err_ctlreg;
        spromctl |= 0x10; /* SPROM WRITE enable. */
-       bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+       err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
        if (err)
                goto err_ctlreg;
        /* We must burn lots of CPU cycles here, but that does not
@@ -768,7 +768,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
                mdelay(20);
        }
        spromctl &= ~0x10; /* SPROM WRITE enable. */
-       bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+       err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
        if (err)
                goto err_ctlreg;
        mdelay(500);
@@ -1463,6 +1463,23 @@ static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
        }
 }
 
+static void drain_txstatus_queue(struct bcm43xx_private *bcm)
+{
+       u32 dummy;
+
+       if (bcm->current_core->rev < 5)
+               return;
+       /* Read all entries from the microcode TXstatus FIFO
+        * and throw them away.
+        */
+       while (1) {
+               dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
+               if (!dummy)
+                       break;
+               dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
+       }
+}
+
 static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
 {
        bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
@@ -3163,9 +3180,11 @@ static int estimate_periodic_work_badness(unsigned int state)
 static void bcm43xx_periodic_work_handler(void *d)
 {
        struct bcm43xx_private *bcm = d;
+       struct net_device *net_dev = bcm->net_dev;
        unsigned long flags;
        u32 savedirqs = 0;
        int badness;
+       unsigned long orig_trans_start = 0;
 
        mutex_lock(&bcm->mutex);
        badness = estimate_periodic_work_badness(bcm->periodic_state);
@@ -3173,7 +3192,18 @@ static void bcm43xx_periodic_work_handler(void *d)
                /* Periodic work will take a long time, so we want it to
                 * be preemtible.
                 */
-               netif_tx_disable(bcm->net_dev);
+
+               netif_tx_lock_bh(net_dev);
+               /* We must fake a started transmission here, as we are going to
+                * disable TX. If we wouldn't fake a TX, it would be possible to
+                * trigger the netdev watchdog, if the last real TX is already
+                * some time on the past (slightly less than 5secs)
+                */
+               orig_trans_start = net_dev->trans_start;
+               net_dev->trans_start = jiffies;
+               netif_stop_queue(net_dev);
+               netif_tx_unlock_bh(net_dev);
+
                spin_lock_irqsave(&bcm->irq_lock, flags);
                bcm43xx_mac_suspend(bcm);
                if (bcm43xx_using_pio(bcm))
@@ -3198,6 +3228,7 @@ static void bcm43xx_periodic_work_handler(void *d)
                        bcm43xx_pio_thaw_txqueues(bcm);
                bcm43xx_mac_enable(bcm);
                netif_wake_queue(bcm->net_dev);
+               net_dev->trans_start = orig_trans_start;
        }
        mmiowb();
        spin_unlock_irqrestore(&bcm->irq_lock, flags);
@@ -3518,6 +3549,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
        bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
        bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
        bcm43xx_security_init(bcm);
+       drain_txstatus_queue(bcm);
        ieee80211softmac_start(bcm->net_dev);
 
        /* Let's go! Be careful after enabling the IRQs.