rpms/kernel/FC-6 linux-2.6-net_bcm43xx_1GB_DMA_fix.patch,1.1,1.2

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Tue Feb 20 18:44:26 UTC 2007


Author: cebbert

Update of /cvs/dist/rpms/kernel/FC-6
In directory cvs.devel.redhat.com:/tmp/cvs-serv30340

Modified Files:
	linux-2.6-net_bcm43xx_1GB_DMA_fix.patch 
Log Message:
the real bcm43xx fix


linux-2.6-net_bcm43xx_1GB_DMA_fix.patch:
 bcm43xx.h     |    1 
 bcm43xx_dma.c |  175 +++++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 127 insertions(+), 49 deletions(-)

Index: linux-2.6-net_bcm43xx_1GB_DMA_fix.patch
===================================================================
RCS file: /cvs/dist/rpms/kernel/FC-6/linux-2.6-net_bcm43xx_1GB_DMA_fix.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- linux-2.6-net_bcm43xx_1GB_DMA_fix.patch	20 Feb 2007 17:42:19 -0000	1.1
+++ linux-2.6-net_bcm43xx_1GB_DMA_fix.patch	20 Feb 2007 18:44:19 -0000	1.2
@@ -1,142 +1,304 @@
 # HG changeset patch
 # User Larry Finger <Larry.Finger at lwfinger.net>
-# Date 1161043788 -14400
-# Node ID 7f32f2e817c799bd252c7dc31e91c0105faa987d
-# Parent 930b764a86abde65a1ec48ceceddface5925b2a6
-[PATCH] bcm43xx-softmac: Fix system hang for x86-64 with >1GB RAM
+# Date 1170879833 18000
+# Node ID 3efe2454e9dd750eb5e9fd0972975b5e083d7414
+# Parent 12751b4ad8dc89f62cbb83f67f26be4c76b0f142
+[PATCH] bcm43xx: Fix problem with >1 GB RAM
 
-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.
+Some versions of the bcm43xx chips only support 30-bit DMA, which means
+that the descriptors and buffers must be in the first 1 GB of RAM. On
+the i386 and x86_64 architectures with more than 1 GB RAM, an incorrect
+assignment may occur. This patch ensures that the various DMA addresses
+are within the capability of the chip. Testing has been limited to x86_64
+as no one has an i386 system with more than 1 GB RAM.
 
 Signed-off-by: Larry Finger <Larry.Finger at lwfinger.net>
 Signed-off-by: John W. Linville <linville at tuxdriver.com>
 
-committer: John W. Linville <linville at tuxdriver.com> 1161043788 -0400
+committer: John W. Linville <linville at tuxdriver.com>
 
