linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] Update hotplug for pseries systems
@ 2014-06-17 15:42 Nathan Fontenot
  2014-06-17 15:45 ` [RFC PATCH 1/4] Create interface for rtas hotplug events and move mem hotplug to the kernel Nathan Fontenot
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Nathan Fontenot @ 2014-06-17 15:42 UTC (permalink / raw)
  To: linuxppc-dev

In order to support device hotplug (cpu, memory, and pci) in both the
PowerVM and the PowerKVM environments the handling of hotplug events
will need to be updated. This patch set adresses this by creating a
common entry point for handling hotplug events in the kernel that
can be used in both PowerVM and PowerKVM environments. To accomplish
this several changes need to be made.

For PowerVM systems hotplug (DLPAR) events are requested by users from the
HMC which then communicates the request to the partitions via the RSCT
framework. The RSCT framework then invokes the drmgr command to handle
the hotplug event. The drmgr command performs some of the work in user
space and makes calls into the kernel to handle the remaining work.

For PowerKVM systems hotplug events are communicated to the guest via
the ras epow interrupt by qemu. We could have the rtas event sent up
to user space through rtas_errd that would then invoke drmgr. This is
not the most ideal solution and it would be nicer to have hotplug
handled completely in the kernel.

To do this, hotplug events will now be communicated to the kernel in
the form of rtas hotplug events. For PowerKVM systems this is done
by qemu using the ras epow interrupt. For PowerVM systems the drmgr
command will be updated to create a rtas hotplug event and send it to
the kernel via a new /proc/powerpc/dlpar interface. Both of these
entry points for hotplug rtas events then call a common routine
for handling rtas hotplug events.

Additionally we will need to be able to handle all of the work to
do resource hotplug in the kernel. This patch set addresses this for
cpu and memory hotplug, pci hotplug will be done later.

Once all of the work is done to move hotplug handling into the kernel
we should also be able to get rid of the /proc/powerpc/ofdt interface.

Of course these updates do depend on updating the drmgr command. If
you care to look the updates for this is here;

https://github.com/nfont/powerpc-utils/tree/mem_rtas_hp

Patch 1/4:
o Create a common rtas hotplug event handling routine
o Create the /proc/powerpc/dlpar interface for PowerVM systems
o Implement memory hotplug handling in the kernel.

Patch 2/4:
o Move the cpu hotplug code from pseries/dlpar.c to pseries/hotplug-cpu.c

Patch 3/4:
o Update cpu hotplug handling to allow for invocation from rtas event
  notifications.

Patch 4/4:
o Update the ras epow interrupt handler to recognize hotplug rtas events

This code (except for patch 4/4 which I cannot test right now) has been tested
on PowerVM systems. There are some error paths that still need to be tested
and of course testing on PowerKVM when cpu and memory hotplug is enabled
for Power.

Thoughts?

-Nathan
---
 include/asm/rtas.h                 |   27 ++
 kernel/rtas.c                      |    7 
 platforms/pseries/dlpar.c          |  253 ++++++--------------------
 platforms/pseries/hotplug-cpu.c    |  358 +++++++++++++++++++++++++++++++++++++
 platforms/pseries/hotplug-memory.c |  351 ++++++++++++++++++++++++++++++------ 
 platforms/pseries/pseries.h        |    6                                      
 platforms/pseries/ras.c            |   12 +                                    
 platforms/pseries/reconfig.c       |    6 
 8 files changed, 780 insertions(+), 240 deletions(-)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC PATCH 1/4] Create interface for rtas hotplug events and move mem hotplug to the kernel
  2014-06-17 15:42 [RFC PATCH 0/4] Update hotplug for pseries systems Nathan Fontenot
@ 2014-06-17 15:45 ` Nathan Fontenot
  2014-06-17 15:46 ` [RFC PATCH 2/4] Migrate cpu hotplug code to pseries/hotplug-cpu.c Nathan Fontenot
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Nathan Fontenot @ 2014-06-17 15:45 UTC (permalink / raw)
  To: linuxppc-dev

In order to support hotplug of memory, cpu and pci devices in the PowerVM
and the PowerKVM environments we will need to provide a single entry
point. To do this requires updating the way in which we handle hotplug
requests in the PowerVM environment. The idea is to have all of the hotplug
in the kernel so that a hotplug rtas event can used to initiate the hotplug
add/remove of a device.

The current method for handling a hotplug request in a PowerVM partition
is to have the HMC notify the partition of the request through the RSCT
framework which then invokes the drmgr command to hotplug add/remove the
requested devices. The drmgr command does part of this in user-space
and part in the kernel via sysfs and /proc interfaces.

This patch creates the entry point for initiating a hotplug request for
pseries with a rtas hotplug event. For PowerVM systems the drmgr command
will now create and write a hotplug rtas event to /proc/powerpc/dlpar which
will then pass the hotplug rtas event to the entry point. For PowerKVM
systems QEMU will generate an epow interrupt to the guest, which then
calls rtas-check-execption to get the hotplug rtas event and pass it to the
entry point. NOTE that the updates to handle hotplug events from epow
interrupts is not in this intial patch.

This patch also adds funtionality so that we can do memory hotplug in the
kernel. Using the updates to drmgr found below you can initiate memory
hotplug events using the new interface.

https://github.com/nfont/powerpc-utils/tree/mem_rtas_hp

---
 arch/powerpc/include/asm/rtas.h                 |  26 ++
 arch/powerpc/kernel/rtas.c                      |   7 +
 arch/powerpc/platforms/pseries/dlpar.c          |  65 ++++-
 arch/powerpc/platforms/pseries/hotplug-memory.c | 351 ++++++++++++++++++++----
 arch/powerpc/platforms/pseries/pseries.h        |   4 +
 arch/powerpc/platforms/pseries/reconfig.c       |   6 +
 6 files changed, 403 insertions(+), 56 deletions(-)

diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index b390f55..26491ae 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -254,6 +254,31 @@ inline uint32_t rtas_ext_event_company_id(struct rtas_ext_event_log_v6 *ext_log)
 	return be32_to_cpu(ext_log->company_id);
 }
 
+/* RTAS pseries hotplug elog section */ 
+struct pseries_hp_elog {
+	uint8_t		resource;
+	uint8_t		action:8;
+        uint8_t		id_type:8;
+        uint8_t		reserved;
+        union {
+		__be32	drc_index;
+		__be32	drc_count;
+		char	drc_name[1];
+        }_drc_u;
+};
+
+#define HP_ELOG_RESOURCE_CPU	1
+#define HP_ELOG_RESOURCE_MEM	2
+#define HP_ELOG_RESOURCE_SLOT	3
+#define HP_ELOG_RESOURCE_PHB	4
+
+#define HP_ELOG_ACTION_ADD	1
+#define HP_ELOG_ACTION_REMOVE	2
+
+#define HP_ELOG_ID_DRC_NAME	1
+#define HP_ELOG_ID_DRC_INDEX	2
+#define HP_ELOG_ID_DRC_COUNT	3
+
 /* pSeries event log format */
 
 /* Two bytes ASCII section IDs */
@@ -273,6 +298,7 @@ inline uint32_t rtas_ext_event_company_id(struct rtas_ext_event_log_v6 *ext_log)
 #define PSERIES_ELOG_SECT_ID_MANUFACT_INFO	(('M' << 8) | 'I')
 #define PSERIES_ELOG_SECT_ID_CALL_HOME		(('C' << 8) | 'H')
 #define PSERIES_ELOG_SECT_ID_USER_DEF		(('U' << 8) | 'D')
+#define PSERIES_ELOG_SECT_ID_HP			(('H' << 8) | 'P')
 
 /* Vendor specific Platform Event Log Format, Version 6, section header */
 struct pseries_errorlog {
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 8cd5ed0..b738b1b 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -997,6 +997,13 @@ struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
 	uint8_t log_format = rtas_ext_event_log_format(ext_log);
 	uint32_t company_id = rtas_ext_event_company_id(ext_log);
 
+	printk(KERN_EMERG "Validation: %x : %lx\n%x : %x\n%x : %x\n",
+		log->extended_log_length, sizeof(struct rtas_ext_event_log_v6),
+		rtas_ext_event_log_format(ext_log),
+		RTAS_V6EXT_LOG_FORMAT_EVENT_LOG,
+		rtas_ext_event_company_id(ext_log),
+		RTAS_V6EXT_COMPANY_ID_IBM);
+		
 	/* Check that we understand the format */
 	if (ext_log_length < sizeof(struct rtas_ext_event_log_v6) ||
 	    log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 022b38e..dfca23b 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -16,9 +16,13 @@
 #include <linux/cpu.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/proc_fs.h>
+#include <linux/memory.h>
+#include <linux/memblock.h>
+#include <linux/mutex.h>
 #include "offline_states.h"
+#include "pseries.h"
 
-#include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/uaccess.h>
 #include <asm/rtas.h>
@@ -529,13 +533,68 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
 	return count;
 }
 
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
+static int handle_dlpar_errorlog(struct rtas_error_log *error_log)
+{
+	struct pseries_errorlog *pseries_log;
+	struct pseries_hp_elog *hp_elog;
+	int rc = -EINVAL;
+
+	pseries_log = get_pseries_errorlog(error_log, PSERIES_ELOG_SECT_ID_HP);
+	if (!pseries_log)
+		return rc; 
+
+	hp_elog = (struct pseries_hp_elog *)pseries_log->data;
+	switch (hp_elog->resource) {
+	case HP_ELOG_RESOURCE_MEM:
+		rc = dlpar_memory(hp_elog);
+		break;
+	}
+
+	return rc;
+}
+
+static ssize_t dlpar_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *offset)
+{
+	char *event_buf;
+	int rc;
+
+	event_buf = kmalloc(count + 1, GFP_KERNEL);
+	if (!event_buf)
+		return -ENOMEM;
+
+	rc = copy_from_user(event_buf, buf, count);
+	if (rc) {
+		kfree(event_buf);
+		return rc;
+	}
+
+	rc = handle_dlpar_errorlog((struct rtas_error_log *)event_buf);
+	kfree(event_buf);
+	return rc;
+}
+
+static const struct file_operations dlpar_fops = {
+	.write = dlpar_write,
+	.llseek = noop_llseek,
+};
+
 static int __init pseries_dlpar_init(void)
 {
+	struct proc_dir_entry *proc_ent;
+
+	proc_ent = proc_create("powerpc/dlpar", S_IWUSR, NULL, &dlpar_fops);
+	if (proc_ent)
+		proc_set_size(proc_ent, 0);
+
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
 	ppc_md.cpu_probe = dlpar_cpu_probe;
 	ppc_md.cpu_release = dlpar_cpu_release;
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
 
 	return 0;
 }
 machine_device_initcall(pseries, pseries_dlpar_init);
-
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 7f75c94..af479eb 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -15,11 +15,17 @@
 #include <linux/vmalloc.h>
 #include <linux/memory.h>
 #include <linux/memory_hotplug.h>
+#include <linux/slab.h>
 
 #include <asm/firmware.h>
 #include <asm/machdep.h>
-#include <asm/prom.h>
 #include <asm/sparsemem.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+
+#include "pseries.h"
+
+DEFINE_MUTEX(dlpar_mem_mutex);
 
 static unsigned long get_memblock_size(void)
 {
@@ -75,6 +81,186 @@ unsigned long memory_block_size_bytes(void)
 	return get_memblock_size();
 }
 
+static struct property *dlpar_clone_drconf_property(struct device_node *dn)
+{
+	struct property *prop, *new_prop;
+
+	prop = of_find_property(dn, "ibm,dynamic-memory", NULL);
+	if (!prop)
+		return NULL;
+
+	new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
+	if (!new_prop)
+		return NULL;
+
+	new_prop->name = kstrdup(prop->name, GFP_KERNEL);
+	new_prop->value = kmalloc(prop->length + 1, GFP_KERNEL);
+	if (!new_prop->name || !new_prop->value) {
+		kfree(new_prop->name);
+		kfree(new_prop->value);
+		kfree(new_prop);
+		return NULL;
+	}
+
+	memcpy(new_prop->value, prop->value, prop->length);
+	new_prop->length = prop->length;
+	*(((char *)new_prop->value) + new_prop->length) = 0;
+
+	return new_prop;
+}
+
+static int lmb_is_removable(struct of_drconf_cell *lmb)
+{
+	int i, scns_per_block;
+	int rc = 1;
+	unsigned long pfn, block_sz;
+	uint64_t base_addr;
+
+	base_addr = lmb->base_addr;
+	block_sz = memory_block_size_bytes();
+	scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
+
+	for (i = 0; i < scns_per_block; i++) {
+		pfn = PFN_DOWN(base_addr);
+		if (!pfn_present(pfn))
+			continue;
+	
+		rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
+		base_addr += MIN_MEMORY_BLOCK_SIZE;
+	}
+
+	return rc;
+}
+
+static int lmb_is_usable(struct pseries_hp_elog *hp_elog,
+			 struct of_drconf_cell *lmb)
+{
+	if (hp_elog->id_type == HP_ELOG_ID_DRC_INDEX
+	    && hp_elog->_drc_u.drc_index == lmb->drc_index) {
+		return 1;
+	} else {
+		if (hp_elog->action == HP_ELOG_ACTION_ADD
+		    && !(lmb->flags & DRCONF_MEM_ASSIGNED))
+			return 1;
+
+		if (hp_elog->action == HP_ELOG_ACTION_REMOVE
+		    && lmb->flags & DRCONF_MEM_ASSIGNED)
+			return lmb_is_removable(lmb);
+	}
+
+	return 0;
+}
+
+static struct memory_block *lmb_to_memblock(struct of_drconf_cell *lmb)
+{
+	unsigned long section_nr;
+	struct mem_section *mem_sect;
+	struct memory_block *mem_block;
+
+	section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr));
+	mem_sect = __nr_to_section(section_nr);
+
+	mem_block = find_memory_block(mem_sect);
+	return mem_block;
+}
+
+static int dlpar_add_one_lmb(struct of_drconf_cell *lmb)
+{
+	struct memory_block *mem_block;
+	u64 phys_addr;
+	unsigned long pages_per_block;
+	unsigned long block_sz;
+	int nid, sections_per_block;
+	int rc;
+
+	phys_addr = lmb->base_addr;
+	block_sz = memory_block_size_bytes();
+	sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
+	pages_per_block = PAGES_PER_SECTION * sections_per_block;
+
+	if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
+		return -EINVAL;
+
+	nid = memory_add_physaddr_to_nid(phys_addr);
+	rc = add_memory(nid, phys_addr, block_sz);
+	if (rc)
+		return rc;
+
+	rc = memblock_add(lmb->base_addr, block_sz);
+	if (rc) {
+		remove_memory(nid, phys_addr, block_sz);
+		return rc;
+	}
+
+	mem_block = lmb_to_memblock(lmb);
+	if (!mem_block) {
+		remove_memory(nid, phys_addr, block_sz);
+		return -EINVAL;
+	}
+
+	rc = device_online(&mem_block->dev);
+	put_device(&mem_block->dev);
+	if (rc)
+		remove_memory(nid, phys_addr, block_sz);
+
+	return rc;
+}
+
+static int dlpar_memory_add(struct pseries_hp_elog *hp_elog)
+{
+	struct of_drconf_cell *lmb;
+	struct device_node *dn;
+	struct property *prop;
+	uint32_t *p, entries;
+	int i, lmbs_to_add;
+	int lmbs_added = 0;
+	int rc = -EINVAL;
+
+	if (hp_elog->id_type == HP_ELOG_ID_DRC_COUNT)
+		lmbs_to_add = hp_elog->_drc_u.drc_count;
+	else
+		lmbs_to_add = 1;
+
+	dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+	if (!dn)
+		return -EINVAL;
+
+	prop = dlpar_clone_drconf_property(dn);
+	if (!prop) {
+		of_node_put(dn);
+		return -EINVAL;
+	}
+
+        p = prop->value;
+        entries = *p++;
+        lmb = (struct of_drconf_cell *)p;
+
+	for (i = 0; i < entries; i++, lmb++) {
+		if (lmbs_to_add == lmbs_added)
+			break;
+
+		if (!lmb_is_usable(hp_elog, lmb))
+			continue;
+
+		rc = dlpar_acquire_drc(lmb->drc_index);
+		if (rc)
+			continue;
+
+		rc = dlpar_add_one_lmb(lmb);
+
+		lmb->flags |= DRCONF_MEM_ASSIGNED;
+		lmbs_added++;
+	}
+
+	if (lmbs_added)
+		rc = of_update_property(dn, prop);
+	else
+		kfree(prop);
+
+	of_node_put(dn);
+	return rc ? rc : lmbs_added;
+}
+
 #ifdef CONFIG_MEMORY_HOTREMOVE
 static int pseries_remove_memory(u64 start, u64 size)
 {
@@ -92,6 +278,93 @@ static int pseries_remove_memory(u64 start, u64 size)
 	return ret;
 }
 
+static int dlpar_remove_one_lmb(struct of_drconf_cell *lmb)
+{
+	struct memory_block *mem_block;
+	unsigned long block_sz;
+	int nid, rc;
+
+	block_sz = memory_block_size_bytes();
+	nid = memory_add_physaddr_to_nid(lmb->base_addr);
+
+	if (!pfn_valid(lmb->base_addr >> PAGE_SHIFT)) {
+		memblock_remove(lmb->base_addr, block_sz);
+		return 0;
+	}
+
+	mem_block = lmb_to_memblock(lmb);
+	if (!mem_block)
+		return -EINVAL;
+
+	rc = device_offline(&mem_block->dev);
+	put_device(&mem_block->dev);
+	if (rc)
+		return rc;
+
+	remove_memory(nid, lmb->base_addr, block_sz);
+	memblock_remove(lmb->base_addr, block_sz);
+
+	return 0;
+}
+
+static int dlpar_memory_remove(struct pseries_hp_elog *hp_elog)
+{
+	struct of_drconf_cell *lmb;
+	struct device_node *dn;
+	struct property *prop;
+	int lmbs_to_remove, lmbs_removed = 0;
+	int i, rc, entries;
+	uint32_t *p;
+
+	if (hp_elog->id_type == HP_ELOG_ID_DRC_COUNT)
+		lmbs_to_remove = hp_elog->_drc_u.drc_count;
+	else
+		lmbs_to_remove = 1;
+
+	dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+	if (!dn)
+		return -EINVAL;
+
+	prop = dlpar_clone_drconf_property(dn);
+	if (!prop) {
+		of_node_put(dn);
+		return -EINVAL;
+	}
+
+        p = prop->value;
+        entries = *p++;
+        lmb = (struct of_drconf_cell *)p;
+
+	for (i = 0; i < entries; i++, lmb++) {
+		if (lmbs_to_remove == lmbs_removed)
+			break;
+
+		if (!lmb_is_usable(hp_elog, lmb))
+			continue;
+
+		rc = dlpar_remove_one_lmb(lmb);
+		if (rc)
+			continue;
+
+		rc = dlpar_release_drc(lmb->drc_index);
+		if (rc) {
+			dlpar_add_one_lmb(lmb);
+			continue;
+		}
+
+		lmb->flags &= ~DRCONF_MEM_ASSIGNED;
+		lmbs_removed++;
+	}
+
+	if (lmbs_removed)
+		rc = of_update_property(dn, prop);
+	else
+		kfree(prop);
+
+	of_node_put(dn);
+	return rc;
+}
+
 static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
 {
 	unsigned long block_sz, start_pfn;
@@ -150,6 +423,10 @@ static int pseries_remove_mem_node(struct device_node *np)
 	return 0;
 }
 #else
+static inline int dlpar_memory_remove(struct pseries_hp_elog *hp_elog)
+{
+	return -EOPNOTSUPP;
+}
 static inline int pseries_remove_memblock(unsigned long base,
 					  unsigned int memblock_size)
 {
@@ -161,6 +438,25 @@ static inline int pseries_remove_mem_node(struct device_node *np)
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
+int dlpar_memory(struct pseries_hp_elog *hp_elog)
+{
+	int rc = 0;
+
+	mutex_lock(&dlpar_mem_mutex);
+
+	switch (hp_elog->action) {
+	case HP_ELOG_ACTION_ADD:
+		rc = dlpar_memory_add(hp_elog);
+		break;
+	case HP_ELOG_ACTION_REMOVE:
+		rc = dlpar_memory_remove(hp_elog);
+		break;
+	}
+
+	mutex_unlock(&dlpar_mem_mutex);
+	return rc;
+}
+
 static int pseries_add_mem_node(struct device_node *np)
 {
 	const char *type;
@@ -193,56 +489,9 @@ static int pseries_add_mem_node(struct device_node *np)
 	return (ret < 0) ? -EINVAL : 0;
 }
 
-static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
-{
-	struct of_drconf_cell *new_drmem, *old_drmem;
-	unsigned long memblock_size;
-	u32 entries;
-	u32 *p;
-	int i, rc = -EINVAL;
-
-	memblock_size = get_memblock_size();
-	if (!memblock_size)
-		return -EINVAL;
-
-	p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL);
-	if (!p)
-		return -EINVAL;
-
-	/* The first int of the property is the number of lmb's described
-	 * by the property. This is followed by an array of of_drconf_cell
-	 * entries. Get the niumber of entries and skip to the array of
-	 * of_drconf_cell's.
-	 */
-	entries = *p++;
-	old_drmem = (struct of_drconf_cell *)p;
-
-	p = (u32 *)pr->prop->value;
-	p++;
-	new_drmem = (struct of_drconf_cell *)p;
-
-	for (i = 0; i < entries; i++) {
-		if ((old_drmem[i].flags & DRCONF_MEM_ASSIGNED) &&
-		    (!(new_drmem[i].flags & DRCONF_MEM_ASSIGNED))) {
-			rc = pseries_remove_memblock(old_drmem[i].base_addr,
-						     memblock_size);
-			break;
-		} else if ((!(old_drmem[i].flags & DRCONF_MEM_ASSIGNED)) &&
-			   (new_drmem[i].flags & DRCONF_MEM_ASSIGNED)) {
-			rc = memblock_add(old_drmem[i].base_addr,
-					  memblock_size);
-			rc = (rc < 0) ? -EINVAL : 0;
-			break;
-		}
-	}
-
-	return rc;
-}
-
 static int pseries_memory_notifier(struct notifier_block *nb,
 				   unsigned long action, void *node)
 {
-	struct of_prop_reconfig *pr;
 	int err = 0;
 
 	switch (action) {
@@ -252,12 +501,8 @@ static int pseries_memory_notifier(struct notifier_block *nb,
 	case OF_RECONFIG_DETACH_NODE:
 		err = pseries_remove_mem_node(node);
 		break;
-	case OF_RECONFIG_UPDATE_PROPERTY:
-		pr = (struct of_prop_reconfig *)node;
-		if (!strcmp(pr->prop->name, "ibm,dynamic-memory"))
-			err = pseries_update_drconf_memory(pr);
-		break;
 	}
+
 	return notifier_from_errno(err);
 }
 
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 9921953..89c25769 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -11,6 +11,7 @@
 #define _PSERIES_PSERIES_H
 
 #include <linux/interrupt.h>
+#include <asm/rtas.h>
 
 struct device_node;
 
@@ -59,6 +60,9 @@ extern void dlpar_free_cc_property(struct property *);
 extern struct device_node *dlpar_configure_connector(u32, struct device_node *);
 extern int dlpar_attach_node(struct device_node *);
 extern int dlpar_detach_node(struct device_node *);
+extern int dlpar_acquire_drc(u32);
+extern int dlpar_release_drc(u32);
+extern int dlpar_memory(struct pseries_hp_elog *);
 
 /* PCI root bridge prepare function override for pseries */
 struct pci_host_bridge;
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 0435bb6..8a1f3cf4 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -370,6 +370,12 @@ static int do_update_property(char *buf, size_t bufsize)
 	if (!strlen(name))
 		return -ENODEV;
 
+	/* updating the ibm,dynamic-memory property is no longer
+	 * supported through this interface.
+	 */
+	if (!strcmp(name, "ibm,dynamic-memory"))
+		return -EINVAL;
+
 	newprop = new_property(name, length, value, NULL);
 	if (!newprop)
 		return -ENOMEM;
-- 
2.0.0.rc3.2.g998f840

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH 2/4] Migrate cpu hotplug code to pseries/hotplug-cpu.c
  2014-06-17 15:42 [RFC PATCH 0/4] Update hotplug for pseries systems Nathan Fontenot
  2014-06-17 15:45 ` [RFC PATCH 1/4] Create interface for rtas hotplug events and move mem hotplug to the kernel Nathan Fontenot
