Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb90ef93 authored by Yinghai Lu's avatar Yinghai Lu Committed by Ingo Molnar
Browse files

early_res: Add free_early_partial()



To free partial areas in pcpu_setup...

Reported-by: default avatarPeter Zijlstra <peterz@infradead.org>
Signed-off-by: default avatarYinghai Lu <yinghai@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
LKML-Reference: <4B85E245.5030001@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 2ee78f7b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -137,7 +137,13 @@ static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)

static void __init pcpu_fc_free(void *ptr, size_t size)
{
#ifdef CONFIG_NO_BOOTMEM
	u64 start = __pa(ptr);
	u64 end = start + size;
	free_early_partial(start, end);
#else
	free_bootmem(__pa(ptr), size);
#endif
}

static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
extern void reserve_early(u64 start, u64 end, char *name);
extern void reserve_early_overlap_ok(u64 start, u64 end, char *name);
extern void free_early(u64 start, u64 end);
void free_early_partial(u64 start, u64 end);
extern void early_res_to_bootmem(u64 start, u64 end);

void reserve_early_without_check(u64 start, u64 end, char *name);
+55 −0
Original line number Diff line number Diff line
@@ -61,6 +61,40 @@ static void __init drop_range(int i)
	early_res_count--;
}

static void __init drop_range_partial(int i, u64 start, u64 end)
{
	u64 common_start, common_end;
	u64 old_start, old_end;

	old_start = early_res[i].start;
	old_end = early_res[i].end;
	common_start = max(old_start, start);
	common_end = min(old_end, end);

	/* no overlap ? */
	if (common_start >= common_end)
		return;

	if (old_start < common_start) {
		/* make head segment */
		early_res[i].end = common_start;
		if (old_end > common_end) {
			/* add another for left over on tail */
			reserve_early_without_check(common_end, old_end,
					 early_res[i].name);
		}
		return;
	} else {
		if (old_end > common_end) {
			/* reuse the entry for tail left */
			early_res[i].start = common_end;
			return;
		}
		/* all covered */
		drop_range(i);
	}
}

/*
 * Split any existing ranges that:
 *  1) are marked 'overlap_ok', and
@@ -284,6 +318,27 @@ void __init free_early(u64 start, u64 end)
	drop_range(i);
}

void __init free_early_partial(u64 start, u64 end)
{
	struct early_res *r;
	int i;

try_next:
	i = find_overlapped_early(start, end);
	if (i >= max_early_res)
		return;

	r = &early_res[i];
	/* hole ? */
	if (r->end >= end && r->start <= start) {
		drop_range_partial(i, start, end);
		return;
	}

	drop_range_partial(i, start, end);
	goto try_next;
}

#ifdef CONFIG_NO_BOOTMEM
static void __init subtract_early_res(struct range *range, int az)
{
+0 −3
Original line number Diff line number Diff line
@@ -1929,10 +1929,7 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
			}
			/* copy and return the unused part */
			memcpy(ptr, __per_cpu_load, ai->static_size);
#ifndef CONFIG_NO_BOOTMEM
			/* fix partial free ! */
			free_fn(ptr + size_sum, ai->unit_size - size_sum);
#endif
		}
	}