|
@@ -96,7 +96,7 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
|
|
|
#endif
|
|
|
|
|
|
/**
|
|
|
- * dma_contiguous_reserve() - reserve area for contiguous memory handling
|
|
|
+ * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling
|
|
|
* @limit: End address of the reserved memory (optional, 0 for any).
|
|
|
*
|
|
|
* This function reserves memory from early allocator. It should be
|
|
@@ -124,22 +124,29 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
- if (selected_size) {
|
|
|
+ if (selected_size && !dma_contiguous_default_area) {
|
|
|
pr_debug("%s: reserving %ld MiB for global area\n", __func__,
|
|
|
(unsigned long)selected_size / SZ_1M);
|
|
|
|
|
|
- dma_declare_contiguous(NULL, selected_size, 0, limit);
|
|
|
+ dma_contiguous_reserve_area(selected_size, 0, limit,
|
|
|
+ &dma_contiguous_default_area);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
static DEFINE_MUTEX(cma_mutex);
|
|
|
|
|
|
-static int __init cma_activate_area(unsigned long base_pfn, unsigned long count)
|
|
|
+static int __init cma_activate_area(struct cma *cma)
|
|
|
{
|
|
|
- unsigned long pfn = base_pfn;
|
|
|
- unsigned i = count >> pageblock_order;
|
|
|
+ int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long);
|
|
|
+ unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
|
|
|
+ unsigned i = cma->count >> pageblock_order;
|
|
|
struct zone *zone;
|
|
|
|
|
|
+ cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
|
|
+
|
|
|
+ if (!cma->bitmap)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
WARN_ON_ONCE(!pfn_valid(pfn));
|
|
|
zone = page_zone(pfn_to_page(pfn));
|
|
|
|
|
@@ -153,92 +160,53 @@ static int __init cma_activate_area(unsigned long base_pfn, unsigned long count)
|
|
|
}
|
|
|
init_cma_reserved_pageblock(pfn_to_page(base_pfn));
|
|
|
} while (--i);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static struct cma * __init cma_create_area(unsigned long base_pfn,
|
|
|
- unsigned long count)
|
|
|
-{
|
|
|
- int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
|
|
|
- struct cma *cma;
|
|
|
- int ret = -ENOMEM;
|
|
|
-
|
|
|
- pr_debug("%s(base %08lx, count %lx)\n", __func__, base_pfn, count);
|
|
|
-
|
|
|
- cma = kmalloc(sizeof *cma, GFP_KERNEL);
|
|
|
- if (!cma)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
-
|
|
|
- cma->base_pfn = base_pfn;
|
|
|
- cma->count = count;
|
|
|
- cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
|
|
|
|
|
- if (!cma->bitmap)
|
|
|
- goto no_mem;
|
|
|
-
|
|
|
- ret = cma_activate_area(base_pfn, count);
|
|
|
- if (ret)
|
|
|
- goto error;
|
|
|
-
|
|
|
- pr_debug("%s: returned %p\n", __func__, (void *)cma);
|
|
|
- return cma;
|
|
|
-
|
|
|
-error:
|
|
|
- kfree(cma->bitmap);
|
|
|
-no_mem:
|
|
|
- kfree(cma);
|
|
|
- return ERR_PTR(ret);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static struct cma_reserved {
|
|
|
- phys_addr_t start;
|
|
|
- unsigned long size;
|
|
|
- struct device *dev;
|
|
|
-} cma_reserved[MAX_CMA_AREAS] __initdata;
|
|
|
-static unsigned cma_reserved_count __initdata;
|
|
|
+static struct cma cma_areas[MAX_CMA_AREAS];
|
|
|
+static unsigned cma_area_count;
|
|
|
|
|
|
static int __init cma_init_reserved_areas(void)
|
|
|
{
|
|
|
- struct cma_reserved *r = cma_reserved;
|
|
|
- unsigned i = cma_reserved_count;
|
|
|
-
|
|
|
- pr_debug("%s()\n", __func__);
|
|
|
+ int i;
|
|
|
|
|
|
- for (; i; --i, ++r) {
|
|
|
- struct cma *cma;
|
|
|
- cma = cma_create_area(PFN_DOWN(r->start),
|
|
|
- r->size >> PAGE_SHIFT);
|
|
|
- if (!IS_ERR(cma))
|
|
|
- dev_set_cma_area(r->dev, cma);
|
|
|
+ for (i = 0; i < cma_area_count; i++) {
|
|
|
+ int ret = cma_activate_area(&cma_areas[i]);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
}
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
core_initcall(cma_init_reserved_areas);
|
|
|
|
|
|
/**
|
|
|
- * dma_declare_contiguous() - reserve area for contiguous memory handling
|
|
|
- * for particular device
|
|
|
- * @dev: Pointer to device structure.
|
|
|
- * @size: Size of the reserved memory.
|
|
|
- * @base: Start address of the reserved memory (optional, 0 for any).
|
|
|
+ * dma_contiguous_reserve_area() - reserve custom contiguous area
|
|
|
+ * @size: Size of the reserved area (in bytes),
|
|
|
+ * @base: Base address of the reserved area optional, use 0 for any
|
|
|
* @limit: End address of the reserved memory (optional, 0 for any).
|
|
|
+ * @res_cma: Pointer to store the created cma region.
|
|
|
*
|
|
|
- * This function reserves memory for specified device. It should be
|
|
|
- * called by board specific code when early allocator (memblock or bootmem)
|
|
|
- * is still activate.
|
|
|
+ * This function reserves memory from early allocator. It should be
|
|
|
+ * called by arch specific code once the early allocator (memblock or bootmem)
|
|
|
+ * has been activated and all other subsystems have already allocated/reserved
|
|
|
+ * memory. This function allows to create custom reserved areas for specific
|
|
|
+ * devices.
|
|
|
*/
|
|
|
-int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
|
|
|
- phys_addr_t base, phys_addr_t limit)
|
|
|
+int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
|
|
|
+ phys_addr_t limit, struct cma **res_cma)
|
|
|
{
|
|
|
- struct cma_reserved *r = &cma_reserved[cma_reserved_count];
|
|
|
+ struct cma *cma = &cma_areas[cma_area_count];
|
|
|
phys_addr_t alignment;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
|
|
|
(unsigned long)size, (unsigned long)base,
|
|
|
(unsigned long)limit);
|
|
|
|
|
|
/* Sanity checks */
|
|
|
- if (cma_reserved_count == ARRAY_SIZE(cma_reserved)) {
|
|
|
+ if (cma_area_count == ARRAY_SIZE(cma_areas)) {
|
|
|
pr_err("Not enough slots for CMA reserved regions!\n");
|
|
|
return -ENOSPC;
|
|
|
}
|
|
@@ -256,7 +224,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
|
|
|
if (base) {
|
|
|
if (memblock_is_region_reserved(base, size) ||
|
|
|
memblock_reserve(base, size) < 0) {
|
|
|
- base = -EBUSY;
|
|
|
+ ret = -EBUSY;
|
|
|
goto err;
|
|
|
}
|
|
|
} else {
|
|
@@ -266,7 +234,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
|
|
|
*/
|
|
|
phys_addr_t addr = __memblock_alloc_base(size, alignment, limit);
|
|
|
if (!addr) {
|
|
|
- base = -ENOMEM;
|
|
|
+ ret = -ENOMEM;
|
|
|
goto err;
|
|
|
} else {
|
|
|
base = addr;
|
|
@@ -277,10 +245,11 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
|
|
|
* Each reserved area must be initialised later, when more kernel
|
|
|
* subsystems (like slab allocator) are available.
|
|
|
*/
|
|
|
- r->start = base;
|
|
|
- r->size = size;
|
|
|
- r->dev = dev;
|
|
|
- cma_reserved_count++;
|
|
|
+ cma->base_pfn = PFN_DOWN(base);
|
|
|
+ cma->count = size >> PAGE_SHIFT;
|
|
|
+ *res_cma = cma;
|
|
|
+ cma_area_count++;
|
|
|
+
|
|
|
pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
|
|
|
(unsigned long)base);
|
|
|
|
|
@@ -289,7 +258,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
|
|
|
return 0;
|
|
|
err:
|
|
|
pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
|
|
|
- return base;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|