netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] bcm43xx: Fix problem with >1 GB RAM
@ 2007-01-20 16:18 Larry Finger
  2007-01-22 18:20 ` Michael Buesch
  0 siblings, 1 reply; 6+ messages in thread
From: Larry Finger @ 2007-01-20 16:18 UTC (permalink / raw)
  To: John Linville
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, Bcm43xx-dev-0fE9KPoRgkgATYTw5x5z8w,
	Michael Buesch

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-tQ5ms3gMjBLk1uMJSBkQmQ@public.gmane.org>
---

John,

This patch should be applied to wireless-2.6 and pushed up to 2.6.20.

Thanks,

Larry

Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
===================================================================
--- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx
 			  int tx)
 {
 	dma_addr_t dmaaddr;
+	int direction = PCI_DMA_FROMDEVICE;
 
-	if (tx) {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
-					 buf, len,
-					 DMA_TO_DEVICE);
-	} else {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+	if (tx)
+		direction = PCI_DMA_TODEVICE;
+
+	dmaaddr = pci_map_single(ring->bcm->pci_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;
-	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
-	int nobits;
 
-	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 */
-	}
+	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);
@@ -774,9 +819,12 @@ int bcm43xx_dma_init(struct bcm43xx_priv
 		dma->rx_ring3 = ring;
 	}
 
-	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:
+	if(err)BUG();
 	return err;
 
 err_destroy_rx0:
@@ -800,7 +848,18 @@ err_destroy_tx1:
 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;
+	BUG();
+	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 +964,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 +984,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;
+		}
+		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;
 
 	fill_descriptor(ring, desc, dmaaddr,
Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx.h
===================================================================
--- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -771,6 +771,7 @@ struct bcm43xx_private {
 	 * This is currently always BCM43xx_BUSTYPE_PCI
 	 */
 	u8 bustype;
+	u64 dma_mask;
 
 	u16 board_vendor;
 	u16 board_type;

---

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] bcm43xx: Fix problem with >1 GB RAM
  2007-01-20 16:18 [PATCH] bcm43xx: Fix problem with >1 GB RAM Larry Finger
@ 2007-01-22 18:20 ` Michael Buesch
  2007-01-22 20:18   ` Larry Finger
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Buesch @ 2007-01-22 18:20 UTC (permalink / raw)
  To: Larry Finger; +Cc: John Linville, netdev, Bcm43xx-dev

On Saturday 20 January 2007 17:18, Larry Finger wrote:
> 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@lwfinger.net>
> ---
> 
> John,
> 
> This patch should be applied to wireless-2.6 and pushed up to 2.6.20.
> 
> Thanks,
> 
> Larry
> 
> Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> ===================================================================
> --- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> +++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> @@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx
>  			  int tx)
>  {
>  	dma_addr_t dmaaddr;
> +	int direction = PCI_DMA_FROMDEVICE;
>  
> -	if (tx) {
> -		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
> -					 buf, len,
> -					 DMA_TO_DEVICE);
> -	} else {
> -		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
> +	if (tx)
> +		direction = PCI_DMA_TODEVICE;
> +
> +	dmaaddr = pci_map_single(ring->bcm->pci_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);
>  }

Any special reason why you convert the DMA operations to the PCI
stuff? I ask, because if this makes a difference, it affects the
new SSB subsystem as well.

>  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;
> -	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
> -	int nobits;
>  
> -	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 */
> -	}
> +	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);
> @@ -774,9 +819,12 @@ int bcm43xx_dma_init(struct bcm43xx_priv
>  		dma->rx_ring3 = ring;
>  	}
>  
> -	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:
> +	if(err)BUG();
>  	return err;
>  
>  err_destroy_rx0:
> @@ -800,7 +848,18 @@ err_destroy_tx1:
>  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;
> +	BUG();

That isn't a BUG. Just remove this call, please.

> +	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 +964,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 +984,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;
> +		}
> +		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;
>  
>  	fill_descriptor(ring, desc, dmaaddr,
> Index: linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx.h
> ===================================================================
> --- linux-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx.h
> +++ linux-2.6/drivers/net/wireless/bcm43xx/bcm43xx.h
> @@ -771,6 +771,7 @@ struct bcm43xx_private {
>  	 * This is currently always BCM43xx_BUSTYPE_PCI
>  	 */
>  	u8 bustype;
> +	u64 dma_mask;
>  
>  	u16 board_vendor;
>  	u16 board_type;

The rest is OK, I think.
Thanks for the nice work.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] bcm43xx: Fix problem with >1 GB RAM
  2007-01-22 18:20 ` Michael Buesch
@ 2007-01-22 20:18   ` Larry Finger
  2007-01-22 20:35     ` Michael Buesch
  2007-01-23 15:18     ` Dan Williams
  0 siblings, 2 replies; 6+ messages in thread
From: Larry Finger @ 2007-01-22 20:18 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John Linville, netdev, Bcm43xx-dev

Michael Buesch wrote:
> On Saturday 20 January 2007 17:18, Larry Finger wrote:
>> 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@lwfinger.net>
>> ---

..snip..

>>  	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);
>>  }
> 
> Any special reason why you convert the DMA operations to the PCI
> stuff? I ask, because if this makes a difference, it affects the
> new SSB subsystem as well.

When I looked at the b44 driver to see how that code handled the problem, it used the pci-form of
the calls rather than the dma-version. Thus I switched early in the debug process - even before I
had the necessary hardware. Once I got it working and understood the problem, I never tried
restoring the dma-forms.

At present, I have a problem getting NetworkManager to see the d80211 wireless interface. Once I get
that solved, I plan to use my system to test with > 1 GB RAM on your git tree. In that case, I'll
switch to the pci-form only if necessary.

> 
>>  static inline
>> @@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct b

..snip..

>> -	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;
>> +	BUG();
> 
> That isn't a BUG. Just remove this call, please.

It was accidentally left in from my debugging. I have already submitted a revised version to
Linville that removes this, and one other BUG statement that you didn't note.


>> +	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 */
>>  }

..snip..

>>  	u16 board_vendor;
>>  	u16 board_type;
> 
> The rest is OK, I think.
> Thanks for the nice work.

Thank you. It certainly was a lot easier with the necessary hardware in house.

Larry


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] bcm43xx: Fix problem with >1 GB RAM
  2007-01-22 20:18   ` Larry Finger
