* [RFC PATCH 3/5] ACPI: property: Add device graph support
2026-09-29 8:55 [RFC PATCH 0/5] hwtracing: rvtrace: Add ACPI support Sunil V L
2026-09-29 8:55 ` [RFC PATCH 1/5] of: property: Add in-ports/out-ports support to of_fwnode_graph_get_port_parent() Sunil V L
2026-09-29 8:55 ` [RFC PATCH 2/5] ACPI: property: Add ports/in-ports/out-ports support to acpi_fwnode_get_parent() Sunil V L
@ 2026-09-29 8:55 ` Sunil V L
2026-09-29 8:55 ` [RFC PATCH 4/5] hwtracing: rvtrace: Move to fwnode_* APIs Sunil V L
2026-09-29 8:55 ` [RFC PATCH 5/5] hwtracing: rvtrace: Add ACPI support Sunil V L
4 siblings, 0 replies; 6+ messages in thread
From: Sunil V L @ 2026-09-29 8:55 UTC (permalink / raw)
To: linux-acpi, linux-riscv, linux-kernel, devicetree
Cc: Rafael J . Wysocki, Len Brown, Mayuresh Chitale, Anup Patel,
Alexander Shishkin, Rob Herring, Saravana Kannan, Sunil V L
From: Sunil V L <sunilvl@oss.qualcomm.com>
Add support for parsing the UEFI DSD-Guide device-graph UUID
(ab02a46b-74c7-45a2-bd68-f7d344ef2153), allowing firmware to describe
device topology graphs similar to devicetree's of_graph bindings.
Synthetic "port" and "endpoint" data nodes are created from
the graph package contents, with "reg"/"port"/"endpoint" integer
properties and a "remote-endpoint" reference property, so that the
existing fwnode graph API (fwnode_graph_parse_endpoint(),
fwnode_graph_get_remote_endpoint(), etc.) can walk the resulting nodes
the same way it walks devicetree graph nodes.
For certain device graph UUIDs, such as the RISC-V Trace ACPI Graph
UUID, nest the synthesized port nodes one level deeper under a synthetic
"in-ports" or "out-ports" node.
Signed-off-by: Sunil V L <sunilvl@oss.qualcomm.com>
---
drivers/acpi/property.c | 500 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 490 insertions(+), 10 deletions(-)
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 78400620390b..49af8eaf79e5 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -68,6 +68,7 @@ static const guid_t buffer_prop_guid =
GUID_INIT(0xedb12dd0, 0x363d, 0x4085,
0xa3, 0xd2, 0x49, 0x52, 0x2c, 0xa1, 0x60, 0xc4);
+static void acpi_free_device_properties(struct list_head *list);
static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
union acpi_object *desc,
struct acpi_device_data *data,
@@ -76,6 +77,18 @@ static bool acpi_extract_properties(acpi_handle handle,
union acpi_object *desc,
struct acpi_device_data *data);
+/* ACPI _DSD device graph GUID [1]: ab02a46b-74c7-45a2-bd68-f7d344ef2153 */
+static const guid_t graph_prop_guid =
+ GUID_INIT(0xab02a46b, 0x74c7, 0x45a2,
+ 0xbd, 0x68, 0xf7, 0xd3, 0x44, 0xef, 0x21, 0x53);
+/* RISC-V Trace ACPI Graph UUID: 42e66f8f-50fe-4eed-9897-cdeed26ecd77 */
+static const guid_t rvtrace_graph_guid =
+ GUID_INIT(0x42e66f8f, 0x50fe, 0x4eed,
+ 0x98, 0x97, 0xcd, 0xee, 0xd2, 0x6e, 0xcd, 0x77);
+
+#define ACPI_GRAPH_LINK_INPUT 0
+#define ACPI_GRAPH_LINK_OUTPUT 1
+
static bool acpi_nondev_subnode_extract(union acpi_object *desc,
acpi_handle handle,
const union acpi_object *link,
@@ -254,14 +267,423 @@ static bool acpi_add_nondev_subnodes(acpi_handle scope,
return ret;
}
+static struct acpi_data_node *
+acpi_data_node_create(const char *name, acpi_handle scope,
+ struct fwnode_handle *parent, struct list_head *list)
+{
+ struct acpi_data_node *dn;
+ union acpi_object *marker;
+
+ /*
+ * Synthetic nodes have no backing _DSD-equivalent package of their
+ * own, but data->pointer is used elsewhere as an indication that a
+ * node's data is valid, so give it a dummy non-NULL object to own
+ * and free, the same way acpi_nondev_subnode_extract() and
+ * acpi_extract_apple_properties() do for their allocated buffers.
+ */
+ marker = ACPI_ALLOCATE_ZEROED(sizeof(*marker));
+ if (!marker)
+ return NULL;
+
+ dn = kzalloc_obj(*dn);
+ if (!dn) {
+ ACPI_FREE(marker);
+ return NULL;
+ }
+
+ dn->name = kstrdup(name, GFP_KERNEL);
+ if (!dn->name) {
+ ACPI_FREE(marker);
+ kfree(dn);
+ return NULL;
+ }
+ dn->handle = scope;
+ dn->parent = parent;
+ dn->data.pointer = marker;
+ fwnode_init(&dn->fwnode, &acpi_data_fwnode_ops);
+ INIT_LIST_HEAD(&dn->data.properties);
+ INIT_LIST_HEAD(&dn->data.subnodes);
+ list_add_tail(&dn->sibling, list);
+
+ return dn;
+}
+
+static void acpi_data_node_delete(struct acpi_data_node *dn)
+{
+ list_del(&dn->sibling);
+ acpi_free_device_properties(&dn->data.properties);
+ ACPI_FREE((void *)dn->data.pointer);
+ kfree(dn->name);
+ kfree(dn);
+}
+
+static struct acpi_data_node *
+acpi_graph_node_create(const char *type, u32 id, acpi_handle scope,
+ struct fwnode_handle *parent,
+ struct list_head *list)
+{
+ struct acpi_data_node *dn;
+ char *name;
+
+ name = kasprintf(GFP_KERNEL, "%s@%u", type, id);
+ if (!name)
+ return NULL;
+
+ dn = acpi_data_node_create(name, scope, parent, list);
+ kfree(name);
+ return dn;
+}
+
+static bool acpi_data_prop_add_integer(struct acpi_device_data *data,
+ const char *name, u64 value)
+{
+ struct acpi_device_properties *props;
+ union acpi_object *obj;
+
+ props = kzalloc(sizeof(*props) + 4 * sizeof(*obj), GFP_KERNEL);
+ if (!props)
+ return false;
+
+ INIT_LIST_HEAD(&props->list);
+ props->guid = &prp_guids[0];
+
+ obj = (union acpi_object *)(props + 1);
+ props->properties = &obj[0];
+ obj[0].type = ACPI_TYPE_PACKAGE;
+ obj[0].package.count = 1;
+ obj[0].package.elements = &obj[1];
+
+ obj[1].type = ACPI_TYPE_PACKAGE;
+ obj[1].package.count = 2;
+ obj[1].package.elements = &obj[2];
+
+ obj[2].type = ACPI_TYPE_STRING;
+ obj[2].string.pointer = (char *)name;
+ obj[2].string.length = strlen(name);
+
+ obj[3].type = ACPI_TYPE_INTEGER;
+ obj[3].integer.value = value;
+
+ list_add_tail(&props->list, &data->properties);
+
+ return true;
+}
+
+static bool acpi_data_prop_add_remote_endpoint(struct acpi_device_data *data,
+ const union acpi_object *remote,
+ u32 port, u32 endpoint)
+{
+ struct acpi_device_properties *props;
+ union acpi_object *obj;
+
+ if (remote->type != ACPI_TYPE_LOCAL_REFERENCE &&
+ remote->type != ACPI_TYPE_STRING)
+ return false;
+
+ props = kzalloc(sizeof(*props) + 7 * sizeof(*obj), GFP_KERNEL);
+ if (!props)
+ return false;
+
+ INIT_LIST_HEAD(&props->list);
+ props->guid = &prp_guids[0];
+
+ obj = (union acpi_object *)(props + 1);
+ props->properties = &obj[0];
+ obj[0].type = ACPI_TYPE_PACKAGE;
+ obj[0].package.count = 1;
+ obj[0].package.elements = &obj[1];
+
+ obj[1].type = ACPI_TYPE_PACKAGE;
+ obj[1].package.count = 2;
+ obj[1].package.elements = &obj[2];
+
+ obj[2].type = ACPI_TYPE_STRING;
+ obj[2].string.pointer = "remote-endpoint";
+ obj[2].string.length = strlen("remote-endpoint");
+
+ obj[3].type = ACPI_TYPE_PACKAGE;
+ obj[3].package.count = 3;
+ obj[3].package.elements = &obj[4];
+
+ obj[4] = *remote;
+
+ obj[5].type = ACPI_TYPE_INTEGER;
+ obj[5].integer.value = port;
+
+ obj[6].type = ACPI_TYPE_INTEGER;
+ obj[6].integer.value = endpoint;
+
+ list_add_tail(&props->list, &data->properties);
+
+ return true;
+}
+
+struct acpi_graph_port_map {
+ struct list_head node;
+ struct acpi_data_node *port;
+ struct fwnode_handle *parent;
+ u32 port_nr;
+ u32 endpoint_id;
+};
+
+struct acpi_graph_root_map {
+ struct list_head node;
+ struct acpi_data_node *root;
+};
+
+static bool acpi_graph_is_directional(const guid_t *graph_guid)
+{
+ return guid_equal(graph_guid, &rvtrace_graph_guid);
+}
+
+static struct acpi_data_node *
+acpi_graph_get_root_node(struct list_head *roots, acpi_handle scope,
+ struct fwnode_handle *parent, struct list_head *subnodes,
+ const char *name)
+{
+ struct acpi_graph_root_map *entry;
+
+ list_for_each_entry(entry, roots, node) {
+ if (!strcmp(entry->root->name, name))
+ return entry->root;
+ }
+
+ entry = kzalloc_obj(*entry);
+ if (!entry)
+ return NULL;
+
+ entry->root = acpi_data_node_create(name, scope, parent, subnodes);
+ if (!entry->root) {
+ kfree(entry);
+ return NULL;
+ }
+
+ list_add_tail(&entry->node, roots);
+ return entry->root;
+}
+
+static struct acpi_graph_port_map *
+acpi_graph_get_port_map(struct list_head *ports, acpi_handle scope,
+ struct fwnode_handle *parent, struct list_head *subnodes,
+ u32 port_nr)
+{
+ struct acpi_graph_port_map *entry;
+
+ list_for_each_entry(entry, ports, node) {
+ if (entry->parent == parent && entry->port_nr == port_nr)
+ return entry;
+ }
+
+ entry = kzalloc_obj(*entry);
+ if (!entry)
+ return NULL;
+
+ entry->port = acpi_graph_node_create("port", port_nr, scope, parent,
+ subnodes);
+ if (!entry->port)
+ goto err_free_entry;
+
+ entry->parent = parent;
+ entry->port_nr = port_nr;
+ if (!acpi_data_prop_add_integer(&entry->port->data, "reg", port_nr) ||
+ !acpi_data_prop_add_integer(&entry->port->data, "port", port_nr))
+ goto err_drop_port;
+
+ list_add_tail(&entry->node, ports);
+
+ return entry;
+
+err_drop_port:
+ acpi_data_node_delete(entry->port);
+err_free_entry:
+ kfree(entry);
+ return NULL;
+}
+
+static bool acpi_dsd_graph_valid(union acpi_object *graph)
+{
+ u64 nr_graphs;
+ u64 i;
+
+ if (graph->type != ACPI_TYPE_PACKAGE)
+ return false;
+
+ if (graph->package.count < 2)
+ return false;
+
+ if (graph->package.elements[0].type != ACPI_TYPE_INTEGER ||
+ graph->package.elements[1].type != ACPI_TYPE_INTEGER)
+ return false;
+
+ if (graph->package.elements[0].integer.value != 0)
+ return false;
+
+ nr_graphs = graph->package.elements[1].integer.value;
+ if (nr_graphs > graph->package.count - 2)
+ return false;
+
+ for (i = 0; i < nr_graphs; i++) {
+ union acpi_object *graph_entry;
+ u64 nr_links;
+
+ graph_entry = &graph->package.elements[i + 2];
+ if (graph_entry->type != ACPI_TYPE_PACKAGE ||
+ graph_entry->package.count < 3)
+ return false;
+
+ if (graph_entry->package.elements[0].type != ACPI_TYPE_INTEGER ||
+ graph_entry->package.elements[1].type != ACPI_TYPE_BUFFER ||
+ graph_entry->package.elements[1].buffer.length != 16 ||
+ graph_entry->package.elements[2].type != ACPI_TYPE_INTEGER)
+ return false;
+
+ nr_links = graph_entry->package.elements[2].integer.value;
+ if (nr_links > graph_entry->package.count - 3)
+ return false;
+ }
+
+ return true;
+}
+
+static bool acpi_add_graph_subnodes(acpi_handle scope, union acpi_object *graph,
+ struct acpi_device_data *data,
+ struct fwnode_handle *parent)
+{
+ LIST_HEAD(ports);
+ LIST_HEAD(roots);
+ u64 nr_graphs;
+ bool ret = false;
+ u64 i;
+
+ if (!acpi_dsd_graph_valid(graph))
+ return false;
+
+ nr_graphs = graph->package.elements[1].integer.value;
+
+ for (i = 0; i < nr_graphs; i++) {
+ union acpi_object *graph_entry;
+ struct fwnode_handle *graph_parent = parent;
+ struct list_head *graph_subnodes = &data->subnodes;
+ struct acpi_data_node *graph_root;
+ const guid_t *graph_guid;
+ u64 nr_links;
+ u64 j;
+
+ graph_entry = &graph->package.elements[i + 2];
+ graph_guid = (const guid_t *)graph_entry->package.elements[1].buffer.pointer;
+ if (!acpi_graph_is_directional(graph_guid))
+ continue;
+ nr_links = graph_entry->package.elements[2].integer.value;
+
+ for (j = 0; j < nr_links; j++) {
+ union acpi_object *link;
+ struct acpi_graph_port_map *port_map;
+ struct acpi_data_node *endpoint;
+ union acpi_object *elem;
+ u32 src_port, dst_port, ep_id;
+ u64 dir;
+
+ link = &graph_entry->package.elements[j + 3];
+ if (link->type != ACPI_TYPE_PACKAGE ||
+ link->package.count < 3)
+ continue;
+
+ elem = link->package.elements;
+ if (elem[0].type != ACPI_TYPE_INTEGER ||
+ elem[1].type != ACPI_TYPE_INTEGER ||
+ (elem[2].type != ACPI_TYPE_LOCAL_REFERENCE &&
+ elem[2].type != ACPI_TYPE_STRING))
+ continue;
+
+ src_port = elem[0].integer.value;
+ dst_port = elem[1].integer.value;
+
+ if (acpi_graph_is_directional(graph_guid)) {
+ if (link->package.count < 4 ||
+ elem[3].type != ACPI_TYPE_INTEGER)
+ continue;
+
+ dir = elem[3].integer.value;
+ if (dir == ACPI_GRAPH_LINK_OUTPUT)
+ graph_root = acpi_graph_get_root_node(&roots, scope,
+ parent,
+ &data->subnodes,
+ "out-ports");
+ else if (dir == ACPI_GRAPH_LINK_INPUT)
+ graph_root = acpi_graph_get_root_node(&roots, scope,
+ parent,
+ &data->subnodes,
+ "in-ports");
+ else
+ continue;
+
+ if (!graph_root)
+ continue;
+
+ graph_parent = &graph_root->fwnode;
+ graph_subnodes = &graph_root->data.subnodes;
+ }
+
+ port_map = acpi_graph_get_port_map(&ports, scope, graph_parent,
+ graph_subnodes, src_port);
+ if (!port_map)
+ continue;
+
+ ep_id = port_map->endpoint_id++;
+ endpoint = acpi_graph_node_create("endpoint", ep_id, scope,
+ &port_map->port->fwnode,
+ &port_map->port->data.subnodes);
+ if (!endpoint)
+ continue;
+
+ if (!acpi_data_prop_add_integer(&endpoint->data, "reg", ep_id) ||
+ !acpi_data_prop_add_integer(&endpoint->data, "endpoint", ep_id) ||
+ !acpi_data_prop_add_remote_endpoint(&endpoint->data, &elem[2],
+ dst_port, 0)) {
+ acpi_data_node_delete(endpoint);
+ continue;
+ }
+
+ ret = true;
+ }
+ }
+
+ while (!list_empty(&ports)) {
+ struct acpi_graph_port_map *port_map;
+
+ port_map = list_first_entry(&ports, struct acpi_graph_port_map, node);
+ list_del(&port_map->node);
+
+ if (!ret || list_empty(&port_map->port->data.subnodes))
+ acpi_data_node_delete(port_map->port);
+
+ kfree(port_map);
+ }
+
+ while (!list_empty(&roots)) {
+ struct acpi_graph_root_map *root;
+
+ root = list_first_entry(&roots, struct acpi_graph_root_map, node);
+ list_del(&root->node);
+
+ if (!ret || list_empty(&root->root->data.subnodes))
+ acpi_data_node_delete(root->root);
+
+ kfree(root);
+ }
+
+ return ret;
+}
+
static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
union acpi_object *desc,
struct acpi_device_data *data,
struct fwnode_handle *parent)
{
+ bool ret = false;
int i;
- /* Look for the ACPI data subnodes GUID. */
+ /* Look for the ACPI data subnodes and graph UUIDs. */
for (i = 0; i < desc->package.count; i += 2) {
const union acpi_object *guid;
union acpi_object *links;
@@ -278,14 +700,14 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
links->type != ACPI_TYPE_PACKAGE)
break;
- if (!guid_equal((guid_t *)guid->buffer.pointer, &ads_guid))
- continue;
-
- return acpi_add_nondev_subnodes(scope, links, &data->subnodes,
- parent);
+ if (guid_equal((guid_t *)guid->buffer.pointer, &ads_guid))
+ ret |= acpi_add_nondev_subnodes(scope, links,
+ &data->subnodes, parent);
+ else if (guid_equal((guid_t *)guid->buffer.pointer, &graph_prop_guid))
+ ret |= acpi_add_graph_subnodes(scope, links, data, parent);
}
- return false;
+ return ret;
}
static bool acpi_property_value_ok(const union acpi_object *value)
@@ -1485,7 +1907,8 @@ static struct fwnode_handle *acpi_graph_get_next_endpoint(
break;
} while (port);
} else {
- port = fwnode_get_parent(prev);
+ /* Use the structural parent: the public parent skips port roots. */
+ port = acpi_node_get_parent(prev);
}
if (!port)
@@ -1544,6 +1967,42 @@ static struct fwnode_handle *acpi_graph_get_child_prop_value(
return NULL;
}
+static struct fwnode_handle *
+acpi_graph_get_first_endpoint(struct fwnode_handle *port)
+{
+ struct fwnode_handle *endpoint = NULL;
+
+ do {
+ endpoint = acpi_get_next_subnode(port, endpoint);
+ } while (endpoint && !is_acpi_graph_node(endpoint, "endpoint"));
+
+ return endpoint;
+}
+
+/**
+ * acpi_graph_get_remote_directional_port - Find a port nested under a
+ * synthetic "in-ports"/"out-ports" root node
+ * @fwnode: device fwnode
+ * @port_nr: the desired port number
+ *
+ * Return: the port node on success, NULL otherwise.
+ */
+static struct fwnode_handle *
+acpi_graph_get_remote_directional_port(struct fwnode_handle *fwnode,
+ unsigned int port_nr,
+ const char *ports_name)
+{
+ struct fwnode_handle *ports_node, *port;
+
+ if (!ports_name)
+ return NULL;
+
+ ports_node = acpi_fwnode_get_named_child_node(fwnode, ports_name);
+ if (ports_node)
+ return acpi_graph_get_child_prop_value(ports_node, "port", port_nr);
+
+ return NULL;
+}
/**
* acpi_graph_get_remote_endpoint - Parses and returns remote end of an endpoint
@@ -1555,6 +2014,8 @@ static struct fwnode_handle *
acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode)
{
struct fwnode_handle *fwnode;
+ struct fwnode_handle *source_port, *source_root;
+ const char *remote_ports = NULL;
unsigned int port_nr, endpoint_nr;
struct fwnode_reference_args args;
int ret;
@@ -1580,9 +2041,28 @@ acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode)
port_nr = args.args[0];
endpoint_nr = args.args[1];
- fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
+ /* A directional source can only be connected to the opposite root. */
+ source_port = acpi_node_get_parent(__fwnode);
+ source_root = acpi_node_get_parent(source_port);
+ if (is_acpi_data_node(source_root)) {
+ if (!strcmp(to_acpi_data_node(source_root)->name, "out-ports"))
+ remote_ports = "in-ports";
+ else if (!strcmp(to_acpi_data_node(source_root)->name, "in-ports"))
+ remote_ports = "out-ports";
+ }
+
+ fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr) ?:
+ acpi_graph_get_remote_directional_port(fwnode, port_nr,
+ remote_ports);
+ if (!fwnode)
+ return NULL;
- return acpi_graph_get_child_prop_value(fwnode, "endpoint", endpoint_nr);
+ /*
+ * Device Graph UUID links may not provide endpoint IDs. In that case
+ * return the first endpoint under the remote port.
+ */
+ return acpi_graph_get_child_prop_value(fwnode, "endpoint", endpoint_nr) ?:
+ acpi_graph_get_first_endpoint(fwnode);
}
static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [RFC PATCH 4/5] hwtracing: rvtrace: Move to fwnode_* APIs
2026-09-29 8:55 [RFC PATCH 0/5] hwtracing: rvtrace: Add ACPI support Sunil V L
` (2 preceding siblings ...)
2026-09-29 8:55 ` [RFC PATCH 3/5] ACPI: property: Add device graph support Sunil V L
@ 2026-09-29 8:55 ` Sunil V L
2026-09-29 8:55 ` [RFC PATCH 5/5] hwtracing: rvtrace: Add ACPI support Sunil V L
4 siblings, 0 replies; 6+ messages in thread
From: Sunil V L @ 2026-09-29 8:55 UTC (permalink / raw)
To: linux-acpi, linux-riscv, linux-kernel, devicetree
Cc: Rafael J . Wysocki, Len Brown, Mayuresh Chitale, Anup Patel,
Alexander Shishkin, Rob Herring, Saravana Kannan, Sunil V L
From: Sunil V L <sunilvl@oss.qualcomm.com>
so that it works for ACPI as well in future.
Signed-off-by: Sunil V L <sunilvl@oss.qualcomm.com>
---
drivers/hwtracing/gtrace/Kconfig | 4 +-
drivers/hwtracing/gtrace/rvtrace-platform.c | 131 +++++++++++++-------
2 files changed, 90 insertions(+), 45 deletions(-)
diff --git a/drivers/hwtracing/gtrace/Kconfig b/drivers/hwtracing/gtrace/Kconfig
index e5b62d65e2fd..86322250a6a3 100644
--- a/drivers/hwtracing/gtrace/Kconfig
+++ b/drivers/hwtracing/gtrace/Kconfig
@@ -2,7 +2,7 @@
menuconfig GTRACE
tristate "Generic Hardware Trace Support"
- depends on OF
+ depends on OF || ACPI
select PERF_EVENTS
help
This framework provides an architecture-neutral kernel interface
@@ -18,7 +18,7 @@ menuconfig GTRACE
config RVTRACE
tristate "RISC-V Trace Support"
depends on RISCV
- depends on OF
+ depends on OF || ACPI
depends on GTRACE
default RISCV
help
diff --git a/drivers/hwtracing/gtrace/rvtrace-platform.c b/drivers/hwtracing/gtrace/rvtrace-platform.c
index f34de9183d9a..12330d9dcddd 100644
--- a/drivers/hwtracing/gtrace/rvtrace-platform.c
+++ b/drivers/hwtracing/gtrace/rvtrace-platform.c
@@ -7,7 +7,6 @@
#include <linux/gtrace.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
@@ -61,52 +60,61 @@ const struct gtrace_hw_ops rvtrace_hw_ops = {
.reset = rvtrace_hw_reset,
};
-static int rvtrace_of_parse_outconns(struct gtrace_platform_data *pdata)
+static int rvtrace_parse_outconns(struct gtrace_platform_data *pdata)
{
- struct device_node *parent, *ep_node, *rep_node, *rdev_node;
+ struct fwnode_handle *parent, *ep_node, *rep_node, *rdev_node;
+ struct fwnode_endpoint ep = { 0 };
+ struct fwnode_endpoint rep = { 0 };
struct gtrace_connection *conn;
- struct of_endpoint ep, rep;
+ unsigned int nr_outconns;
int ret = 0, i = 0;
- parent = of_get_child_by_name(dev_of_node(pdata->dev), "out-ports");
+ parent = fwnode_get_named_child_node(dev_fwnode(pdata->dev), "out-ports");
if (!parent)
return 0;
- pdata->nr_outconns = of_graph_get_endpoint_count(parent);
- pdata->outconns = devm_kcalloc(pdata->dev, pdata->nr_outconns,
+ nr_outconns = fwnode_graph_get_endpoint_count(parent, 0);
+ pdata->nr_outconns = nr_outconns;
+ pdata->outconns = devm_kcalloc(pdata->dev, nr_outconns,
sizeof(*pdata->outconns), GFP_KERNEL);
if (!pdata->outconns) {
ret = -ENOMEM;
goto done;
}
- for_each_endpoint_of_node(parent, ep_node) {
+ fwnode_graph_for_each_endpoint(parent, ep_node) {
conn = devm_kzalloc(pdata->dev, sizeof(*conn), GFP_KERNEL);
if (!conn) {
- of_node_put(ep_node);
+ fwnode_handle_put(ep_node);
ret = -ENOMEM;
break;
}
- ret = of_graph_parse_endpoint(ep_node, &ep);
+ ret = fwnode_graph_parse_endpoint(ep_node, &ep);
if (ret) {
- of_node_put(ep_node);
+ fwnode_handle_put(ep_node);
break;
}
- rep_node = of_graph_get_remote_endpoint(ep_node);
+ rep_node = fwnode_graph_get_remote_endpoint(ep_node);
if (!rep_node) {
ret = -ENODEV;
- of_node_put(ep_node);
+ fwnode_handle_put(ep_node);
+ break;
+ }
+ rdev_node = fwnode_graph_get_port_parent(rep_node);
+ if (!rdev_node) {
+ ret = -ENODEV;
+ fwnode_handle_put(ep_node);
+ fwnode_handle_put(rep_node);
break;
}
- rdev_node = of_graph_get_port_parent(rep_node);
- ret = of_graph_parse_endpoint(rep_node, &rep);
+ ret = fwnode_graph_parse_endpoint(rep_node, &rep);
if (ret) {
- of_node_put(ep_node);
- of_node_put(rep_node);
- of_node_put(rdev_node);
+ fwnode_handle_put(ep_node);
+ fwnode_handle_put(rep_node);
+ fwnode_handle_put(rdev_node);
break;
}
@@ -115,21 +123,25 @@ static int rvtrace_of_parse_outconns(struct gtrace_platform_data *pdata)
/* The 'src_comp' is set by gtrace_register_component() */
conn->src_comp = NULL;
conn->dest_port = rep.port;
- conn->dest_fwnode = of_fwnode_handle(rdev_node);
+ conn->dest_fwnode = rdev_node;
fwnode_handle_get(conn->dest_fwnode);
conn->dest_comp = gtrace_find_by_fwnode(conn->dest_fwnode);
if (!conn->dest_comp) {
ret = -EPROBE_DEFER;
- of_node_put(ep_node);
- of_node_put(rep_node);
- of_node_put(rdev_node);
+ fwnode_handle_put(ep_node);
+ fwnode_handle_put(rep_node);
+ fwnode_handle_put(rdev_node);
break;
}
- pdata->outconns[i] = conn;
- i++;
+ pdata->outconns[i++] = conn;
+ fwnode_handle_put(rep_node);
+ fwnode_handle_put(rdev_node);
}
+ if (!ret)
+ pdata->nr_outconns = i;
+
done:
if (ret) {
for (i = 0; i < pdata->nr_outconns && pdata->outconns; i++) {
@@ -138,29 +150,69 @@ static int rvtrace_of_parse_outconns(struct gtrace_platform_data *pdata)
fwnode_handle_put(conn->dest_fwnode);
}
}
- of_node_put(parent);
+ fwnode_handle_put(parent);
return ret;
}
-static int rvtrace_of_parse_inconns(struct gtrace_platform_data *pdata)
+static int rvtrace_parse_inconns(struct gtrace_platform_data *pdata)
{
- struct device_node *parent;
+ struct fwnode_handle *parent;
int ret = 0;
- parent = of_get_child_by_name(dev_of_node(pdata->dev), "in-ports");
+ parent = fwnode_get_named_child_node(dev_fwnode(pdata->dev), "in-ports");
if (!parent)
return 0;
- pdata->nr_inconns = of_graph_get_endpoint_count(parent);
+ pdata->nr_inconns = fwnode_graph_get_endpoint_count(parent,
+ FWNODE_GRAPH_DEVICE_DISABLED);
pdata->inconns = devm_kcalloc(pdata->dev, pdata->nr_inconns,
sizeof(*pdata->inconns), GFP_KERNEL);
if (!pdata->inconns)
ret = -ENOMEM;
- of_node_put(parent);
+ fwnode_handle_put(parent);
return ret;
}
+#ifdef CONFIG_OF
+static int of_rvtrace_get_cpu(struct device *dev)
+{
+ struct device_node *dn;
+ int cpu;
+
+ if (!dev->of_node)
+ return -1;
+
+ dn = of_parse_phandle(dev->of_node, "cpus", 0);
+ if (!dn)
+ return -1;
+
+ cpu = of_cpu_node_to_id(dn);
+ of_node_put(dn);
+
+ return cpu;
+}
+#else
+static int of_rvtrace_get_cpu(struct device *dev)
+{
+ return -1;
+}
+#endif
+
+/*
+ * rvtrace_get_cpu - Find the logical CPU id of the CPU associated
+ * with this rvtrace device.
+ *
+ * Returns the logical CPU id when found.
+ */
+static int rvtrace_get_cpu(struct device *dev)
+{
+ if (is_of_node(dev_fwnode(dev)))
+ return of_rvtrace_get_cpu(dev);
+
+ return -1;
+}
+
static int rvtrace_platform_probe(struct platform_device *pdev)
{
struct gtrace_platform_data *pdata;
@@ -168,7 +220,6 @@ static int rvtrace_platform_probe(struct platform_device *pdev)
struct gtrace_component_id id;
struct gtrace_component *comp;
u32 impl, type, major, minor;
- struct device_node *node;
struct resource *res;
int gtype;
int ret;
@@ -189,24 +240,18 @@ static int rvtrace_platform_probe(struct platform_device *pdev)
if (!pdata->base)
return dev_err_probe(dev, -ENOMEM, "failed to ioremap %pR\n", res);
- pdata->bound_cpu = -1;
- node = of_parse_phandle(dev_of_node(dev), "cpus", 0);
- if (node) {
- ret = of_cpu_node_to_id(node);
- of_node_put(node);
- if (ret < 0)
- return dev_err_probe(dev, ret, "failed to get CPU id for %pOF\n", node);
- pdata->bound_cpu = ret;
- }
-
+ pdata->bound_cpu = rvtrace_get_cpu(dev);
+ if (pdata->bound_cpu < 0)
+ return dev_err_probe(dev, pdata->bound_cpu,
+ "failed to get bound CPU\n");
/* Default control poll timeout */
pdata->control_poll_timeout_usecs = 10;
- ret = rvtrace_of_parse_outconns(pdata);
+ ret = rvtrace_parse_outconns(pdata);
if (ret)
return dev_err_probe(dev, ret, "failed to parse output connections\n");
- ret = rvtrace_of_parse_inconns(pdata);
+ ret = rvtrace_parse_inconns(pdata);
if (ret)
return dev_err_probe(dev, ret, "failed to parse input connections\n");
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread