diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 08:19:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 08:19:14 -0700 |
commit | 867a89e0b73af48838c7987e80899a1ff26dd6ff (patch) | |
tree | b4a8830b3e880b9a5133ad1ec3106665819cc8d4 /arch/powerpc/platforms/pseries | |
parent | 44473d991332053eb3fea1e08f8a6ee2c6fb409c (diff) | |
parent | 6c39103ce5192bdb2195f3daab7323dfa44fb52e (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc:
[RAPIDIO] Change RapidIO doorbell source and target ID field to 16-bit
[RAPIDIO] Add RapidIO connection info print out and re-training for broken connections
[RAPIDIO] Add serial RapidIO controller support, which includes MPC8548, MPC8641
[RAPIDIO] Add RapidIO node probing into MPC86xx_HPCN board id table
[RAPIDIO] Add RapidIO node into MPC8641HPCN dts file
[RAPIDIO] Auto-probe the RapidIO system size
[RAPIDIO] Add OF-tree support to RapidIO controller driver
[RAPIDIO] Add RapidIO multi mport support
[RAPIDIO] Move include/asm-ppc/rio.h to asm-powerpc
[RAPIDIO] Add RapidIO option to kernel configuration
[RAPIDIO] Change RIO function mpc85xx_ to fsl_
[POWERPC] Provide walk_memory_resource() for powerpc
[POWERPC] Update lmb data structures for hotplug memory add/remove
[POWERPC] Hotplug memory remove notifications for powerpc
[POWERPC] windfarm: Add PowerMac 12,1 support
[POWERPC] Fix building of pmac32 when CONFIG_NVRAM=m
[POWERPC] Add IRQSTACKS support on ppc32
[POWERPC] Use __always_inline for xchg* and cmpxchg*
[POWERPC] Add fast little-endian switch system call
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-memory.c | 141 |
2 files changed, 142 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index bd2593ed28d..554c6e42ef2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_PCI) += pci.o pci_dlpar.o obj-$(CONFIG_PCI_MSI) += msi.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o +obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_HVCS) += hvcserver.o diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c new file mode 100644 index 00000000000..3c5727dd5aa --- /dev/null +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -0,0 +1,141 @@ +/* + * pseries Memory Hotplug infrastructure. + * + * Copyright (C) 2008 Badari Pulavarty, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/of.h> +#include <linux/lmb.h> +#include <asm/firmware.h> +#include <asm/machdep.h> +#include <asm/pSeries_reconfig.h> + +static int pseries_remove_memory(struct device_node *np) +{ + const char *type; + const unsigned int *my_index; + const unsigned int *regs; + u64 start_pfn, start; + struct zone *zone; + int ret = -EINVAL; + + /* + * Check to see if we are actually removing 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); + zone = page_zone(pfn_to_page(start_pfn)); + + /* + * Remove section mappings and sysfs entries for the + * section of the memory we are removing. + * + * NOTE: Ideally, this should be done in generic code like + * remove_memory(). But remove_memory() gets called by writing + * to sysfs "state" file and we can't remove sysfs entries + * while writing to it. So we have to defer it to here. + */ + ret = __remove_pages(zone, start_pfn, regs[3] >> PAGE_SHIFT); + if (ret) + 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); + ret = remove_section_mapping(start, start + regs[3]); + 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 added 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) +{ + int err = NOTIFY_OK; + + switch (action) { + case PSERIES_RECONFIG_ADD: + if (pseries_add_memory(node)) + err = NOTIFY_BAD; + break; + case PSERIES_RECONFIG_REMOVE: + if (pseries_remove_memory(node)) + err = NOTIFY_BAD; + break; + default: + err = NOTIFY_DONE; + break; + } + return err; +} + +static struct notifier_block pseries_mem_nb = { + .notifier_call = pseries_memory_notifier, +}; + +static int __init pseries_memory_hotplug_init(void) +{ + if (firmware_has_feature(FW_FEATURE_LPAR)) + pSeries_reconfig_notifier_register(&pseries_mem_nb); + + return 0; +} +machine_device_initcall(pseries, pseries_memory_hotplug_init); |