@ 2014-06-17 15:46 ` Nathan Fontenot
  2014-06-17 15:46 ` [RFC PATCH 3/4] Handle cpu hotplug from rtas hotplug events Nathan Fontenot
  2014-06-17 15:47 ` [RFC PATCH 4/4] Hook into ras epow interrupt handler for hotplug Nathan Fontenot
  3 siblings, 0 replies; 5+ messages in thread
From: Nathan Fontenot @ 2014-06-17 15:46 UTC (permalink / raw)
  To: linuxppc-dev

This patch moves the cpu hotplug handling code from pseries/dlpar.c
to pseries/hotplug-cpu.c. Additionally it factors out the work to
add/remove a single cpu into its own routine.

---
 arch/powerpc/platforms/pseries/dlpar.c       | 182 -------------------------
 arch/powerpc/platforms/pseries/hotplug-cpu.c | 194 +++++++++++++++++++++++++++
 2 files changed, 194 insertions(+), 182 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index dfca23b..16c85b9 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -359,182 +359,6 @@ int dlpar_release_drc(u32 drc_index)
 	return 0;
 }
 
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-
-static int dlpar_online_cpu(struct device_node *dn)
-{
-	int rc = 0;
-	unsigned int cpu;
-	int len, nthreads, i;
-	const u32 *intserv;
-
-	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
-	if (!intserv)
-		return -EINVAL;
-
-	nthreads = len / sizeof(u32);
-
-	cpu_maps_update_begin();
-	for (i = 0; i < nthreads; i++) {
-		for_each_present_cpu(cpu) {
-			if (get_hard_smp_processor_id(cpu) != intserv[i])
-				continue;
-			BUG_ON(get_cpu_current_state(cpu)
-					!= CPU_STATE_OFFLINE);
-			cpu_maps_update_done();
-			rc = cpu_up(cpu);
-			if (rc)
-				goto out;
-			cpu_maps_update_begin();
-
-			break;
-		}
-		if (cpu == num_possible_cpus())
-			printk(KERN_WARNING "Could not find cpu to online "
-			       "with physical id 0x%x\n", intserv[i]);
-	}
-	cpu_maps_update_done();
-
-out:
-	return rc;
-
-}
-
-static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
-{
-	struct device_node *dn, *parent;
-	unsigned long drc_index;
-	int rc;
-
-	rc = strict_strtoul(buf, 0, &drc_index);
-	if (rc)
-		return -EINVAL;
-
-	parent = of_find_node_by_path("/cpus");
-	if (!parent)
-		return -ENODEV;
-
-	dn = dlpar_configure_connector(drc_index, parent);
-	if (!dn)
-		return -EINVAL;
-
-	of_node_put(parent);
-
-	rc = dlpar_acquire_drc(drc_index);
-	if (rc) {
-		dlpar_free_cc_nodes(dn);
-		return -EINVAL;
-	}
-
-	rc = dlpar_attach_node(dn);
-	if (rc) {
-		dlpar_release_drc(drc_index);
-		dlpar_free_cc_nodes(dn);
-		return rc;
-	}
-
-	rc = dlpar_online_cpu(dn);
-	if (rc)
-		return rc;
-
-	return count;
-}
-
-static int dlpar_offline_cpu(struct device_node *dn)
-{
-	int rc = 0;
-	unsigned int cpu;
-	int len, nthreads, i;
-	const u32 *intserv;
-
-	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
-	if (!intserv)
-		return -EINVAL;
-
-	nthreads = len / sizeof(u32);
-
-	cpu_maps_update_begin();
-	for (i = 0; i < nthreads; i++) {
-		for_each_present_cpu(cpu) {
-			if (get_hard_smp_processor_id(cpu) != intserv[i])
-				continue;
-
-			if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
-				break;
-
-			if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
-				set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
-				cpu_maps_update_done();
-				rc = cpu_down(cpu);
-				if (rc)
-					goto out;
-				cpu_maps_update_begin();
-				break;
-
-			}
-
-			/*
-			 * The cpu is in CPU_STATE_INACTIVE.
-			 * Upgrade it's state to CPU_STATE_OFFLINE.
-			 */
-			set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
-			BUG_ON(plpar_hcall_norets(H_PROD, intserv[i])
-								!= H_SUCCESS);
-			__cpu_die(cpu);
-			break;
-		}
-		if (cpu == num_possible_cpus())
-			printk(KERN_WARNING "Could not find cpu to offline "
-			       "with physical id 0x%x\n", intserv[i]);
-	}
-	cpu_maps_update_done();
-
-out:
-	return rc;
-
-}
-
-static ssize_t dlpar_cpu_release(const char *buf, size_t count)
-{
-	struct device_node *dn;
-	const u32 *drc_index;
-	int rc;
-
-	dn = of_find_node_by_path(buf);
-	if (!dn)
-		return -EINVAL;
-
-	drc_index = of_get_property(dn, "ibm,my-drc-index", NULL);
-	if (!drc_index) {
-		of_node_put(dn);
-		return -EINVAL;
-	}
-
-	rc = dlpar_offline_cpu(dn);
-	if (rc) {
-		of_node_put(dn);
-		return -EINVAL;
-	}
-
-	rc = dlpar_release_drc(*drc_index);
-	if (rc) {
-		of_node_put(dn);
-		return rc;
-	}
-
-	rc = dlpar_detach_node(dn);
-	if (rc) {
-		dlpar_acquire_drc(*drc_index);
-		return rc;
-	}
-
-	of_node_put(dn);
-
-	return count;
-}
-
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
-
 static int handle_dlpar_errorlog(struct rtas_error_log *error_log)
 {
 	struct pseries_errorlog *pseries_log;
@@ -589,12 +413,6 @@ static int __init pseries_dlpar_init(void)
 	if (proc_ent)
 		proc_set_size(proc_ent, 0);
 
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-	ppc_md.cpu_probe = dlpar_cpu_probe;
-	ppc_md.cpu_release = dlpar_cpu_release;
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
-
-
 	return 0;
 }
 machine_device_initcall(pseries, pseries_dlpar_init);
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 20d6297..6b42fd5 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -33,6 +33,7 @@
 #include <asm/plpar_wrappers.h>
 
 #include "offline_states.h"
+#include "pseries.h"
 
 /* This version can't take the spinlock, because it never returns */
 static int rtas_stop_self_token = RTAS_UNKNOWN_SERVICE;
@@ -235,6 +236,194 @@ static void pseries_cpu_die(unsigned int cpu)
 	paca[cpu].cpu_start = 0;
 }
 
+static int dlpar_online_cpu(struct device_node *dn)
+{
+	int rc = 0;
+	unsigned int cpu;
+	int len, nthreads, i;
+	const u32 *intserv;
+
+	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+	if (!intserv)
+		return -EINVAL;
+
+	nthreads = len / sizeof(u32);
+
+	cpu_maps_update_begin();
+	for (i = 0; i < nthreads; i++) {
+		for_each_present_cpu(cpu) {
+			if (get_hard_smp_processor_id(cpu) != intserv[i])
+				continue;
+			BUG_ON(get_cpu_current_state(cpu)
+					!= CPU_STATE_OFFLINE);
+			cpu_maps_update_done();
+			rc = cpu_up(cpu);
+			if (rc)
+				goto out;
+			cpu_maps_update_begin();
+
+			break;
+		}
+		if (cpu == num_possible_cpus())
+			printk(KERN_WARNING "Could not find cpu to online "
+			       "with physical id 0x%x\n", intserv[i]);
+	}
+	cpu_maps_update_done();
+
+out:
+	return rc;
+
+}
+
+static ssize_t dlpar_add_one_cpu(u32 drc_index)
+{
+	struct device_node *dn, *parent;
+	int rc;
+
+	parent = of_find_node_by_path("/cpus");
+	if (!parent)
+		return -ENODEV;
+
+	dn = dlpar_configure_connector(drc_index, parent);
+	if (!dn)
+		return -EINVAL;
+
+	of_node_put(parent);
+
+	rc = dlpar_acquire_drc(drc_index);
+	if (rc) {
+		dlpar_free_cc_nodes(dn);
+		return -EINVAL;
+	}
+
+	rc = dlpar_attach_node(dn);
+	if (rc) {
+		dlpar_release_drc(drc_index);
+		dlpar_free_cc_nodes(dn);
+		return rc;
+	}
+
+	rc = dlpar_online_cpu(dn);
+	return rc;
+}
+
+static int dlpar_offline_cpu(struct device_node *dn)
+{
+	int rc = 0;
+	unsigned int cpu;
+	int len, nthreads, i;
+	const u32 *intserv;
+
+	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+	if (!intserv)
+		return -EINVAL;
+
+	nthreads = len / sizeof(u32);
+
+	cpu_maps_update_begin();
+	for (i = 0; i < nthreads; i++) {
+		for_each_present_cpu(cpu) {
+			if (get_hard_smp_processor_id(cpu) != intserv[i])
+				continue;
+
+			if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
+				break;
+
+			if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
+				set_preferred_offline_state(cpu,
+							    CPU_STATE_OFFLINE);
+				cpu_maps_update_done();
+				rc = cpu_down(cpu);
+				if (rc)
+					goto out;
+				cpu_maps_update_begin();
+				break;
+
+			}
+
+			/*
+			 * The cpu is in CPU_STATE_INACTIVE.
+			 * Upgrade it's state to CPU_STATE_OFFLINE.
+			 */
+			set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
+			BUG_ON(plpar_hcall_norets(H_PROD, intserv[i])
+								!= H_SUCCESS);
+			__cpu_die(cpu);
+			break;
+		}
+		if (cpu == num_possible_cpus())
+			printk(KERN_WARNING "Could not find cpu to offline "
+			       "with physical id 0x%x\n", intserv[i]);
+	}
+	cpu_maps_update_done();
+
+out:
+	return rc;
+
+}
+
+static int dlpar_remove_one_cpu(struct device_node *dn, u32 drc_index)
+{
+	int rc;
+
+	rc = dlpar_offline_cpu(dn);
+	if (rc) {
+		of_node_put(dn);
+		return -EINVAL;
+	}
+
+	rc = dlpar_release_drc(drc_index);
+	if (rc) {
+		of_node_put(dn);
+		return rc;
+	}
+
+	rc = dlpar_detach_node(dn);
+	if (rc) {
+		dlpar_acquire_drc(drc_index);
+		return rc;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+static ssize_t dlpar_cpu_release(const char *buf, size_t count)
+{
+	struct device_node *dn;
+	const u32 *drc_index;
+	int rc;
+
+	dn = of_find_node_by_path(buf);
+	if (!dn)
+		return -EINVAL;
+
+	drc_index = of_get_property(dn, "ibm,my-drc-index", NULL);
+	if (!drc_index) {
+		of_node_put(dn);
+		return -EINVAL;
+	}
+
+	rc = dlpar_remove_one_cpu(dn, *drc_index);
+	of_node_put(dn);
+
+	return rc ? rc : count;
+}
+
+static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
+{
+	unsigned long drc_index;
+	int rc;
+
+	rc = strict_strtoul(buf, 0, &drc_index);
+	if (rc)
+		return -EINVAL;
+
+	rc = dlpar_add_one_cpu(drc_index);
+	return rc ? rc : count;
+}
+#endif
+
 /*
  * Update cpu_present_mask and paca(s) for a new cpu node.  The wrinkle
  * here is that a cpu device node may represent up to two logical cpus
@@ -403,6 +592,11 @@ static int __init pseries_cpu_hotplug_init(void)
 		return 0;
 	}
 
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+	ppc_md.cpu_probe = dlpar_cpu_probe;
+	ppc_md.cpu_release = dlpar_cpu_release;
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
 	ppc_md.cpu_die = pseries_mach_cpu_die;
 	smp_ops->cpu_disable = pseries_cpu_disable;
 	smp_ops->cpu_die = pseries_cpu_die;
-- 
2.0.0.rc3.2.g998f840

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH 3/4] Handle cpu hotplug from rtas hotplug events
  2014-06-17 15:42 [RFC PATCH 0/4] Update hotplug for pseries systems Nathan Fontenot
  2014-06-17 15:45 ` [RFC PATCH 1/4] Create interface for rtas hotplug events and move mem hotplug to the kernel Nathan Fontenot
  2014-06-17 15:46 ` [RFC PATCH 2/4] Migrate cpu hotplug code to pseries/hotplug-cpu.c Nathan Fontenot
@ 2014-06-17 15:46 ` Nathan Fontenot
  2014-06-17 15:47 ` [RFC PATCH 4/4] Hook into ras epow interrupt handler for hotplug Nathan Fontenot
  3 siblings, 0 replies; 5+ messages in thread
From: Nathan Fontenot @ 2014-06-17 15:46 UTC (permalink / raw)
  To: linuxppc-dev

This patch updates the cpu hotplug handling code so that we can perform
cpu hotplug using the new rtas hotplug event interface while still
maintaining the ability to use the probe/release sysfs interface
for adding and removing cpus.

At a later point we could deprecate the use of the probe/release sysfs
files and remove those code bits.

---
 arch/powerpc/platforms/pseries/dlpar.c       |   4 +
 arch/powerpc/platforms/pseries/hotplug-cpu.c | 164 +++++++++++++++++++++++++++
 arch/powerpc/platforms/pseries/pseries.h     |   1 +
 3 files changed, 169 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 16c85b9..53f4fe6 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -275,6 +275,7 @@ int dlpar_attach_node(struct device_node *dn)
 	if (!dn->parent)
 		return -ENOMEM;
 
+	of_node_init(dn);
 	rc = of_attach_node(dn);
 	if (rc) {
 		printk(KERN_ERR "Failed to add device node %s\n",
@@ -374,6 +375,9 @@ static int handle_dlpar_errorlog(struct rtas_error_log *error_log)
 	case HP_ELOG_RESOURCE_MEM:
 		rc = dlpar_memory(hp_elog);
 		break;
+	case HP_ELOG_RESOURCE_CPU:
+		rc = dlpar_cpus(hp_elog);
+		break;
 	}
 
 	return rc;
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 6b42fd5..8be88d6 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -24,6 +24,7 @@
 #include <linux/sched.h>	/* for idle_task_exit */
 #include <linux/cpu.h>
 #include <linux/of.h>
+#include <linux/slab.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/firmware.h>
@@ -387,6 +388,169 @@ static int dlpar_remove_one_cpu(struct device_node *dn, u32 drc_index)
 	return 0;
 }
 
+struct cpu_drc_info {
+	u32	drc_index;
+	int	present;
+};
+
+static struct cpu_drc_info *get_cpu_drc_info(int *drc_count)
+{
+	struct device_node *dn, *child = NULL;
+	struct cpu_drc_info *drcs;
+	const u32 *indexes;
+	int i, count;
+
+	dn = of_find_node_by_path("/cpus");
+	if (!dn)
+		return NULL;
+
+	indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
+	if (!indexes) {
+		of_node_put(dn);
+		return NULL;
+	}
+
+	count = *indexes++;
+	drcs = kzalloc(count * sizeof(*drcs), GFP_KERNEL);
+	if (!drcs) {
+		of_node_put(dn);
+		return NULL;
+	}
+
+	for (i = 0; i < count; i++)
+		drcs[i].drc_index = indexes[i];
+
+	for_each_child_of_node(dn, child) {
+		const u32 *drc_index;
+
+		drc_index = of_get_property(child, "ibm,my-drc-index", NULL);
+		if (!drc_index)
+			continue;
+
+		for (i = 0; i < count; i++) {
+			if (drcs[i].drc_index == *drc_index)
+				drcs[i].present = 1;
+				break;
+		}
+	}
+
+	of_node_put(dn);
+	*drc_count = count;
+	return drcs;
+}
+
+static struct device_node *cpu_drc_index_to_device(u32 drc_index)
+{
+	struct device_node *parent, *child;
+	const u32 *my_drc_index;
+
+	parent = of_find_node_by_path("/cpus");
+	if (!parent)
+		return NULL;
+
+	for_each_child_of_node(parent, child) {
+		my_drc_index = of_get_property(child, "ibm,my-drc-index", NULL);
+		if (!my_drc_index)
+			continue;
+
+		if (*my_drc_index == drc_index)
+			break;
+	}
+
+	of_node_put(parent);
+	return child;
+}
+
+static int dlpar_remove_cpus(struct pseries_hp_elog *hp_elog,
+			    struct cpu_drc_info *cpu_drcs, int num_drcs)
+{
+	struct device_node *dn;
+	int cpus_to_remove, cpus_removed = 0;
+	int rc, i;
+
+	if (hp_elog->id_type == HP_ELOG_ID_DRC_COUNT)
+		cpus_to_remove = hp_elog->_drc_u.drc_count;
+	else
+		cpus_to_remove = 1;
+
+	for (i = 0; i < num_drcs; i++) {
+		if (cpus_to_remove == cpus_removed)
+			break;
+
+		if (!cpu_drcs[i].present)
+			continue;
+
+		if (hp_elog->id_type == HP_ELOG_ID_DRC_INDEX
+		    && hp_elog->_drc_u.drc_index != cpu_drcs[i].drc_index)
+			continue;
+
+		dn = cpu_drc_index_to_device(cpu_drcs[i].drc_index);
+		if (!dn)
+			continue;
+
+		rc = dlpar_remove_one_cpu(dn, cpu_drcs[i].drc_index);
+		of_node_put(dn);
+		
+		if (!rc)
+			cpus_removed++;
+	}
+
+	return (cpus_to_remove == cpus_removed) ? 0: -1;
+}
+
+static int dlpar_add_cpus(struct pseries_hp_elog *hp_elog,
+			  struct cpu_drc_info *cpu_drcs, int num_drcs)
+{
+	int cpus_to_add, cpus_added = 0;
+	int rc, i;
+
+	if (hp_elog->id_type == HP_ELOG_ID_DRC_COUNT)
+		cpus_to_add = hp_elog->_drc_u.drc_count;
+	else
+		cpus_to_add = 1;
+
+	for (i = 0; i < num_drcs; i++) {
+		if (cpus_to_add == cpus_added)
+			break;
+
+		if (cpu_drcs[i].present)
+			continue;
+
+		if (hp_elog->id_type == HP_ELOG_ID_DRC_INDEX
+		    && hp_elog->_drc_u.drc_index != cpu_drcs[i].drc_index)
+			continue;
+		
+		rc = dlpar_add_one_cpu(cpu_drcs[i].drc_index);
+		if (!rc)
+			cpus_added++;
+	}
+
+	return (cpus_to_add == cpus_added) ? 0: -1;
+}
+
+int dlpar_cpus(struct pseries_hp_elog *hp_elog)
+{
+	struct cpu_drc_info *cpu_drcs;
+	int num_drcs;
+	int rc = 0;
+
+	cpu_drcs = get_cpu_drc_info(&num_drcs);
+	if (!cpu_drcs)
+		return -1;
+
+	switch (hp_elog->action) {
+	case HP_ELOG_ACTION_ADD:
+		rc = dlpar_add_cpus(hp_elog, cpu_drcs, num_drcs);
+		break;
+	case HP_ELOG_ACTION_REMOVE:
+		rc = dlpar_remove_cpus(hp_elog, cpu_drcs, num_drcs);
+		break;
+	}
+
+	kfree(cpu_drcs);
+	return rc;
+}
+
 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
 static ssize_t dlpar_cpu_release(const char *buf, size_t count)
 {
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 89c25769..1706215 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -63,6 +63,7 @@ extern int dlpar_detach_node(struct device_node *);
 extern int dlpar_acquire_drc(u32);
 extern int dlpar_release_drc(u32);
 extern int dlpar_memory(struct pseries_hp_elog *);
+extern int dlpar_cpus(struct pseries_hp_elog *);
 
 /* PCI root bridge prepare function override for pseries */
 struct pci_host_bridge;
-- 
2.0.0.rc3.2.g998f840

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH 4/4] Hook into ras epow interrupt handler for hotplug
  2014-06-17 15:42 [RFC PATCH 0/4] Update hotplug for pseries systems Nathan Fontenot
                   ` (2 preceding siblings ...)
  2014-06-17 15:46 ` [RFC PATCH 3/4] Handle cpu hotplug from rtas hotplug events Nathan Fontenot
@ 2014-06-17 15:47 ` Nathan Fontenot
  3 siblings, 0 replies; 5+ messages in thread
