b43: Workaround DMA quirks
PATCH 1/1 b43: Workaround DMA quirks
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.
Signed-off-by Michael Buesch <[email protected]>
---
John, this is a bugfix for 2.6.26
Stefano, we might probably want to backport this to legacy.
drivers/net/wireless/b43/dma.c +39 -8
@@ -977,29 +977,60 @@ void b43_dma_free(struct b43_wldev *dev)destroy_ring (dma, tx_ring_AC_BE);destroy_ring (dma, tx_ring_AC_VI);destroy_ring (dma, tx_ring_AC_VO);destroy_ring (dma, tx_ring_mcast); } +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;int err;u64 dmamask;enum b43_dmatype type; dmamask =supported_dma_mask (dev); type =dma_mask_to_engine_type (dmamask); - 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 ; - } + err =b43_dma_set_mask (dev, dmamask); +if (err) +return err; err = -ENOMEM ;/* setup TX DMA channels. */ dma->tx_ring_AC_BK =b43_setup_dmaring (dev,0 ,1 , type);if (!dma->tx_ring_AC_BK) goto out;