|
@@ -436,6 +436,18 @@ int dlpar_release_drc(u32 drc_index)
|
|
|
|
|
|
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
|
|
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
|
|
|
|
|
|
|
|
+static DEFINE_MUTEX(pseries_cpu_hotplug_mutex);
|
|
|
|
+
|
|
|
|
+void cpu_hotplug_driver_lock()
|
|
|
|
+{
|
|
|
|
+ mutex_lock(&pseries_cpu_hotplug_mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void cpu_hotplug_driver_unlock()
|
|
|
|
+{
|
|
|
|
+ mutex_unlock(&pseries_cpu_hotplug_mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
|
static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
|
{
|
|
{
|
|
struct device_node *dn;
|
|
struct device_node *dn;
|
|
@@ -443,13 +455,18 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
|
char *cpu_name;
|
|
char *cpu_name;
|
|
int rc;
|
|
int rc;
|
|
|
|
|
|
|
|
+ cpu_hotplug_driver_lock();
|
|
rc = strict_strtoul(buf, 0, &drc_index);
|
|
rc = strict_strtoul(buf, 0, &drc_index);
|
|
- if (rc)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ if (rc) {
|
|
|
|
+ rc = -EINVAL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
dn = dlpar_configure_connector(drc_index);
|
|
dn = dlpar_configure_connector(drc_index);
|
|
- if (!dn)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ if (!dn) {
|
|
|
|
+ rc = -EINVAL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
/* configure-connector reports cpus as living in the base
|
|
/* configure-connector reports cpus as living in the base
|
|
* directory of the device tree. CPUs actually live in the
|
|
* directory of the device tree. CPUs actually live in the
|
|
@@ -459,7 +476,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
|
GFP_KERNEL);
|
|
GFP_KERNEL);
|
|
if (!cpu_name) {
|
|
if (!cpu_name) {
|
|
dlpar_free_cc_nodes(dn);
|
|
dlpar_free_cc_nodes(dn);
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ rc = -ENOMEM;
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
sprintf(cpu_name, "/cpus%s", dn->full_name);
|
|
sprintf(cpu_name, "/cpus%s", dn->full_name);
|
|
@@ -469,7 +487,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
|
rc = dlpar_acquire_drc(drc_index);
|
|
rc = dlpar_acquire_drc(drc_index);
|
|
if (rc) {
|
|
if (rc) {
|
|
dlpar_free_cc_nodes(dn);
|
|
dlpar_free_cc_nodes(dn);
|
|
- return -EINVAL;
|
|
|
|
|
|
+ rc = -EINVAL;
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
rc = dlpar_attach_node(dn);
|
|
rc = dlpar_attach_node(dn);
|
|
@@ -479,6 +498,8 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
|
}
|
|
}
|
|
|
|
|
|
rc = online_node_cpus(dn);
|
|
rc = online_node_cpus(dn);
|
|
|
|
+out:
|
|
|
|
+ cpu_hotplug_driver_unlock();
|
|
|
|
|
|
return rc ? rc : count;
|
|
return rc ? rc : count;
|
|
}
|
|
}
|
|
@@ -499,26 +520,30 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ cpu_hotplug_driver_lock();
|
|
rc = offline_node_cpus(dn);
|
|
rc = offline_node_cpus(dn);
|
|
if (rc) {
|
|
if (rc) {
|
|
of_node_put(dn);
|
|
of_node_put(dn);
|
|
- return -EINVAL;
|
|
|
|
|
|
+ rc = -EINVAL;
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
rc = dlpar_release_drc(*drc_index);
|
|
rc = dlpar_release_drc(*drc_index);
|
|
if (rc) {
|
|
if (rc) {
|
|
of_node_put(dn);
|
|
of_node_put(dn);
|
|
- return -EINVAL;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
rc = dlpar_detach_node(dn);
|
|
rc = dlpar_detach_node(dn);
|
|
if (rc) {
|
|
if (rc) {
|
|
dlpar_acquire_drc(*drc_index);
|
|
dlpar_acquire_drc(*drc_index);
|
|
- return rc;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
of_node_put(dn);
|
|
of_node_put(dn);
|
|
- return count;
|
|
|
|
|
|
+out:
|
|
|
|
+ cpu_hotplug_driver_unlock();
|
|
|
|
+ return rc ? rc : count;
|
|
}
|
|
}
|
|
|
|
|
|
static int __init pseries_dlpar_init(void)
|
|
static int __init pseries_dlpar_init(void)
|