This adds a new DMA subsystem API call for "weak" setting of the DMA mask. Weak means that it will fallback to smaller masks in case the DMA subsystem rejects a big mask. Currently such rejection may happen if the driver requests a 64bit mask on a VIA machine, for example. dma_set_mask_weak() will fallback to 32bit, in that case, and tell the caller about it by modifying the passed mask. Signed-off-by: Michael Buesch <mb@xxxxxxxxx> Index: wireless-testing/drivers/base/dma-mapping.c =================================================================== --- wireless-testing.orig/drivers/base/dma-mapping.c 2008-04-28 23:34:19.000000000 +0200 +++ wireless-testing/drivers/base/dma-mapping.c 2008-04-28 23:46:25.000000000 +0200 @@ -216,3 +216,38 @@ void dmam_release_declared_memory(struct EXPORT_SYMBOL(dmam_release_declared_memory); #endif + +/** + * dma_set_mask_weak - Set the DMA mask. Retry with smaller masks. + * @dev: Device to set the mask on. + * @mask: Pointer to the mask that you want to set. The function will + * modify the mask and set it to the actually used mask, in case + * it had to fall back to a smaller mask. + * + * Set the DMA mask and allow falling back to smaller masks in + * case of an error. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int dma_set_mask_weak(struct device *dev, u64 *mask) +{ + u64 m = *mask; + int err; + + if (m < DMA_MIN_FALLBACK_MASK) + return -EINVAL; + while (1) { + err = dma_set_mask(dev, m); + if (!err) + break; + /* Did not like this one. Try a smaller one. */ + m >>= 1; + if (m < DMA_MIN_FALLBACK_MASK) + return err; + } + *mask = m; + + return 0; +} +EXPORT_SYMBOL(dma_set_mask_weak); Index: wireless-testing/include/linux/dma-mapping.h =================================================================== --- wireless-testing.orig/include/linux/dma-mapping.h 2008-04-28 23:34:19.000000000 +0200 +++ wireless-testing/include/linux/dma-mapping.h 2008-04-28 23:35:35.000000000 +0200 @@ -60,6 +60,11 @@ static inline int is_device_dma_capable( extern u64 dma_get_required_mask(struct device *dev); +extern int dma_set_mask_weak(struct device *dev, u64 *mask); +/* Smallest mask fallback used by dma_set_mask_weak(). */ +#define DMA_MIN_FALLBACK_MASK DMA_BIT_MASK(24) /* 16 MB */ + + static inline unsigned int dma_get_max_seg_size(struct device *dev) { return dev->dma_parms ? dev->dma_parms->max_segment_size : 65536; -- Greetings Michael. -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html