From: Nathan Fontenot @ 2014-06-17 15:47 UTC (permalink / raw)
  To: linuxppc-dev

This patch hooks into the ras EPOW interrupt handler so that we can
communicate hotplug rtas events to a PowerKVM guest from qemu.

The ras epow interrupt wil lnow check for hotplgu rtas events and
invoke the common handling routine accordingly.
---
 arch/powerpc/include/asm/rtas.h          |  1 +
 arch/powerpc/platforms/pseries/dlpar.c   |  2 +-
 arch/powerpc/platforms/pseries/pseries.h |  1 +
 arch/powerpc/platforms/pseries/ras.c     | 12 +++++++++++-
 4 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 26491ae..7313e6f 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -124,6 +124,7 @@ struct rtas_suspend_me_data {
 #define RTAS_TYPE_INFO			0xE2
 #define RTAS_TYPE_DEALLOC		0xE3
 #define RTAS_TYPE_DUMP			0xE4
+#define RTAS_TYPE_HOTPLUG		0xE5
 /* I don't add PowerMGM events right now, this is a different topic */ 
 #define RTAS_TYPE_PMGM_POWER_SW_ON	0x60
 #define RTAS_TYPE_PMGM_POWER_SW_OFF	0x61
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 53f4fe6..6d3de6e 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -360,7 +360,7 @@ int dlpar_release_drc(u32 drc_index)
 	return 0;
 }
 
