| @@ -196,93 +196,75 @@ static int __init dma_atomic_pool_init(void) · 195 unmodified lines |
| 196 | 196 | } |
| 197 | 197 | postcore_initcall(dma_atomic_pool_init); |
| 198 | 198 | |
| 199 | | −static inline struct gen_pool *dma_guess_pool_from_device(struct device *dev) |
| 199 | +static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp) |
| 200 | 200 | { |
| 201 | | − u64 phys_mask; |
| 202 | | − gfp_t gfp; |
| 203 | | − |
| 204 | | − gfp = dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, |
| 205 | | − &phys_mask); |
| 206 | | − if (IS_ENABLED(CONFIG_ZONE_DMA) && gfp == GFP_DMA) |
| 201 | + if (prev == NULL) { |
| 202 | + if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32)) |
| 203 | + return atomic_pool_dma32; |
| 204 | + if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA)) |
| 205 | + return atomic_pool_dma; |
| 206 | + return atomic_pool_kernel; |
| 207 | + } |
| 208 | + if (prev == atomic_pool_kernel) |
| 209 | + return atomic_pool_dma32 ? atomic_pool_dma32 : atomic_pool_dma; |
| 210 | + if (prev == atomic_pool_dma32) |
| 207 | 211 | return atomic_pool_dma; |
| 208 | | − if (IS_ENABLED(CONFIG_ZONE_DMA32) && gfp == GFP_DMA32) |
| 209 | | − return atomic_pool_dma32; |
| 210 | | − return atomic_pool_kernel; |
| 212 | + return NULL; |
| 211 | 213 | } |
| 212 | 214 | |
| 213 | | −static inline struct gen_pool *dma_get_safer_pool(struct gen_pool *bad_pool) |
| 215 | +static struct page *__dma_alloc_from_pool(struct device *dev, size_t size, |
| 216 | + struct gen_pool *pool, void **cpu_addr, |
| 217 | + bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t)) |
| 214 | 218 | { |
| 215 | | − if (bad_pool == atomic_pool_kernel) |
| 216 | | − return atomic_pool_dma32 ? : atomic_pool_dma; |
| 219 | + unsigned long addr; |
| 220 | + phys_addr_t phys; |
| 217 | 221 | |
| 218 | | − if (bad_pool == atomic_pool_dma32) |
| 219 | | − return atomic_pool_dma; |
| 222 | + addr = gen_pool_alloc(pool, size); |
| 223 | + if (!addr) |
| 224 | + return NULL; |
| 220 | 225 | |
| 221 | | − return NULL; |
| 222 | | −} |
| 226 | + phys = gen_pool_virt_to_phys(pool, addr); |
| 227 | + if (phys_addr_ok && !phys_addr_ok(dev, phys, size)) { |
| 228 | + gen_pool_free(pool, addr, size); |
| 229 | + return NULL; |
| 230 | + } |
| 223 | 231 | |
| 224 | | −static inline struct gen_pool *dma_guess_pool(struct device *dev, |
| 225 | | − struct gen_pool *bad_pool) |
| 226 | | −{ |
| 227 | | − if (bad_pool) |
| 228 | | − return dma_get_safer_pool(bad_pool); |
| 232 | + if (gen_pool_avail(pool) < atomic_pool_size) |
| 233 | + schedule_work(&atomic_pool_work); |
| 229 | 234 | |
| 230 | | − return dma_guess_pool_from_device(dev); |
| 235 | + *cpu_addr = (void *)addr; |
| 236 | + memset(*cpu_addr, 0, size); |
| 237 | + return pfn_to_page(__phys_to_pfn(phys)); |
| 231 | 238 | } |
| 232 | 239 | |
| 233 | | −void *dma_alloc_from_pool(struct device *dev, size_t size, |
| 234 | | − struct page **ret_page, gfp_t flags) |
| 240 | +struct page *dma_alloc_from_pool(struct device *dev, size_t size, |
| 241 | + void **cpu_addr, gfp_t gfp, |
| 242 | + bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t)) |
| 235 | 243 | { |
| 236 | 244 | struct gen_pool *pool = NULL; |
| 237 | | − unsigned long val = 0; |
| 238 | | − void *ptr = NULL; |
| 239 | | − phys_addr_t phys; |
| 240 | | − |
| 241 | | − while (1) { |
| 242 | | − pool = dma_guess_pool(dev, pool); |
| 243 | | − if (!pool) { |
| 244 | | − WARN(1, "Failed to get suitable pool for %s\n", |
| 245 | | − dev_name(dev)); |
| 246 | | − break; |
| 247 | | − } |
| 248 | | − |
| 249 | | − val = gen_pool_alloc(pool, size); |
| 250 | | − if (!val) |
| 251 | | − continue; |
| 252 | | − |
| 253 | | − phys = gen_pool_virt_to_phys(pool, val); |
| 254 | | − if (dma_coherent_ok(dev, phys, size)) |
| 255 | | − break; |
| 256 | | − |
| 257 | | − gen_pool_free(pool, val, size); |
| 258 | | − val = 0; |
| 259 | | − } |
| 260 | | − |
| 261 | | − |
| 262 | | − if (val) { |
| 263 | | − *ret_page = pfn_to_page(__phys_to_pfn(phys)); |
| 264 | | − ptr = (void *)val; |
| 265 | | − memset(ptr, 0, size); |
| 245 | + struct page *page; |
| 266 | 246 | |
| 267 | | − if (gen_pool_avail(pool) < atomic_pool_size) |
| 268 | | − schedule_work(&atomic_pool_work); |
| 247 | + while ((pool = dma_guess_pool(pool, gfp))) { |
| 248 | + page = __dma_alloc_from_pool(dev, size, pool, cpu_addr, |
| 249 | + phys_addr_ok); |
| 250 | + if (page) |
| 251 | + return page; |
| 269 | 252 | } |
| 270 | 253 | |
| 271 | | − return ptr; |
| 254 | + WARN(1, "Failed to get suitable pool for %s\n", dev_name(dev)); |
| 255 | + return NULL; |
| 272 | 256 | } |
| 273 | 257 | |
| 274 | 258 | bool dma_free_from_pool(struct device *dev, void *start, size_t size) |
| 275 | 259 | { |
| 276 | 260 | struct gen_pool *pool = NULL; |
| 277 | 261 | |
| 278 | | − while (1) { |
| 279 | | − pool = dma_guess_pool(dev, pool); |
| 280 | | − if (!pool) |
| 281 | | − return false; |
| 282 | | − |
| 283 | | − if (gen_pool_has_addr(pool, (unsigned long)start, size)) { |
| 284 | | − gen_pool_free(pool, (unsigned long)start, size); |
| 285 | | − return true; |
| 286 | | − } |
| 262 | + while ((pool = dma_guess_pool(pool, 0))) { |
| 263 | + if (!gen_pool_has_addr(pool, (unsigned long)start, size)) |
| 264 | + continue; |
| 265 | + gen_pool_free(pool, (unsigned long)start, size); |
| 266 | + return true; |
| 287 | 267 | } |
| 268 | + |
| 269 | + return false; |
| 288 | 270 | } |