diff options
| -rw-r--r-- | arch/arm/mm/dma-mapping.c | 51 | ||||
| -rw-r--r-- | arch/arm/mm/init.c | 2 | ||||
| -rw-r--r-- | arch/arm/mm/mm.h | 2 |
3 files changed, 49 insertions, 6 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index f5e1a8471714..7b3f2426a1fb 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
| @@ -159,7 +159,7 @@ EXPORT_SYMBOL(arm_coherent_dma_ops); | |||
| 159 | 159 | ||
| 160 | static u64 get_coherent_dma_mask(struct device *dev) | 160 | static u64 get_coherent_dma_mask(struct device *dev) |
| 161 | { | 161 | { |
| 162 | u64 mask = (u64)arm_dma_limit; | 162 | u64 mask = (u64)DMA_BIT_MASK(32); |
| 163 | 163 | ||
| 164 | if (dev) { | 164 | if (dev) { |
| 165 | mask = dev->coherent_dma_mask; | 165 | mask = dev->coherent_dma_mask; |
| @@ -173,10 +173,30 @@ static u64 get_coherent_dma_mask(struct device *dev) | |||
| 173 | return 0; | 173 | return 0; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | if ((~mask) & (u64)arm_dma_limit) { | 176 | /* |
| 177 | dev_warn(dev, "coherent DMA mask %#llx is smaller " | 177 | * If the mask allows for more memory than we can address, |
| 178 | "than system GFP_DMA mask %#llx\n", | 178 | * and we actually have that much memory, then fail the |
| 179 | mask, (u64)arm_dma_limit); | 179 | * allocation. |
| 180 | */ | ||
| 181 | if (sizeof(mask) != sizeof(dma_addr_t) && | ||
| 182 | mask > (dma_addr_t)~0 && | ||
| 183 | dma_to_pfn(dev, ~0) > arm_dma_pfn_limit) { | ||
| 184 | dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n", | ||
| 185 | mask); | ||
| 186 | dev_warn(dev, "Driver did not use or check the return value from dma_set_coherent_mask()?\n"); | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | /* | ||
| 191 | * Now check that the mask, when translated to a PFN, | ||
| 192 | * fits within the allowable addresses which we can | ||
| 193 | * allocate. | ||
| 194 | */ | ||
| 195 | if (dma_to_pfn(dev, mask) < arm_dma_pfn_limit) { | ||
| 196 | dev_warn(dev, "Coherent DMA mask %#llx (pfn %#lx-%#lx) covers a smaller range of system memory than the DMA zone pfn 0x0-%#lx\n", | ||
| 197 | mask, | ||
| 198 | dma_to_pfn(dev, 0), dma_to_pfn(dev, mask) + 1, | ||
| 199 | arm_dma_pfn_limit + 1); | ||
| 180 | return 0; | 200 | return 0; |
| 181 | } | 201 | } |
| 182 | } | 202 | } |
| @@ -1007,8 +1027,27 @@ void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, | |||
| 1007 | */ | 1027 | */ |
| 1008 | int dma_supported(struct device *dev, u64 mask) | 1028 | int dma_supported(struct device *dev, u64 mask) |
| 1009 | { | 1029 | { |
| 1010 | if (mask < (u64)arm_dma_limit) | 1030 | unsigned long limit; |
| 1031 | |||
| 1032 | /* | ||
| 1033 | * If the mask allows for more memory than we can address, | ||
| 1034 | * and we actually have that much memory, then we must | ||
| 1035 | * indicate that DMA to this device is not supported. | ||
| 1036 | */ | ||
| 1037 | if (sizeof(mask) != sizeof(dma_addr_t) && | ||
| 1038 | mask > (dma_addr_t)~0 && | ||
| 1039 | dma_to_pfn(dev, ~0) > arm_dma_pfn_limit) | ||
| 1040 | return 0; | ||
| 1041 | |||
| 1042 | /* | ||
| 1043 | * Translate the device's DMA mask to a PFN limit. This | ||
| 1044 | * PFN number includes the page which we can DMA to. | ||
| 1045 | */ | ||
| 1046 | limit = dma_to_pfn(dev, mask); | ||
| 1047 | |||
| 1048 | if (limit < arm_dma_pfn_limit) | ||
| 1011 | return 0; | 1049 | return 0; |
| 1050 | |||
| 1012 | return 1; | 1051 | return 1; |
| 1013 | } | 1052 | } |
| 1014 | EXPORT_SYMBOL(dma_supported); | 1053 | EXPORT_SYMBOL(dma_supported); |
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index febaee7ca57b..8aab24f35a5e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
| @@ -218,6 +218,7 @@ EXPORT_SYMBOL(arm_dma_zone_size); | |||
| 218 | * so a successful GFP_DMA allocation will always satisfy this. | 218 | * so a successful GFP_DMA allocation will always satisfy this. |
| 219 | */ | 219 | */ |
| 220 | phys_addr_t arm_dma_limit; | 220 | phys_addr_t arm_dma_limit; |
| 221 | unsigned long arm_dma_pfn_limit; | ||
| 221 | 222 | ||
| 222 | static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, | 223 | static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, |
| 223 | unsigned long dma_size) | 224 | unsigned long dma_size) |
| @@ -240,6 +241,7 @@ void __init setup_dma_zone(const struct machine_desc *mdesc) | |||
| 240 | arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1; | 241 | arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1; |
| 241 | } else | 242 | } else |
| 242 | arm_dma_limit = 0xffffffff; | 243 | arm_dma_limit = 0xffffffff; |
| 244 | arm_dma_pfn_limit = arm_dma_limit >> PAGE_SHIFT; | ||
| 243 | #endif | 245 | #endif |
| 244 | } | 246 | } |
| 245 | 247 | ||
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index d5a4e9ad8f0f..d5a982d15a88 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h | |||
| @@ -81,8 +81,10 @@ extern __init void add_static_vm_early(struct static_vm *svm); | |||
| 81 | 81 | ||
| 82 | #ifdef CONFIG_ZONE_DMA | 82 | #ifdef CONFIG_ZONE_DMA |
| 83 | extern phys_addr_t arm_dma_limit; | 83 | extern phys_addr_t arm_dma_limit; |
| 84 | extern unsigned long arm_dma_pfn_limit; | ||
| 84 | #else | 85 | #else |
| 85 | #define arm_dma_limit ((phys_addr_t)~0) | 86 | #define arm_dma_limit ((phys_addr_t)~0) |
| 87 | #define arm_dma_pfn_limit (~0ul >> PAGE_SHIFT) | ||
| 86 | #endif | 88 | #endif |
| 87 | 89 | ||
| 88 | extern phys_addr_t arm_lowmem_limit; | 90 | extern phys_addr_t arm_lowmem_limit; |
