[PATCH 4/5] [PPC] update lmb for hotplug memory add/remove
Benjamin Herrenschmidt
benh at kernel.crashing.org
Thu May 15 16:49:50 EST 2008
On Thu, 2008-03-27 at 16:39 -0800, Badari Pulavarty wrote:
> ppc kernel maintains information about logical memory blocks in
> lmb.memory structure at the boot time. Its not updated for
> hotplug memory add/remove. hotplug memory notifier for memory
> add/remove now updates lmb.memory.
>
> This information is useful for eHEA driver to find out the memory
> layout and holes.
>
> NOTE: No special locking is needed for lmb_add() and lmb_remove().
> Calls to these are serialized by caller. (pSeries_reconfig_chain).
My worry here is the lack of locking...
> Signed-off-by: Badari Pulavarty <pbadari at us.ibm.com>
> ---
> arch/powerpc/platforms/pseries/hotplug-memory.c | 43 +++++++++++++++
> include/linux/lmb.h | 3 -
> lib/lmb.c | 66 ++++++++++++++++++++----
> 3 files changed, 102 insertions(+), 10 deletions(-)
>
> Index: linux-2.6.25-rc3/lib/lmb.c
> ===================================================================
> --- linux-2.6.25-rc3.orig/lib/lmb.c 2008-03-05 10:44:29.000000000 -0800
> +++ linux-2.6.25-rc3/lib/lmb.c 2008-03-05 10:44:56.000000000 -0800
> @@ -54,14 +54,13 @@ void lmb_dump_all(void)
> #endif /* DEBUG */
> }
>
> -static unsigned long __init lmb_addrs_overlap(u64 base1,
> - u64 size1, u64 base2, u64 size2)
> +static unsigned long lmb_addrs_overlap(u64 base1, u64 size1, u64 base2,
> + u64 size2)
> {
> return ((base1 < (base2+size2)) && (base2 < (base1+size1)));
> }
>
> -static long __init lmb_addrs_adjacent(u64 base1, u64 size1,
> - u64 base2, u64 size2)
> +static long lmb_addrs_adjacent(u64 base1, u64 size1, u64 base2, u64 size2)
> {
> if (base2 == base1 + size1)
> return 1;
> @@ -71,7 +70,7 @@ static long __init lmb_addrs_adjacent(u6
> return 0;
> }
>
> -static long __init lmb_regions_adjacent(struct lmb_region *rgn,
> +static long lmb_regions_adjacent(struct lmb_region *rgn,
> unsigned long r1, unsigned long r2)
> {
> u64 base1 = rgn->region[r1].base;
> @@ -82,7 +81,7 @@ static long __init lmb_regions_adjacent(
> return lmb_addrs_adjacent(base1, size1, base2, size2);
> }
>
> -static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r)
> +static void lmb_remove_region(struct lmb_region *rgn, unsigned long r)
> {
> unsigned long i;
>
> @@ -94,7 +93,7 @@ static void __init lmb_remove_region(str
> }
>
> /* Assumption: base addr of region 1 < base addr of region 2 */
> -static void __init lmb_coalesce_regions(struct lmb_region *rgn,
> +static void lmb_coalesce_regions(struct lmb_region *rgn,
> unsigned long r1, unsigned long r2)
> {
> rgn->region[r1].size += rgn->region[r2].size;
> @@ -129,7 +128,7 @@ void __init lmb_analyze(void)
> }
>
> /* This routine called with relocation disabled. */
> -static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
> +static long lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
> {
> unsigned long coalesced = 0;
> long adjacent, i;
> @@ -195,7 +194,7 @@ static long __init lmb_add_region(struct
> }
>
> /* This routine may be called with relocation disabled. */
> -long __init lmb_add(u64 base, u64 size)
> +long lmb_add(u64 base, u64 size)
> {
> struct lmb_region *_rgn = &(lmb.memory);
>
> @@ -207,6 +206,55 @@ long __init lmb_add(u64 base, u64 size)
>
> }
>
> +long lmb_remove(u64 base, u64 size)
> +{
> + struct lmb_region *rgn = &(lmb.memory);
> + u64 rgnbegin, rgnend;
> + u64 end = base + size;
> + int i;
> +
> + rgnbegin = rgnend = 0; /* supress gcc warnings */
> +
> + /* Find the region where (base, size) belongs to */
> + for (i=0; i < rgn->cnt; i++) {
> + rgnbegin = rgn->region[i].base;
> + rgnend = rgnbegin + rgn->region[i].size;
> +
> + if ((rgnbegin <= base) && (end <= rgnend))
> + break;
> + }
> +
> + /* Didn't find the region */
> + if (i == rgn->cnt)
> + return -1;
> +
> + /* Check to see if we are removing entire region */
> + if ((rgnbegin == base) && (rgnend == end)) {
> + lmb_remove_region(rgn, i);
> + return 0;
> + }
> +
> + /* Check to see if region is matching at the front */
> + if (rgnbegin == base) {
> + rgn->region[i].base = end;
> + rgn->region[i].size -= size;
> + return 0;
> + }
> +
> + /* Check to see if the region is matching at the end */
> + if (rgnend == end) {
> + rgn->region[i].size -= size;
> + return 0;
> + }
> +
> + /*
> + * We need to split the entry - adjust the current one to the
> + * beginging of the hole and add the region after hole.
> + */
> + rgn->region[i].size = base - rgn->region[i].base;
> + return lmb_add_region(rgn, end, rgnend - end);
> +}
> +
> long __init lmb_reserve(u64 base, u64 size)
> {
> struct lmb_region *_rgn = &(lmb.reserved);
> Index: linux-2.6.25-rc3/arch/powerpc/platforms/pseries/hotplug-memory.c
> ===================================================================
> --- linux-2.6.25-rc3.orig/arch/powerpc/platforms/pseries/hotplug-memory.c 2008-03-05 10:44:51.000000000 -0800
> +++ linux-2.6.25-rc3/arch/powerpc/platforms/pseries/hotplug-memory.c 2008-03-05 10:45:06.000000000 -0800
> @@ -10,6 +10,7 @@
> */
>
> #include <linux/of.h>
> +#include <linux/lmb.h>
> #include <asm/firmware.h>
> #include <asm/machdep.h>
> #include <asm/pSeries_reconfig.h>
> @@ -58,6 +59,11 @@ static int pseries_remove_memory(struct
> return ret;
>
> /*
> + * Update memory regions for memory remove
> + */
> + lmb_remove(start_pfn << PAGE_SHIFT, regs[3]);
> +
> + /*
> * Remove htab bolted mappings for this section of memory
> */
> start = (unsigned long)__va(start_pfn << PAGE_SHIFT);
> @@ -65,6 +71,41 @@ static int pseries_remove_memory(struct
> return ret;
> }
>
> +static int pseries_add_memory(struct device_node *np)
> +{
> + const char *type;
> + const unsigned int *my_index;
> + const unsigned int *regs;
> + u64 start_pfn;
> + int ret = -EINVAL;
> +
> + /*
> + * Check to see if we are actually adding memory
> + */
> + type = of_get_property(np, "device_type", NULL);
> + if (type == NULL || strcmp(type, "memory") != 0)
> + return 0;
> +
> + /*
> + * Find the memory index and size of the removing section
> + */
> + my_index = of_get_property(np, "ibm,my-drc-index", NULL);
> + if (!my_index)
> + return ret;
> +
> + regs = of_get_property(np, "reg", NULL);
> + if (!regs)
> + return ret;
> +
> + start_pfn = section_nr_to_pfn(*my_index & 0xffff);
> +
> + /*
> + * Update memory region to represent the memory add
> + */
> + lmb_add(start_pfn << PAGE_SHIFT, regs[3]);
> + return 0;
> +}
> +
> static int pseries_memory_notifier(struct notifier_block *nb,
> unsigned long action, void *node)
> {
> @@ -72,6 +113,8 @@ static int pseries_memory_notifier(struc
>
> switch (action) {
> case PSERIES_RECONFIG_ADD:
> + if (pseries_add_memory(node))
> + err = NOTIFY_BAD;
> break;
> case PSERIES_RECONFIG_REMOVE:
> if (pseries_remove_memory(node))
> Index: linux-2.6.25-rc3/include/linux/lmb.h
> ===================================================================
> --- linux-2.6.25-rc3.orig/include/linux/lmb.h 2008-03-05 10:44:29.000000000 -0800
> +++ linux-2.6.25-rc3/include/linux/lmb.h 2008-03-05 10:44:56.000000000 -0800
> @@ -40,7 +40,8 @@ extern struct lmb lmb;
>
> extern void __init lmb_init(void);
> extern void __init lmb_analyze(void);
> -extern long __init lmb_add(u64 base, u64 size);
> +extern long lmb_add(u64 base, u64 size);
> +extern long lmb_remove(u64 base, u64 size);
> extern long __init lmb_reserve(u64 base, u64 size);
> extern u64 __init lmb_alloc(u64 size, u64 align);
> extern u64 __init lmb_alloc_base(u64 size,
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev at ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
More information about the Linuxppc-dev
mailing list