>From 0ba5a0996d307d89f19ef79cf5fed1f8c4a7ed27 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sun, 2 Dec 2012 20:54:32 +0800 Subject: [PATCH 1/3] memblock: introduce interfaces to assoicate tag and data with reserved regions Currently some subsystems use private static arrays to store information assoicated with memory blocks allocated/reserved from memblock subsystem. For example, dma-contiguous.c uses cma_reserved[] to store information assoicated with allocated memory blocks. So introduce interfaces to associate tag(type) and caller specific data with allocated/reserved memblock regions. Users of memblock subsystem may be simplified by using these new interfaces. Signed-off-by: Jiang Liu --- include/linux/memblock.h | 33 ++++++++++++++++++++++++++ mm/Kconfig | 3 +++ mm/memblock.c | 58 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index d452ee1..40dea53 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -22,6 +22,10 @@ struct memblock_region { phys_addr_t base; phys_addr_t size; +#ifdef CONFIG_HAVE_MEMBLOCK_TAG + void *data; + int tag; +#endif #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int nid; #endif @@ -118,6 +122,35 @@ void __next_free_mem_range_rev(u64 *idx, int nid, phys_addr_t *out_start, i != (u64)ULLONG_MAX; \ __next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid)) +#ifdef CONFIG_HAVE_MEMBLOCK_TAG +#define MEMBLOCK_TAG_DEFAULT 0x0 /* default tag for bootmem allocatror */ + +int memblock_mark_tag(phys_addr_t base, phys_addr_t size, int tag, void *data); +void memblock_free_all_with_tag(int tag); + +/* Only merge regions with default tag */ +static inline bool memblock_tag_mergeable(struct memblock_region *prev, + struct memblock_region *next) +{ + return prev->tag == MEMBLOCK_TAG_DEFAULT && + next->tag == MEMBLOCK_TAG_DEFAULT; +} + +static inline void memblock_init_tag(struct memblock_region *reg) +{ + reg->tag = MEMBLOCK_TAG_DEFAULT; + reg->data = NULL; +} +#else /* CONFIG_HAVE_MEMBLOCK_TAG */ +static inline bool memblock_tag_mergeable(struct memblock_region *prev, + struct memblock_region *next) +{ + return true; +} + +static inline void memblock_init_tag(struct memblock_region *reg) {} +#endif /* CONFIG_HAVE_MEMBLOCK_TAG */ + #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int memblock_set_node(phys_addr_t base, phys_addr_t size, int nid); diff --git a/mm/Kconfig b/mm/Kconfig index a3f8ddd..5080390 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -131,6 +131,9 @@ config SPARSEMEM_VMEMMAP config HAVE_MEMBLOCK boolean +config HAVE_MEMBLOCK_TAG + boolean + config HAVE_MEMBLOCK_NODE_MAP boolean diff --git a/mm/memblock.c b/mm/memblock.c index 6259055..c2c644e 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -307,7 +307,8 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type) if (this->base + this->size != next->base || memblock_get_region_node(this) != - memblock_get_region_node(next)) { + memblock_get_region_node(next) || + !memblock_tag_mergeable(this, next)) { BUG_ON(this->base + this->size > next->base); i++; continue; @@ -339,6 +340,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type, memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn)); rgn->base = base; rgn->size = size; + memblock_init_tag(rgn); memblock_set_region_node(rgn, nid); type->cnt++; type->total_size += size; @@ -764,6 +766,60 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, } #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ +#ifdef CONFIG_HAVE_MEMBLOCK_TAG +/** + * memblock_mark_tag - mark @tag and @data with reserved regions + * @base: base of area to mark @tag and @data with + * @size: size of area to mark @tag and @data with + * @tag: tag (type) to assoicated with reserved regions + * @data: caller specific data to associated with reserved regions + * + * Associate @tag(type) and caller specific @data with reserved memblock + * regions in [@base,@base+@size). + * Regions which cross the area boundaries are split as necessary. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int __init_memblock memblock_mark_tag(phys_addr_t base, phys_addr_t size, + int tag, void *data) +{ + struct memblock_type *type = &memblock.reserved; + int start_rgn, end_rgn; + int i, ret; + + ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn); + if (ret) + return ret; + + for (i = start_rgn; i < end_rgn; i++) { + type->regions[i].tag = tag; + type->regions[i].data = data; + } + + memblock_merge_regions(type); + + return 0; +} + +/** + * memblock_free_all_with_tag - free all reserved regions with @tag + * @tag: tag to identify reserved memblock regions to be freed + * + * Free all reserved memblock regions with tag (type) of @tag + */ +void __init_memblock memblock_free_all_with_tag(int tag) +{ + int i; + struct memblock_type *type = &memblock.reserved; + + /* scan backward because it may remove current region */ + for (i = type->cnt - 1; i >= 0; i--) + if (type->regions[i].tag == tag) + memblock_remove_region(type, i); +} +#endif /* CONFIG_HAVE_MEMBLOCK_TAG */ + static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr, int nid) -- 1.7.9.5