-static int handle_dlpar_errorlog(struct rtas_error_log *error_log)
+int handle_dlpar_errorlog(struct rtas_error_log *error_log)
 {
 	struct pseries_errorlog *pseries_log;
 	struct pseries_hp_elog *hp_elog;
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 1706215..9b9bd82 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -64,6 +64,7 @@ extern int dlpar_acquire_drc(u32);
 extern int dlpar_release_drc(u32);
 extern int dlpar_memory(struct pseries_hp_elog *);
 extern int dlpar_cpus(struct pseries_hp_elog *);
+extern int handle_dlpar_errorlog(struct rtas_error_log *);
 
 /* PCI root bridge prepare function override for pseries */
 struct pci_host_bridge;
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 9c5778e..3cc6a49 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -183,6 +183,7 @@ void rtas_parse_epow_errlog(struct rtas_error_log *log)
 /* Handle environmental and power warning (EPOW) interrupts. */
 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 {
+	struct rtas_error_log *elog;
 	int status;
 	int state;
 	int critical;
@@ -205,7 +206,16 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 
 	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
 
-	rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf);
+	elog = (struct rtas_error_log *)ras_log_buf;
+
+	switch(rtas_error_type(elog)) {
+	case RTAS_TYPE_EPOW:
+		rtas_parse_epow_errlog(elog);
+		break;
+	case RTAS_TYPE_HOTPLUG:
+		handle_dlpar_errorlog(elog);
+		break;
+	}
 
 	spin_unlock(&ras_log_buf_lock);
 	return IRQ_HANDLED;
-- 
2.0.0.rc3.2.g998f840

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-06-17 15:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-17 15:42 [RFC PATCH 0/4] Update hotplug for pseries systems Nathan Fontenot
2014-06-17 15:45 ` [RFC PATCH 1/4] Create interface for rtas hotplug events and move mem hotplug to the kernel Nathan Fontenot
2014-06-17 15:46 ` [RFC PATCH 2/4] Migrate cpu hotplug code to pseries/hotplug-cpu.c Nathan Fontenot
2014-06-17 15:46 ` [RFC PATCH 3/4] Handle cpu hotplug from rtas hotplug events Nathan Fontenot
2014-06-17 15:47 ` [RFC PATCH 4/4] Hook into ras epow interrupt handler for hotplug Nathan Fontenot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).