-
---- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c	Tue Oct 17 04:09:47 2006 +0400
-+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c	Tue Oct 17 04:09:48 2006 +0400
-@@ -705,11 +705,30 @@ int bcm43xx_dma_init(struct bcm43xx_priv
+--- a/drivers/net/wireless/bcm43xx/bcm43xx.h	Wed Feb 07 15:23:53 2007 -0500
++++ b/drivers/net/wireless/bcm43xx/bcm43xx.h	Wed Feb 07 15:23:53 2007 -0500
+@@ -766,6 +766,7 @@ struct bcm43xx_private {
+ 	 * This is currently always BCM43xx_BUSTYPE_PCI
+ 	 */
+ 	u8 bustype;
++	u64 dma_mask;
+ 
+ 	u16 board_vendor;
+ 	u16 board_type;
+--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c	Wed Feb 07 15:23:53 2007 -0500
++++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c	Wed Feb 07 15:23:53 2007 -0500
+@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx
+ 			  int tx)
+ {
+ 	dma_addr_t dmaaddr;
+-
+-	if (tx) {
+-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
++	int direction = PCI_DMA_FROMDEVICE;
++
++	if (tx)
++		direction = PCI_DMA_TODEVICE;
++
++	dmaaddr = pci_map_single(ring->bcm->pci_dev,
+ 					 buf, len,
+-					 DMA_TO_DEVICE);
+-	} else {
+-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+-					 buf, len,
+-					 DMA_FROM_DEVICE);
+-	}
++					 direction);
+ 
+ 	return dmaaddr;
+ }
+@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dma
+ 		      int tx)
+ {
+ 	if (tx) {
+-		dma_unmap_single(&ring->bcm->pci_dev->dev,
++		pci_unmap_single(ring->bcm->pci_dev,
+ 				 addr, len,
+-				 DMA_TO_DEVICE);
++				 PCI_DMA_TODEVICE);
+ 	} else {
+-		dma_unmap_single(&ring->bcm->pci_dev->dev,
++		pci_unmap_single(ring->bcm->pci_dev,
+ 				 addr, len,
+-				 DMA_FROM_DEVICE);
++				 PCI_DMA_FROMDEVICE);
+ 	}
+ }
+ 
+@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm4
+ {
+ 	assert(!ring->tx);
+ 
+-	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
+-				addr, len, DMA_FROM_DEVICE);
++	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
++				    addr, len, PCI_DMA_FROMDEVICE);
+ }
+ 
+ static inline
+@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct b
+ {
+ 	assert(!ring->tx);
+ 
+-	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
+-				   addr, len, DMA_FROM_DEVICE);
++	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
++				    addr, len, PCI_DMA_TODEVICE);
+ }
+ 
+ /* Unmap and free a descriptor buffer. */
+@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43
+ 
+ static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
+ {
+-	struct device *dev = &(ring->bcm->pci_dev->dev);
+-
+-	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+-					    &(ring->dmabase), GFP_KERNEL);
++	ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
++					    &(ring->dmabase));
+ 	if (!ring->descbase) {
+-		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+-		return -ENOMEM;
++		/* Allocation may have failed due to pci_alloc_consistent
++		   insisting on use of GFP_DMA, which is more restrictive
++		   than necessary...  */
++		struct dma_desc *rx_ring;
++		dma_addr_t rx_ring_dma;
++
++		rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
++		if (!rx_ring)
++			goto out_err;
++
++		rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
++					     BCM43xx_DMA_RINGMEMSIZE,
++					     PCI_DMA_BIDIRECTIONAL);
++
++		if (pci_dma_mapping_error(rx_ring_dma) ||
++		    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
++			/* Sigh... */
++			if (!pci_dma_mapping_error(rx_ring_dma))
++				pci_unmap_single(ring->bcm->pci_dev,
++						 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
++						 PCI_DMA_BIDIRECTIONAL);
++			rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
++						 rx_ring, BCM43xx_DMA_RINGMEMSIZE,
++						 PCI_DMA_BIDIRECTIONAL);
++			if (pci_dma_mapping_error(rx_ring_dma) ||
++			    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
++				assert(0);
++				if (!pci_dma_mapping_error(rx_ring_dma))
++					pci_unmap_single(ring->bcm->pci_dev,
++							 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
++							 PCI_DMA_BIDIRECTIONAL);
++				goto out_err;
++			}
++                }
++
++                ring->descbase = rx_ring;
++                ring->dmabase = rx_ring_dma;
+ 	}
+ 	memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+ 
+ 	return 0;
++out_err:
++	printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
++	return -ENOMEM;
+ }
+ 
+ static void free_ringmemory(struct bcm43xx_dmaring *ring)
+@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bc
+ 	if (unlikely(!skb))
+ 		return -ENOMEM;
+ 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
++	/* This hardware bug work-around adapted from the b44 driver.
++	   The chip may be unable to do PCI DMA to/from anything above 1GB */
++	if (pci_dma_mapping_error(dmaaddr) ||
++	    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
++		/* This one has 30-bit addressing... */
++		if (!pci_dma_mapping_error(dmaaddr))
++			pci_unmap_single(ring->bcm->pci_dev,
++					 dmaaddr, ring->rx_buffersize,
++					 PCI_DMA_FROMDEVICE);
++		dev_kfree_skb_any(skb);
++		skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
++		if (skb == NULL)
++			return -ENOMEM;
++		dmaaddr = pci_map_single(ring->bcm->pci_dev,
++					 skb->data, ring->rx_buffersize,
++					 PCI_DMA_FROMDEVICE);
++		if (pci_dma_mapping_error(dmaaddr) ||
++		    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
++			assert(0);
++			dev_kfree_skb_any(skb);
++			return -ENOMEM;
++		}
++	}
+ 	meta->skb = skb;
+ 	meta->dmaaddr = dmaaddr;
+ 	skb->dev = ring->bcm->net_dev;
+@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_d
+ 	err = dmacontroller_setup(ring);
+ 	if (err)
+ 		goto err_free_ringmemory;
++	return ring;
+ 
+ out:
++	printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
+ 	return ring;
+ 
+ err_free_ringmemory:
+@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_priv
  	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)
