diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-04-23 13:13:01 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-23 21:25:36 -0400 |
commit | 1033b3ea11820ea1fb1b877207bd6724e9aaedc3 (patch) | |
tree | 6037db5b31dcaa0596f5cca9843612707c881279 /drivers/net | |
parent | 0da926f05748d273e7b2b673b0de21629ae9acdd (diff) |
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 <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 21c886a9a1d9..6dcbb3c87e72 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -980,6 +980,42 @@ void b43_dma_free(struct b43_wldev *dev) | |||
980 | destroy_ring(dma, tx_ring_mcast); | 980 | destroy_ring(dma, tx_ring_mcast); |
981 | } | 981 | } |
982 | 982 | ||
983 | static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) | ||
984 | { | ||
985 | u64 orig_mask = mask; | ||
986 | bool fallback = 0; | ||
987 | int err; | ||
988 | |||
989 | /* Try to set the DMA mask. If it fails, try falling back to a | ||
990 | * lower mask, as we can always also support a lower one. */ | ||
991 | while (1) { | ||
992 | err = ssb_dma_set_mask(dev->dev, mask); | ||
993 | if (!err) | ||
994 | break; | ||
995 | if (mask == DMA_64BIT_MASK) { | ||
996 | mask = DMA_32BIT_MASK; | ||
997 | fallback = 1; | ||
998 | continue; | ||
999 | } | ||
1000 | if (mask == DMA_32BIT_MASK) { | ||
1001 | mask = DMA_30BIT_MASK; | ||
1002 | fallback = 1; | ||
1003 | continue; | ||
1004 | } | ||
1005 | b43err(dev->wl, "The machine/kernel does not support " | ||
1006 | "the required %u-bit DMA mask\n", | ||
1007 | (unsigned int)dma_mask_to_engine_type(orig_mask)); | ||
1008 | return -EOPNOTSUPP; | ||
1009 | } | ||
1010 | if (fallback) { | ||
1011 | b43info(dev->wl, "DMA mask fallback from %u-bit to %u-bit\n", | ||
1012 | (unsigned int)dma_mask_to_engine_type(orig_mask), | ||
1013 | (unsigned int)dma_mask_to_engine_type(mask)); | ||
1014 | } | ||
1015 | |||
1016 | return 0; | ||
1017 | } | ||
1018 | |||
983 | int b43_dma_init(struct b43_wldev *dev) | 1019 | int b43_dma_init(struct b43_wldev *dev) |
984 | { | 1020 | { |
985 | struct b43_dma *dma = &dev->dma; | 1021 | struct b43_dma *dma = &dev->dma; |
@@ -989,14 +1025,9 @@ int b43_dma_init(struct b43_wldev *dev) | |||
989 | 1025 | ||
990 | dmamask = supported_dma_mask(dev); | 1026 | dmamask = supported_dma_mask(dev); |
991 | type = dma_mask_to_engine_type(dmamask); | 1027 | type = dma_mask_to_engine_type(dmamask); |
992 | err = ssb_dma_set_mask(dev->dev, dmamask); | 1028 | err = b43_dma_set_mask(dev, dmamask); |
993 | if (err) { | 1029 | if (err) |
994 | b43err(dev->wl, "The machine/kernel does not support " | 1030 | return err; |
995 | "the required DMA mask (0x%08X%08X)\n", | ||
996 | (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32), | ||
997 | (unsigned int)(dmamask & 0x00000000FFFFFFFFULL)); | ||
998 | return -EOPNOTSUPP; | ||
999 | } | ||
1000 | 1031 | ||
1001 | err = -ENOMEM; | 1032 | err = -ENOMEM; |
1002 | /* setup TX DMA channels. */ | 1033 | /* setup TX DMA channels. */ |