* [PATCH stable 4/4] b43: Workaround DMA quirks
@ 2008-04-24 18:06 Michael Buesch
0 siblings, 0 replies; only message in thread
From: Michael Buesch @ 2008-04-24 18:06 UTC (permalink / raw)
To: stable; +Cc: bcm43xx-dev, linux-wireless
Some mainboards/CPUs don't allow DMA masks bigger than a certain limit.
Some VIA crap^h^h^h^hdevices have an upper limit of 0xFFFFFFFF. So in this
case a 64-bit b43 device would always fail to acquire the mask.
Implement a workaround to fallback to lower DMA mask, as we can always
also support a lower mask.
This patch is in wireless-testing.git, commit
91725545159f81f1c9dc738dfc329199583f649a
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Index: linux-2.6.25/drivers/net/wireless/b43/dma.c
===================================================================
--- linux-2.6.25.orig/drivers/net/wireless/b43/dma.c 2008-04-19 18:29:16.000000000 +0200
+++ linux-2.6.25/drivers/net/wireless/b43/dma.c 2008-04-23 18:35:33.000000000 +0200
@@ -819,12 +819,24 @@ static u64 supported_dma_mask(struct b43
if (tmp & B43_DMA32_TXADDREXT_MASK)
return DMA_32BIT_MASK;
return DMA_30BIT_MASK;
}
+static enum b43_dmatype dma_mask_to_engine_type(u64 dmamask)
+{
+ if (dmamask == DMA_30BIT_MASK)
+ return B43_DMA_30BIT;
+ if (dmamask == DMA_32BIT_MASK)
+ return B43_DMA_32BIT;
+ if (dmamask == DMA_64BIT_MASK)
+ return B43_DMA_64BIT;
+ B43_WARN_ON(1);
+ return B43_DMA_30BIT;
+}
+
/* Main initialization function. */
static
struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
int controller_index,
int for_tx,
enum b43_dmatype type)
@@ -979,42 +991,61 @@ void b43_dma_free(struct b43_wldev *dev)
b43_destroy_dmaring(dma->tx_ring1);
dma->tx_ring1 = NULL;
b43_destroy_dmaring(dma->tx_ring0);
dma->tx_ring0 = NULL;
}
+static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
+{
+ u64 orig_mask = mask;
+ bool fallback = 0;
+ int err;
+
+ /* Try to set the DMA mask. If it fails, try falling back to a
+ * lower mask, as we can always also support a lower one. */
+ while (1) {
+ err = ssb_dma_set_mask(dev->dev, mask);
+ if (!err)
+ break;
+ if (mask == DMA_64BIT_MASK) {
+ mask = DMA_32BIT_MASK;
+ fallback = 1;
+ continue;
+ }
+ if (mask == DMA_32BIT_MASK) {
+ mask = DMA_30BIT_MASK;
+ fallback = 1;
+ continue;
+ }
+ b43err(dev->wl, "The machine/kernel does not support "
+ "the required %u-bit DMA mask\n",
+ (unsigned int)dma_mask_to_engine_type(orig_mask));
+ return -EOPNOTSUPP;
+ }
+ if (fallback) {
+ b43info(dev->wl, "DMA mask fallback from %u-bit to %u-bit\n",
+ (unsigned int)dma_mask_to_engine_type(orig_mask),
+ (unsigned int)dma_mask_to_engine_type(mask));
+ }
+
+ return 0;
+}
+
int b43_dma_init(struct b43_wldev *dev)
{
struct b43_dma *dma = &dev->dma;
struct b43_dmaring *ring;
int err;
u64 dmamask;
enum b43_dmatype type;
dmamask = supported_dma_mask(dev);
- switch (dmamask) {
- default:
- B43_WARN_ON(1);
- case DMA_30BIT_MASK:
- type = B43_DMA_30BIT;
- break;
- case DMA_32BIT_MASK:
- type = B43_DMA_32BIT;
- break;
- case DMA_64BIT_MASK:
- type = B43_DMA_64BIT;
- break;
- }
- err = ssb_dma_set_mask(dev->dev, dmamask);
- if (err) {
- b43err(dev->wl, "The machine/kernel does not support "
- "the required DMA mask (0x%08X%08X)\n",
- (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32),
- (unsigned int)(dmamask & 0x00000000FFFFFFFFULL));
- return -EOPNOTSUPP;
- }
+ type = dma_mask_to_engine_type(dmamask);
+ err = b43_dma_set_mask(dev, dmamask);
+ if (err)
+ return err;
err = -ENOMEM;
/* setup TX DMA channels. */
ring = b43_setup_dmaring(dev, 0, 1, type);
if (!ring)
goto out;
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2008-04-24 18:09 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-24 18:06 [PATCH stable 4/4] b43: Workaround DMA quirks Michael Buesch
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.