-+	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
-+	int nobits;
+-	if (mask == DMA_64BIT_MASK) {
 +
-+	if (mask == DMA_64BIT_MASK) {
++	bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
++	if (bcm->dma_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 */
-+	}
+-		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 */
+-	}
++	err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
++	if (err)
++		goto no_dma;
++	err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
++	if (err)
++		goto no_dma;
  
  	/* setup TX DMA channels. */
  	ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
-@@ -755,8 +774,7 @@ int bcm43xx_dma_init(struct bcm43xx_priv
+@@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_priv
  		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);
+-	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
++	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
++		(bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
++		(bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
  	err = 0;
  out:
  	return err;
---- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h	Tue Oct 17 04:09:47 2006 +0400
-+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h	Tue Oct 17 04:09:48 2006 +0400
-@@ -314,6 +314,23 @@ int bcm43xx_dma_tx(struct bcm43xx_privat
- 		   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 */
- 
- 
---- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c	Tue Oct 17 04:09:47 2006 +0400
-+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c	Tue Oct 17 04:09:48 2006 +0400
-@@ -2925,10 +2925,13 @@ static int bcm43xx_wireless_core_init(st
- 		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);
+@@ -800,7 +847,17 @@ err_destroy_tx0:
+ err_destroy_tx0:
+ 	bcm43xx_destroy_dmaring(dma->tx_ring0);
+ 	dma->tx_ring0 = NULL;
+-	goto out;
++no_dma:
++#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 */
+ }
+ 
+ /* Generate a cookie for the TX header. */
+@@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43
+ 	struct bcm43xx_dmadesc_generic *desc;
+ 	struct bcm43xx_dmadesc_meta *meta;
+ 	dma_addr_t dmaaddr;
++	struct sk_buff *bounce_skb;
+ 
+ 	assert(skb_shinfo(skb)->nr_frags == 0);
+ 
+@@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43
+ 			       skb->len - sizeof(struct bcm43xx_txhdr),
+ 			       (cur_frag == 0),
+ 			       generate_cookie(ring, slot));
++	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
++	if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
++		/* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
++		if (!dma_mapping_error(dmaaddr))
++			unmap_descbuffer(ring, dmaaddr, skb->len, 1);
++		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
++		if (!bounce_skb)
++			return;
++		dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
++		if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
++			if (!dma_mapping_error(dmaaddr))
++				unmap_descbuffer(ring, dmaaddr, skb->len, 1);
++			dev_kfree_skb_any(bounce_skb);
++			assert(0);
++			return;
 +		}
- 		if (err)
- 			goto err_chip_cleanup;
- 	}
-@@ -3992,8 +3995,6 @@ static int bcm43xx_init_private(struct b
- 				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 b
- 		     (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;
++		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
++		dev_kfree_skb_any(skb);
++		skb = bounce_skb;
++	}
+ 
+ 	meta->skb = skb;
+-	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ 	meta->dmaaddr = dmaaddr;
  
- 	/* default to sw encryption for now */
+ 	fill_descriptor(ring, desc, dmaaddr,




More information about the fedora-cvs-commits mailing list