* [PATCH 1/2] powerpc/pseries/dlpar: Remove device tree node for DLPAR IO remove
@ 2024-08-13 21:50 Haren Myneni
0 siblings, 0 replies; 3+ messages in thread
From: Haren Myneni @ 2024-08-13 21:50 UTC (permalink / raw)
To: linuxppc-dev
Cc: mpe, npiggin, tyreld, brking, hbabu, Haren Myneni, Scott Cheloha
For the DLPAR IO REMOVE, the corresponding device tree nodes and
properties have to be removed from the device tree after disable
the device. In the current implementation, the user space (drmgr
tool) remove the device tree nodes by updating /proc/ppc64/ofdt
which needs /dev/mem. But /dev/mem access is restricted under
system lockdown is enabled.
This patch extends the /sys/kernel/dlpar interface and provides
‘dt remove index <drc_index>’ to the user space so that drmgr
tool can remove the corresponding device tree nodes based on DRC
index from the device tree.
Signed-off-by: Scott Cheloha <cheloha@linux.ibm.com>
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
arch/powerpc/include/asm/rtas.h | 1 +
arch/powerpc/platforms/pseries/dlpar.c | 87 +++++++++++++++++++++++++-
2 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 065ffd1b2f8a..04406162fc5a 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -397,6 +397,7 @@ inline uint16_t pseries_errorlog_length(struct pseries_errorlog *sect)
#define PSERIES_HP_ELOG_RESOURCE_SLOT 3
#define PSERIES_HP_ELOG_RESOURCE_PHB 4
#define PSERIES_HP_ELOG_RESOURCE_PMEM 6
+#define PSERIES_HP_ELOG_RESOURCE_DT 7
#define PSERIES_HP_ELOG_ACTION_ADD 1
#define PSERIES_HP_ELOG_ACTION_REMOVE 2
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 47f8eabd1bee..993fd3e8f6ea 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -330,6 +330,86 @@ int dlpar_unisolate_drc(u32 drc_index)
return 0;
}
+static int changeset_detach_node_recursive(struct of_changeset *ocs,
+ struct device_node *node)
+{
+ struct device_node *child;
+ int rc;
+
+ for_each_child_of_node(node, child) {
+ rc = changeset_detach_node_recursive(ocs, child);
+ if (rc) {
+ of_node_put(child);
+ return rc;
+ }
+ }
+
+ pr_info("%s: %pOF\n", __func__, node);
+ return of_changeset_detach_node(ocs, node);
+}
+
+static int dlpar_hp_dt_remove(u32 drc_index)
+{
+ struct device_node *np;
+ struct of_changeset ocs;
+ u32 index;
+ int rc = 0;
+
+ /*
+ * Prune all nodes with a matching index.
+ * TODO Search for sub-nodes that haven't been properly detached yet.
+ */
+ of_changeset_init(&ocs);
+
+ for_each_node_with_property(np, "ibm,my-drc-index") {
+ rc = of_property_read_u32(np, "ibm,my-drc-index", &index);
+ if (rc) {
+ pr_err("%s: %pOF: of_property_read_u32 %s: %d\n",
+ __func__, np, "ibm,my-drc-index", rc);
+ of_node_put(np);
+ goto out;
+ }
+
+ if (index == drc_index) {
+ rc = changeset_detach_node_recursive(&ocs, np);
+ if (rc) {
+ of_node_put(np);
+ goto out;
+ }
+ }
+ }
+
+ rc = of_changeset_apply(&ocs);
+
+out:
+ of_changeset_destroy(&ocs);
+ return rc;
+}
+
+static int dlpar_hp_dt(struct pseries_hp_errorlog *phpe)
+{
+ int rc;
+
+ if (phpe->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX)
+ return -EINVAL;
+
+ lock_device_hotplug();
+
+ switch (phpe->action) {
+ case PSERIES_HP_ELOG_ACTION_REMOVE:
+ rc = dlpar_hp_dt_remove(phpe->_drc_u.drc_index);
+ break;
+ default:
+ pr_err("Invalid action (%d) specified\n", phpe->action);
+ rc = -EINVAL;
+ break;
+ }
+
+ unlock_device_hotplug();
+
+ return rc;
+}
+
int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
{
int rc;
@@ -361,6 +441,9 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
case PSERIES_HP_ELOG_RESOURCE_PMEM:
rc = dlpar_hp_pmem(hp_elog);
break;
+ case PSERIES_HP_ELOG_RESOURCE_DT:
+ rc = dlpar_hp_dt(hp_elog);
+ break;
default:
pr_warn_ratelimited("Invalid resource (%d) specified\n",
@@ -413,6 +496,8 @@ static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog)
hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
} else if (sysfs_streq(arg, "cpu")) {
hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
+ } else if (sysfs_streq(arg, "dt")) {
+ hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_DT;
} else {
pr_err("Invalid resource specified.\n");
return -EINVAL;
@@ -554,7 +639,7 @@ static ssize_t dlpar_store(const struct class *class, const struct class_attribu
static ssize_t dlpar_show(const struct class *class, const struct class_attribute *attr,
char *buf)
{
- return sprintf(buf, "%s\n", "memory,cpu");
+ return sprintf(buf, "%s\n", "memory,cpu,dt");
}
static CLASS_ATTR_RW(dlpar);
--
2.43.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 1/2] powerpc/pseries/dlpar: Remove device tree node for DLPAR IO remove
@ 2024-08-14 2:49 Haren Myneni
2024-08-14 2:49 ` [PATCH 2/2] powerpc/pseries/dlpar: Add device tree nodes for DLPAR IO add Haren Myneni
0 siblings, 1 reply; 3+ messages in thread
From: Haren Myneni @ 2024-08-14 2:49 UTC (permalink / raw)
To: linuxppc-dev; +Cc: hbabu, Haren Myneni
For the DLPAR IO REMOVE, the corresponding device tree nodes and
properties have to be removed from the device tree after disable
the device. In the current implementation, the user space (drmgr
tool) remove the device tree nodes by updating /proc/ppc64/ofdt
which needs /dev/mem. But /dev/mem access is restricted under
system lockdown is enabled.
This patch extends the /sys/kernel/dlpar interface and provides
‘dt remove index <drc_index>’ to the user space so that drmgr
tool can remove the corresponding device tree nodes based on DRC
index from the device tree.
Signed-off-by: Scott Cheloha <cheloha@linux.ibm.com>
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
arch/powerpc/include/asm/rtas.h | 1 +
arch/powerpc/platforms/pseries/dlpar.c | 87 +++++++++++++++++++++++++-
2 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 065ffd1b2f8a..04406162fc5a 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -397,6 +397,7 @@ inline uint16_t pseries_errorlog_length(struct pseries_errorlog *sect)
#define PSERIES_HP_ELOG_RESOURCE_SLOT 3
#define PSERIES_HP_ELOG_RESOURCE_PHB 4
#define PSERIES_HP_ELOG_RESOURCE_PMEM 6
+#define PSERIES_HP_ELOG_RESOURCE_DT 7
#define PSERIES_HP_ELOG_ACTION_ADD 1
#define PSERIES_HP_ELOG_ACTION_REMOVE 2
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 47f8eabd1bee..993fd3e8f6ea 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -330,6 +330,86 @@ int dlpar_unisolate_drc(u32 drc_index)
return 0;
}
+static int changeset_detach_node_recursive(struct of_changeset *ocs,
+ struct device_node *node)
+{
+ struct device_node *child;
+ int rc;
+
+ for_each_child_of_node(node, child) {
+ rc = changeset_detach_node_recursive(ocs, child);
+ if (rc) {
+ of_node_put(child);
+ return rc;
+ }
+ }
+
+ pr_info("%s: %pOF\n", __func__, node);
+ return of_changeset_detach_node(ocs, node);
+}
+
+static int dlpar_hp_dt_remove(u32 drc_index)
+{
+ struct device_node *np;
+ struct of_changeset ocs;
+ u32 index;
+ int rc = 0;
+
+ /*
+ * Prune all nodes with a matching index.
+ * TODO Search for sub-nodes that haven't been properly detached yet.
+ */
+ of_changeset_init(&ocs);
+
+ for_each_node_with_property(np, "ibm,my-drc-index") {
+ rc = of_property_read_u32(np, "ibm,my-drc-index", &index);
+ if (rc) {
+ pr_err("%s: %pOF: of_property_read_u32 %s: %d\n",
+ __func__, np, "ibm,my-drc-index", rc);
+ of_node_put(np);
+ goto out;
+ }
+
+ if (index == drc_index) {
+ rc = changeset_detach_node_recursive(&ocs, np);
+ if (rc) {
+ of_node_put(np);
+ goto out;
+ }
+ }
+ }
+
+ rc = of_changeset_apply(&ocs);
+
+out:
+ of_changeset_destroy(&ocs);
+ return rc;
+}
+
+static int dlpar_hp_dt(struct pseries_hp_errorlog *phpe)
+{
+ int rc;
+
+ if (phpe->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX)
+ return -EINVAL;
+
+ lock_device_hotplug();
+
+ switch (phpe->action) {
+ case PSERIES_HP_ELOG_ACTION_REMOVE:
+ rc = dlpar_hp_dt_remove(phpe->_drc_u.drc_index);
+ break;
+ default:
+ pr_err("Invalid action (%d) specified\n", phpe->action);
+ rc = -EINVAL;
+ break;
+ }
+
+ unlock_device_hotplug();
+
+ return rc;
+}
+
int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
{
int rc;
@@ -361,6 +441,9 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
case PSERIES_HP_ELOG_RESOURCE_PMEM:
rc = dlpar_hp_pmem(hp_elog);
break;
+ case PSERIES_HP_ELOG_RESOURCE_DT:
+ rc = dlpar_hp_dt(hp_elog);
+ break;
default:
pr_warn_ratelimited("Invalid resource (%d) specified\n",
@@ -413,6 +496,8 @@ static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog)
hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
} else if (sysfs_streq(arg, "cpu")) {
hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
+ } else if (sysfs_streq(arg, "dt")) {
+ hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_DT;
} else {
pr_err("Invalid resource specified.\n");
return -EINVAL;
@@ -554,7 +639,7 @@ static ssize_t dlpar_store(const struct class *class, const struct class_attribu
static ssize_t dlpar_show(const struct class *class, const struct class_attribute *attr,
char *buf)
{
- return sprintf(buf, "%s\n", "memory,cpu");
+ return sprintf(buf, "%s\n", "memory,cpu,dt");
}
static CLASS_ATTR_RW(dlpar);
--
2.43.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] powerpc/pseries/dlpar: Add device tree nodes for DLPAR IO add
2024-08-14 2:49 [PATCH 1/2] powerpc/pseries/dlpar: Remove device tree node for DLPAR IO remove Haren Myneni
@ 2024-08-14 2:49 ` Haren Myneni
0 siblings, 0 replies; 3+ messages in thread
From: Haren Myneni @ 2024-08-14 2:49 UTC (permalink / raw)
To: linuxppc-dev; +Cc: hbabu, Haren Myneni
For the DLPAR IO ADD, the corresponding device tree nodes and
properties will be added to the device tree after enable the
device. The user space (drmgr tool) uses configure_connector
RTAS call with the DRC index to retrieve the corresponding
device nodes but this RTAS call needs /dev/mem access. Also
updates the device tree by writing to /proc/ppc64/ofdt.
Under system lockdown, /dev/mem access is restricted which means
the user space can not issue configure_connector RTAS call and
also can not access to /proc/ppc64/ofdt.
This patch extends the /sys/kernel/dlpar interface and provides
‘dt add index <drc_index>’ to the user space. The drmgr tool uses
this interface to update the device tree whenever the device is
added. This interface retrieves device tree nodes for the
corresponding DRC index using configure_connector RTAS call and
adds new device nodes / properties to the device tree.
Signed-off-by: Scott Cheloha <cheloha@linux.ibm.com>
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
---
arch/powerpc/platforms/pseries/dlpar.c | 134 +++++++++++++++++++++++++
1 file changed, 134 insertions(+)
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 993fd3e8f6ea..fb34d5859da8 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -23,6 +23,7 @@
#include <linux/uaccess.h>
#include <asm/rtas.h>
#include <asm/rtas-work-area.h>
+#include <asm/prom.h>
static struct workqueue_struct *pseries_hp_wq;
@@ -264,6 +265,22 @@ int dlpar_detach_node(struct device_node *dn)
return 0;
}
+static int dlpar_changeset_attach_cc_nodes(struct of_changeset *ocs,
+ struct device_node *dn)
+{
+ int rc;
+
+ pr_info("%s: %pOF\n", __func__, dn);
+
+ rc = of_changeset_attach_node(ocs, dn);
+
+ if (!rc && dn->child)
+ rc = dlpar_changeset_attach_cc_nodes(ocs, dn->child);
+ if (!rc && dn->sibling)
+ rc = dlpar_changeset_attach_cc_nodes(ocs, dn->sibling);
+
+ return rc;
+}
#define DR_ENTITY_SENSE 9003
#define DR_ENTITY_PRESENT 1
@@ -330,6 +347,120 @@ int dlpar_unisolate_drc(u32 drc_index)
return 0;
}
+static struct device_node *
+get_device_node_with_drc_index(u32 index)
+{
+ struct device_node *np = NULL;
+ u32 node_index;
+ int rc;
+
+ for_each_node_with_property(np, "ibm,my-drc-index") {
+ rc = of_property_read_u32(np, "ibm,my-drc-index",
+ &node_index);
+ if (rc) {
+ pr_err("%s: %pOF: of_property_read_u32 %s: %d\n",
+ __func__, np, "ibm,my-drc-index", rc);
+ of_node_put(np);
+ return NULL;
+ }
+
+ if (index == node_index)
+ break;
+ }
+
+ return np;
+}
+
+static struct device_node *
+get_device_node_with_drc_info(u32 index)
+{
+ struct device_node *np = NULL;
+ struct of_drc_info drc;
+ struct property *info;
+ const __be32 *value;
+ u32 node_index;
+ int i, j, count;
+
+ for_each_node_with_property(np, "ibm,drc-info") {
+ info = of_find_property(np, "ibm,drc-info", NULL);
+ if (info == NULL) {
+ /* XXX can this happen? */
+ of_node_put(np);
+ return NULL;
+ }
+ value = of_prop_next_u32(info, NULL, &count);
+ if (value == NULL)
+ continue;
+ value++;
+ for (i = 0; i < count; i++) {
+ if (of_read_drc_info_cell(&info, &value, &drc))
+ break;
+ if (index > drc.last_drc_index)
+ continue;
+ node_index = drc.drc_index_start;
+ for (j = 0; j < drc.num_sequential_elems; j++) {
+ if (index == node_index)
+ return np;
+ node_index += drc.sequential_inc;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int dlpar_hp_dt_add(u32 index)
+{
+ struct device_node *np, *nodes;
+ struct of_changeset ocs;
+ int rc;
+
+ /*
+ * Do not add device node(s) if already exists in the
+ * device tree.
+ */
+ np = get_device_node_with_drc_index(index);
+ if (np) {
+ pr_err("%s: Adding device node for index (%d), but "
+ "already exists in the device tree\n",
+ __func__, index);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ np = get_device_node_with_drc_info(index);
+
+ if (!np)
+ return -EIO;
+
+ pr_info("%s: %pOF\n", __func__, np);
+
+ /* Next, configure the connector. */
+ nodes = dlpar_configure_connector(cpu_to_be32(index), np);
+ if (!nodes) {
+ rc = -EIO;
+ goto out;
+ }
+
+ /*
+ * Add the new nodes from dlpar_configure_connector() onto
+ * the device-tree.
+ */
+ of_changeset_init(&ocs);
+ rc = dlpar_changeset_attach_cc_nodes(&ocs, nodes);
+
+ if (!rc)
+ rc = of_changeset_apply(&ocs);
+ else
+ dlpar_free_cc_nodes(nodes);
+
+ of_changeset_destroy(&ocs);
+
+out:
+ of_node_put(np);
+ return rc;
+}
+
static int changeset_detach_node_recursive(struct of_changeset *ocs,
struct device_node *node)
{
@@ -396,6 +527,9 @@ static int dlpar_hp_dt(struct pseries_hp_errorlog *phpe)
lock_device_hotplug();
switch (phpe->action) {
+ case PSERIES_HP_ELOG_ACTION_ADD:
+ rc = dlpar_hp_dt_add(phpe->_drc_u.drc_index);
+ break;
case PSERIES_HP_ELOG_ACTION_REMOVE:
rc = dlpar_hp_dt_remove(phpe->_drc_u.drc_index);
break;
--
2.43.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-08-14 2:50 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-14 2:49 [PATCH 1/2] powerpc/pseries/dlpar: Remove device tree node for DLPAR IO remove Haren Myneni
2024-08-14 2:49 ` [PATCH 2/2] powerpc/pseries/dlpar: Add device tree nodes for DLPAR IO add Haren Myneni
-- strict thread matches above, loose matches on Subject: below --
2024-08-13 21:50 [PATCH 1/2] powerpc/pseries/dlpar: Remove device tree node for DLPAR IO remove Haren Myneni
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).