From: Nathan Fontenot <nfont@linux.vnet.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Subject: [RFC PATCH 3/4] Handle cpu hotplug from rtas hotplug events
Date: Tue, 17 Jun 2014 10:46:52 -0500 [thread overview]
Message-ID: <53A062EC.3040000@linux.vnet.ibm.com> (raw)
In-Reply-To: <53A061EC.10403@linux.vnet.ibm.com>
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
next prev parent reply other threads:[~2014-06-17 15:47 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2014-06-17 15:47 ` [RFC PATCH 4/4] Hook into ras epow interrupt handler for hotplug Nathan Fontenot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53A062EC.3040000@linux.vnet.ibm.com \
--to=nfont@linux.vnet.ibm.com \
--cc=linuxppc-dev@lists.ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).