@ 2007-01-22 20:35     ` Michael Buesch
  2007-01-23 15:18     ` Dan Williams
  1 sibling, 0 replies; 6+ messages in thread
From: Michael Buesch @ 2007-01-22 20:35 UTC (permalink / raw)
  To: Larry Finger; +Cc: John Linville, netdev, Bcm43xx-dev

On Monday 22 January 2007 21:18, Larry Finger wrote:
> When I looked at the b44 driver to see how that code handled the problem, it used the pci-form of
> the calls rather than the dma-version. Thus I switched early in the debug process - even before I
> had the necessary hardware. Once I got it working and understood the problem, I never tried
> restoring the dma-forms.

Ok, I see. I'm OK with that.

> > That isn't a BUG. Just remove this call, please.
> 
> It was accidentally left in from my debugging. I have already submitted a revised version to
> Linville that removes this, and one other BUG statement that you didn't note.

Yeah, saw it too late. That patch is ACKed then by me.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] bcm43xx: Fix problem with >1 GB RAM
  2007-01-22 20:18   ` Larry Finger
  2007-01-22 20:35     ` Michael Buesch
@ 2007-01-23 15:18     ` Dan Williams
  2007-01-23 15:22       ` Michael Buesch
  1 sibling, 1 reply; 6+ messages in thread
From: Dan Williams @ 2007-01-23 15:18 UTC (permalink / raw)
  To: Larry Finger; +Cc: Michael Buesch, John Linville, netdev, Bcm43xx-dev

On Mon, 2007-01-22 at 14:18 -0600, Larry Finger wrote:
> Michael Buesch wrote:
> > On Saturday 20 January 2007 17:18, Larry Finger wrote:
> >> 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@lwfinger.net>
> >> ---
> 
> ..snip..
> 
> >>  	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);
> >>  }
> > 
> > Any special reason why you convert the DMA operations to the PCI
> > stuff? I ask, because if this makes a difference, it affects the
> > new SSB subsystem as well.
> 
> When I looked at the b44 driver to see how that code handled the problem, it used the pci-form of
> the calls rather than the dma-version. Thus I switched early in the debug process - even before I
> had the necessary hardware. Once I got it working and understood the problem, I never tried
> restoring the dma-forms.
> 
> At present, I have a problem getting NetworkManager to see the d80211 wireless interface. Once I get
> that solved, I plan to use my system to test with > 1 GB RAM on your git tree. In that case, I'll
> switch to the pci-form only if necessary.

NM should show the interface if HAL sees the interface and has assigned
it a "net.80211" capability.  We had all agreed that HAL should be a bit
smarter about detecting d80211 devices, but we were postponing that
until we figured out what to do with the master device.  Now that we
think it will actually go away, it will be easier to find the actual
wlan devices in sysfs or in /proc/net/wireless.

I think HAL still looks in /proc/net/wireless to determine whether a
network interface that it found is actually a wireless interface.

The long and short of it is that if HAL says it has "net.80211"
capability, NM should be able to find the device.

Dan

> > 
> >>  static inline
> >> @@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct b
> 
> ..snip..
> 
> >> -	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;
> >> +	BUG();
> > 
> > That isn't a BUG. Just remove this call, please.
> 
> It was accidentally left in from my debugging. I have already submitted a revised version to
> Linville that removes this, and one other BUG statement that you didn't note.
> 
> 
> >> +	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 */
> >>  }
> 
> ..snip..
> 
> >>  	u16 board_vendor;
> >>  	u16 board_type;
> > 
> > The rest is OK, I think.
> > Thanks for the nice work.
> 
> Thank you. It certainly was a lot easier with the necessary hardware in house.
> 
> Larry
> 
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] bcm43xx: Fix problem with >1 GB RAM
  2007-01-23 15:18     ` Dan Williams
@ 2007-01-23 15:22       ` Michael Buesch
  0 siblings, 0 replies; 6+ messages in thread
From: Michael Buesch @ 2007-01-23 15:22 UTC (permalink / raw)
  To: Dan Williams; +Cc: Larry Finger, John Linville, netdev, Bcm43xx-dev, Jiri Benc

On Tuesday 23 January 2007 16:18, Dan Williams wrote:
> > At present, I have a problem getting NetworkManager to see the d80211 wireless interface. Once I get
> > that solved, I plan to use my system to test with > 1 GB RAM on your git tree. In that case, I'll
> > switch to the pci-form only if necessary.
> 
> NM should show the interface if HAL sees the interface and has assigned
> it a "net.80211" capability.  We had all agreed that HAL should be a bit
> smarter about detecting d80211 devices, but we were postponing that
> until we figured out what to do with the master device.  Now that we

Jiri already has a working patch for that.
I think he will commit it, soon.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2007-01-23 15:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-01-20 16:18 [PATCH] bcm43xx: Fix problem with >1 GB RAM Larry Finger
2007-01-22 18:20 ` Michael Buesch
2007-01-22 20:18   ` Larry Finger
2007-01-22 20:35     ` Michael Buesch
2007-01-23 15:18     ` Dan Williams
2007-01-23 15:22       ` Michael Buesch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).