[PATCH] bcm43xx-softmac: Fix system hang for x86-64 with >1GB RAM
authorLarry Finger <Larry.Finger@lwfinger.net>
Tue, 3 Oct 2006 04:48:54 +0000 (23:48 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 17 Oct 2006 00:09:48 +0000 (20:09 -0400)
The bcm43xx-softmac software currently fails when running on x86_64 systems
with more than 1GB RAM and one of the card variants with 30-bit DMA addressing.
This patch uses the address extension bits in the hardware to set the correct
DMA mask for the specific card in use.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/bcm43xx/bcm43xx_dma.c
drivers/net/wireless/bcm43xx/bcm43xx_dma.h
drivers/net/wireless/bcm43xx/bcm43xx_main.c

index 76e3aed..978ed09 100644 (file)
@@ -705,11 +705,30 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
        struct bcm43xx_dmaring *ring;
        int err = -ENOMEM;
        int dma64 = 0;
-       u32 sbtmstatehi;
+       u64 mask = bcm43xx_get_supported_dma_mask(bcm);
+       int nobits;
 
-       sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
-       if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT)
+       if (mask == DMA_64BIT_MASK) {
                dma64 = 1;
+               nobits = 64;
+       } else if (mask == DMA_32BIT_MASK)
+               nobits = 32;
+       else
+               nobits = 30;
+       err = pci_set_dma_mask(bcm->pci_dev, mask);
+       err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
+       if (err) {
+#ifdef CONFIG_BCM43XX_PIO
+               printk(KERN_WARNING PFX "DMA not supported on this device."
+                                       " Falling back to PIO.\n");
+               bcm->__using_pio = 1;
+               return -ENOSYS;
+#else
+               printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+                                   "Please recompile the driver with PIO support.\n");
+               return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
+       }
 
        /* setup TX DMA channels. */
        ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -755,8 +774,7 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
                dma->rx_ring3 = ring;
        }
 
-       dprintk(KERN_INFO PFX "%s DMA initialized\n",
-                       dma64 ? "64-bit" : "32-bit");
+       dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
        err = 0;
 out:
        return err;
index e04bcad..ea16078 100644 (file)
@@ -314,6 +314,23 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
                   struct ieee80211_txb *txb);
 void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
 
+/* Helper function that returns the dma mask for this device. */
+static inline
+u64 bcm43xx_get_supported_dma_mask(struct bcm43xx_private *bcm)
+{
+       int dma64 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH) &
+                                  BCM43xx_SBTMSTATEHIGH_DMA64BIT;
+       u16 mmio_base = bcm43xx_dmacontroller_base(dma64, 0);
+       u32 mask = BCM43xx_DMA32_TXADDREXT_MASK;
+
+       if (dma64)
+               return DMA_64BIT_MASK;
+       bcm43xx_write32(bcm, mmio_base + BCM43xx_DMA32_TXCTL, mask);
+       if (bcm43xx_read32(bcm, mmio_base + BCM43xx_DMA32_TXCTL) & mask)
+               return DMA_32BIT_MASK;
+       return DMA_30BIT_MASK;
+}
+
 #else /* CONFIG_BCM43XX_DMA */
 
 
index 7776b5c..a94c6d8 100644 (file)
@@ -2925,10 +2925,13 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
                bcm43xx_write16(bcm, 0x043C, 0x000C);
 
        if (active_wlcore) {
-               if (bcm43xx_using_pio(bcm))
+               if (bcm43xx_using_pio(bcm)) {
                        err = bcm43xx_pio_init(bcm);
-               else
+               } else {
                        err = bcm43xx_dma_init(bcm);
+                       if (err == -ENOSYS)
+                               err = bcm43xx_pio_init(bcm);
+               }
                if (err)
                        goto err_chip_cleanup;
        }
@@ -3992,8 +3995,6 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
                                struct net_device *net_dev,
                                struct pci_dev *pci_dev)
 {
-       int err;
-
        bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
        bcm->ieee = netdev_priv(net_dev);
        bcm->softmac = ieee80211_priv(net_dev);
@@ -4011,22 +4012,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
                     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
                     (unsigned long)bcm);
        tasklet_disable_nosync(&bcm->isr_tasklet);
-       if (modparam_pio) {
+       if (modparam_pio)
                bcm->__using_pio = 1;
-       } else {
-               err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
-               err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
-               if (err) {
-#ifdef CONFIG_BCM43XX_PIO
-                       printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
-                       bcm->__using_pio = 1;
-#else
-                       printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
-                                           "Recompile the driver with PIO support, please.\n");
-                       return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
-               }
-       }
        bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
 
        /* default to sw encryption for now */