示例#1
0
void __init memblock_init(void)
{
    static int init_done __initdata = 0;

    if (init_done)
        return;
    init_done = 1;

    /* Hookup the initial arrays */
    memblock.memory.regions	= memblock_memory_init_regions;
    memblock.memory.max		= INIT_MEMBLOCK_REGIONS;
    memblock.reserved.regions	= memblock_reserved_init_regions;
    memblock.reserved.max	= INIT_MEMBLOCK_REGIONS;

    /* Write a marker in the unused last array entry */
    memblock.memory.regions[INIT_MEMBLOCK_REGIONS].base = (phys_addr_t)RED_INACTIVE;
    memblock.reserved.regions[INIT_MEMBLOCK_REGIONS].base = (phys_addr_t)RED_INACTIVE;

    /* Create a dummy zero size MEMBLOCK which will get coalesced away later.
     * This simplifies the memblock_add() code below...
     */
    memblock.memory.regions[0].base = 0;
    memblock.memory.regions[0].size = 0;
    memblock_set_region_node(&memblock.memory.regions[0], MAX_NUMNODES);
    memblock.memory.cnt = 1;

    /* Ditto. */
    memblock.reserved.regions[0].base = 0;
    memblock.reserved.regions[0].size = 0;
    memblock_set_region_node(&memblock.reserved.regions[0], MAX_NUMNODES);
    memblock.reserved.cnt = 1;

    memblock.current_limit = MEMBLOCK_ALLOC_ANYWHERE;
}
示例#2
0
/**
 * memblock_insert_region - insert new memblock region
 * @type: memblock type to insert into
 * @idx: index for the insertion point
 * @base: base address of the new region
 * @size: size of the new region
 *
 * Insert new memblock region [@base,@base+@size) into @type at @idx.
 * @type must already have extra room to accomodate the new region.
 */
static void __init_memblock memblock_insert_region(struct memblock_type *type,
        int idx, phys_addr_t base,
        phys_addr_t size, int nid)
{
    struct memblock_region *rgn = &type->regions[idx];

    BUG_ON(type->cnt >= type->max);
    memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn));
    rgn->base = base;
    rgn->size = size;
    memblock_set_region_node(rgn, nid);
    type->cnt++;
}
示例#3
0
static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
{
    memmove(&type->regions[r], &type->regions[r + 1],
            (type->cnt - (r + 1)) * sizeof(type->regions[r]));
    type->cnt--;

    /* Special case for empty arrays */
    if (type->cnt == 0) {
        type->cnt = 1;
        type->regions[0].base = 0;
        type->regions[0].size = 0;
        memblock_set_region_node(&type->regions[0], MAX_NUMNODES);
    }
}
示例#4
0
/**
 * memblock_add_region - add new memblock region
 * @type: memblock type to add new region into
 * @base: base address of the new region
 * @size: size of the new region
 * @nid: nid of the new region
 *
 * Add new memblock region [@base,@base+@size) into @type.  The new region
 * is allowed to overlap with existing ones - overlaps don't affect already
 * existing regions.  @type is guaranteed to be minimal (all neighbouring
 * compatible regions are merged) after the addition.
 *
 * RETURNS:
 * 0 on success, -errno on failure.
 */
static int __init_memblock memblock_add_region(struct memblock_type *type,
				phys_addr_t base, phys_addr_t size, int nid)
{
	bool insert = false;
	phys_addr_t obase = base;
	phys_addr_t end = base + memblock_cap_size(base, &size);
	int i, nr_new;

	/* special case for empty array */
	if (type->regions[0].size == 0) {
		WARN_ON(type->cnt != 1 || type->total_size);
		type->regions[0].base = base;
		type->regions[0].size = size;
		memblock_set_region_node(&type->regions[0], nid);
		type->total_size = size;
		return 0;
	}
repeat:
	/*
	 * The following is executed twice.  Once with %false @insert and
	 * then with %true.  The first counts the number of regions needed
	 * to accomodate the new area.  The second actually inserts them.
	 */
	base = obase;
	nr_new = 0;

	for (i = 0; i < type->cnt; i++) {
		struct memblock_region *rgn = &type->regions[i];
		phys_addr_t rbase = rgn->base;
		phys_addr_t rend = rbase + rgn->size;

		if (rbase >= end)
			break;
		if (rend <= base)
			continue;
		/*
		 * @rgn overlaps.  If it separates the lower part of new
		 * area, insert that portion.
		 */
		if (rbase > base) {
			nr_new++;
			if (insert)
				memblock_insert_region(type, i++, base,
						       rbase - base, nid);
		}
		/* area below @rend is dealt with, forget about it */
		base = min(rend, end);
	}

	/* insert the remaining portion */
	if (base < end) {
		nr_new++;
		if (insert)
			memblock_insert_region(type, i, base, end - base, nid);
	}

	/*
	 * If this was the first round, resize array and repeat for actual
	 * insertions; otherwise, merge and return.
	 */
	if (!insert) {
		while (type->cnt + nr_new > type->max)
			if (memblock_double_array(type) < 0)
				return -ENOMEM;
		insert = true;
		goto repeat;
	} else {
		memblock_merge_regions(type);
		return 0;
	}
}