Blame SOURCES/0119-cxl-list-Reuse-the-target-option-for-ports.patch

e0018b
From d87cee2dd4756f7e067bdadc78a0632dd666cc64 Mon Sep 17 00:00:00 2001
e0018b
From: Dan Williams <dan.j.williams@intel.com>
e0018b
Date: Sun, 23 Jan 2022 16:54:44 -0800
e0018b
Subject: [PATCH 119/217] cxl/list: Reuse the --target option for ports
e0018b
e0018b
It is useful to be able to dump the dport-id to host-device-name. Rather
e0018b
than introduce a new option, just interpret --target as "list dports" for
e0018b
port objects.
e0018b
e0018b
$ cxl list -BTu -b ACPI.CXL
e0018b
{
e0018b
  "bus":"root0",
e0018b
  "provider":"ACPI.CXL",
e0018b
  "nr_dports":1,
e0018b
  "dports":[
e0018b
    {
e0018b
      "dport":"ACPI0016:00",
e0018b
      "alias":"pci0000:34",
e0018b
      "id":"0"
e0018b
    }
e0018b
  ]
e0018b
}
e0018b
e0018b
Link: https://lore.kernel.org/r/164298568481.3021641.4632086646702812643.stgit@dwillia2-desk3.amr.corp.intel.com
e0018b
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
e0018b
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
e0018b
---
e0018b
 .clang-format                    |   1 +
e0018b
 Documentation/cxl/cxl-list.txt   |  18 ++++-
e0018b
 Documentation/cxl/lib/libcxl.txt |  27 ++++++++
e0018b
 cxl/json.c                       |  56 +++++++++++++++-
e0018b
 cxl/lib/libcxl.c                 | 109 ++++++++++++++++++++++++++++++-
e0018b
 cxl/lib/libcxl.sym               |   7 ++
e0018b
 cxl/lib/private.h                |  13 ++++
e0018b
 cxl/libcxl.h                     |  12 ++++
e0018b
 cxl/list.c                       |   2 +-
e0018b
 9 files changed, 240 insertions(+), 5 deletions(-)
e0018b
e0018b
diff --git a/.clang-format b/.clang-format
e0018b
index 47fb657..c753487 100644
e0018b
--- a/.clang-format
e0018b
+++ b/.clang-format
e0018b
@@ -82,6 +82,7 @@ ForEachMacros:
e0018b
   - 'cxl_port_foreach'
e0018b
   - 'cxl_decoder_foreach'
e0018b
   - 'cxl_target_foreach'
e0018b
+  - 'cxl_dport_foreach'
e0018b
   - 'cxl_endpoint_foreach'
e0018b
   - 'daxctl_dev_foreach'
e0018b
   - 'daxctl_mapping_foreach'
e0018b
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
e0018b
index 20ff2cb..e1299d9 100644
e0018b
--- a/Documentation/cxl/cxl-list.txt
e0018b
+++ b/Documentation/cxl/cxl-list.txt
e0018b
@@ -272,7 +272,23 @@ OPTIONS
e0018b
 
e0018b
 -T::
e0018b
 --targets::
e0018b
-	Extend decoder listings with downstream port target information.
e0018b
+	Extend decoder listings with downstream port target information, and /
e0018b
+	or port and bus listings with the downstream port information.
e0018b
+----
e0018b
+# cxl list -BTu -b ACPI.CXL
e0018b
+{
e0018b
+  "bus":"root0",
e0018b
+  "provider":"ACPI.CXL",
e0018b
+  "nr_dports":1,
e0018b
+  "dports":[
e0018b
+    {
e0018b
+      "dport":"ACPI0016:00",
e0018b
+      "alias":"pci0000:34",
e0018b
+      "id":"0"
e0018b
+    }
e0018b
+  ]
e0018b
+}
e0018b
+----
e0018b
 
e0018b
 --debug::
e0018b
 	If the cxl tool was built with debug enabled, turn on debug
e0018b
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
e0018b
index a68a58b..2e8570d 100644
e0018b
--- a/Documentation/cxl/lib/libcxl.txt
e0018b
+++ b/Documentation/cxl/lib/libcxl.txt
e0018b
@@ -245,6 +245,7 @@ bool cxl_port_is_root(struct cxl_port *port);
e0018b
 bool cxl_port_is_switch(struct cxl_port *port);
e0018b
 bool cxl_port_is_endpoint(struct cxl_port *port);
e0018b
 bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);
e0018b
+int cxl_port_get_nr_dports(struct cxl_port *port);
e0018b
 ----
e0018b
 The port type is communicated via cxl_port_is_<type>(). An 'enabled' port
e0018b
 is one that has succeeded in discovering the CXL component registers in
e0018b
@@ -256,6 +257,32 @@ of intervening switch ports, and a terminal endpoint port.
e0018b
 cxl_port_hosts_memdev() returns true if the port's host appears in the
e0018b
 memdev host's device topology ancestry.
e0018b
 
e0018b
+==== DPORTS
e0018b
+A CXL dport object represents a CXL / PCIe Switch Downstream Port, or a
e0018b
+CXL / PCIe host bridge.
e0018b
+
e0018b
+===== DPORT: Enumeration
e0018b
+----
e0018b
+struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);
e0018b
+struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);
e0018b
+
e0018b
+#define cxl_dport_foreach(port, dport)                                     \
e0018b
+       for (dport = cxl_dport_get_first(port); dport != NULL;              \
e0018b
+            dport = cxl_dport_get_next(dport))
e0018b
+
e0018b
+----
e0018b
+
e0018b
+===== DPORT: Attributes
e0018b
+----
e0018b
+const char *cxl_dport_get_devname(struct cxl_dport *dport);
e0018b
+const char *cxl_dport_get_physical_node(struct cxl_dport *dport);
e0018b
+int cxl_dport_get_id(struct cxl_dport *dport);
e0018b
+----
e0018b
+The id of a dport is the hardware idenfifier used by an upstream port to
e0018b
+reference a downstream port. The physical node of a dport is only
e0018b
+available for platform firmware defined downstream ports and alias the
e0018b
+companion object, like a PCI host bridge, in the PCI device hierarchy.
e0018b
+
e0018b
 ENDPOINTS
e0018b
 ---------
e0018b
 CXL endpoint objects encapsulate the set of host-managed device-memory
e0018b
diff --git a/cxl/json.c b/cxl/json.c
e0018b
index d81aed8..4fb5eec 100644
e0018b
--- a/cxl/json.c
e0018b
+++ b/cxl/json.c
e0018b
@@ -241,6 +241,58 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
e0018b
 	return jdev;
e0018b
 }
e0018b
 
e0018b
+static struct json_object *util_cxl_dports_to_json(struct json_object *jport,
e0018b
+						   struct cxl_port *port,
e0018b
+						   unsigned long flags)
e0018b
+{
e0018b
+	struct json_object *jobj, *jdports;
e0018b
+	struct cxl_dport *dport;
e0018b
+	int val;
e0018b
+
e0018b
+	val = cxl_port_get_nr_dports(port);
e0018b
+	if (!val || !(flags & UTIL_JSON_TARGETS))
e0018b
+		return jport;
e0018b
+
e0018b
+	jobj = json_object_new_int(val);
e0018b
+	if (jobj)
e0018b
+		json_object_object_add(jport, "nr_dports", jobj);
e0018b
+
e0018b
+	jdports = json_object_new_array();
e0018b
+	if (!jdports)
e0018b
+		return jport;
e0018b
+
e0018b
+	cxl_dport_foreach(port, dport) {
e0018b
+		struct json_object *jdport;
e0018b
+		const char *phys_node;
e0018b
+
e0018b
+		jdport = json_object_new_object();
e0018b
+		if (!jdport)
e0018b
+			continue;
e0018b
+
e0018b
+		jobj = json_object_new_string(cxl_dport_get_devname(dport));
e0018b
+		if (jobj)
e0018b
+			json_object_object_add(jdport, "dport", jobj);
e0018b
+
e0018b
+		phys_node = cxl_dport_get_physical_node(dport);
e0018b
+		if (phys_node) {
e0018b
+			jobj = json_object_new_string(phys_node);
e0018b
+			if (jobj)
e0018b
+				json_object_object_add(jdport, "alias", jobj);
e0018b
+		}
e0018b
+
e0018b
+		val = cxl_dport_get_id(dport);
e0018b
+		jobj = util_json_object_hex(val, flags);
e0018b
+		if (jobj)
e0018b
+			json_object_object_add(jdport, "id", jobj);
e0018b
+
e0018b
+		json_object_array_add(jdports, jdport);
e0018b
+	}
e0018b
+
e0018b
+	json_object_object_add(jport, "dports", jdports);
e0018b
+
e0018b
+	return jport;
e0018b
+}
e0018b
+
e0018b
 struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
e0018b
 					 unsigned long flags)
e0018b
 {
e0018b
@@ -259,7 +311,7 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
e0018b
 	if (jobj)
e0018b
 		json_object_object_add(jbus, "provider", jobj);
e0018b
 
e0018b
-	return jbus;
e0018b
+	return util_cxl_dports_to_json(jbus, cxl_bus_get_port(bus), flags);
e0018b
 }
e0018b
 
e0018b
 struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
e0018b
@@ -403,7 +455,7 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,
e0018b
 			json_object_object_add(jport, "state", jobj);
e0018b
 	}
e0018b
 
e0018b
-	return jport;
e0018b
+	return util_cxl_dports_to_json(jport, port, flags);
e0018b
 }
e0018b
 
e0018b
 struct json_object *util_cxl_port_to_json(struct cxl_port *port,
e0018b
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
e0018b
index 7bf7949..d7a3f10 100644
e0018b
--- a/cxl/lib/libcxl.c
e0018b
+++ b/cxl/lib/libcxl.c
e0018b
@@ -89,13 +89,24 @@ static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)
e0018b
 	free(decoder);
e0018b
 }
e0018b
 
e0018b
+static void free_dport(struct cxl_dport *dport, struct list_head *head)
e0018b
+{
e0018b
+	if (head)
e0018b
+		list_del_from(head, &dport->list);
e0018b
+	free(dport->dev_buf);
e0018b
+	free(dport->dev_path);
e0018b
+	free(dport->phys_path);
e0018b
+	free(dport);
e0018b
+}
e0018b
+
e0018b
 static void free_port(struct cxl_port *port, struct list_head *head);
e0018b
 static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head);
e0018b
 static void __free_port(struct cxl_port *port, struct list_head *head)
e0018b
 {
e0018b
-	struct cxl_port *child, *_c;
e0018b
 	struct cxl_endpoint *endpoint, *_e;
e0018b
 	struct cxl_decoder *decoder, *_d;
e0018b
+	struct cxl_dport *dport, *_dp;
e0018b
+	struct cxl_port *child, *_c;
e0018b
 
e0018b
 	if (head)
e0018b
 		list_del_from(head, &port->list);
e0018b
@@ -105,6 +116,8 @@ static void __free_port(struct cxl_port *port, struct list_head *head)
e0018b
 		free_endpoint(endpoint, &port->endpoints);
e0018b
 	list_for_each_safe(&port->decoders, decoder, _d, list)
e0018b
 		free_decoder(decoder, &port->decoders);
e0018b
+	list_for_each_safe(&port->dports, dport, _dp, list)
e0018b
+		free_dport(dport , &port->dports);
e0018b
 	kmod_module_unref(port->module);
e0018b
 	free(port->dev_buf);
e0018b
 	free(port->dev_path);
e0018b
@@ -701,6 +714,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,
e0018b
 	list_head_init(&port->child_ports);
e0018b
 	list_head_init(&port->endpoints);
e0018b
 	list_head_init(&port->decoders);
e0018b
+	list_head_init(&port->dports);
e0018b
 
e0018b
 	port->dev_path = strdup(cxlport_base);
e0018b
 	if (!port->dev_path)
e0018b
@@ -1332,6 +1346,99 @@ CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)
e0018b
 	return container_of(port, struct cxl_bus, port);
e0018b
 }
e0018b
 
e0018b
+static void *add_cxl_dport(void *parent, int id, const char *cxldport_base)
e0018b
+{
e0018b
+	const char *devname = devpath_to_devname(cxldport_base);
e0018b
+	struct cxl_dport *dport, *dport_dup;
e0018b
+	struct cxl_port *port = parent;
e0018b
+	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
e0018b
+
e0018b
+	dbg(ctx, "%s: base: \'%s\'\n", devname, cxldport_base);
e0018b
+
e0018b
+	dport = calloc(1, sizeof(*dport));
e0018b
+	if (!dport)
e0018b
+		return NULL;
e0018b
+
e0018b
+	dport->id = id;
e0018b
+	dport->port = port;
e0018b
+
e0018b
+	dport->dev_path = realpath(cxldport_base, NULL);
e0018b
+	if (!dport->dev_path)
e0018b
+		goto err;
e0018b
+
e0018b
+	dport->dev_buf = calloc(1, strlen(cxldport_base) + 50);
e0018b
+	if (!dport->dev_buf)
e0018b
+		goto err;
e0018b
+	dport->buf_len = strlen(cxldport_base) + 50;
e0018b
+
e0018b
+	sprintf(dport->dev_buf, "%s/physical_node", cxldport_base);
e0018b
+	dport->phys_path = realpath(dport->dev_buf, NULL);
e0018b
+
e0018b
+	cxl_dport_foreach(port, dport_dup)
e0018b
+		if (dport_dup->id == dport->id) {
e0018b
+			free_dport(dport, NULL);
e0018b
+			return dport_dup;
e0018b
+		}
e0018b
+
e0018b
+	port->nr_dports++;
e0018b
+	list_add(&port->dports, &dport->list);
e0018b
+	return dport;
e0018b
+
e0018b
+err:
e0018b
+	free_dport(dport, NULL);
e0018b
+	return NULL;
e0018b
+}
e0018b
+
e0018b
+static void cxl_dports_init(struct cxl_port *port)
e0018b
+{
e0018b
+	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
e0018b
+
e0018b
+	if (port->dports_init)
e0018b
+		return;
e0018b
+
e0018b
+	port->dports_init = 1;
e0018b
+
e0018b
+	sysfs_device_parse(ctx, port->dev_path, "dport", port, add_cxl_dport);
e0018b
+}
e0018b
+
e0018b
+CXL_EXPORT int cxl_port_get_nr_dports(struct cxl_port *port)
e0018b
+{
e0018b
+	if (!port->dports_init)
e0018b
+		cxl_dports_init(port);
e0018b
+	return port->nr_dports;
e0018b
+}
e0018b
+
e0018b
+CXL_EXPORT struct cxl_dport *cxl_dport_get_first(struct cxl_port *port)
e0018b
+{
e0018b
+	cxl_dports_init(port);
e0018b
+
e0018b
+	return list_top(&port->dports, struct cxl_dport, list);
e0018b
+}
e0018b
+
e0018b
+CXL_EXPORT struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport)
e0018b
+{
e0018b
+	struct cxl_port *port = dport->port;
e0018b
+
e0018b
+	return list_next(&port->dports, dport, list);
e0018b
+}
e0018b
+
e0018b
+CXL_EXPORT const char *cxl_dport_get_devname(struct cxl_dport *dport)
e0018b
+{
e0018b
+	return devpath_to_devname(dport->dev_path);
e0018b
+}
e0018b
+
e0018b
+CXL_EXPORT const char *cxl_dport_get_physical_node(struct cxl_dport *dport)
e0018b
+{
e0018b
+	if (!dport->phys_path)
e0018b
+		return NULL;
e0018b
+	return devpath_to_devname(dport->phys_path);
e0018b
+}
e0018b
+
e0018b
+CXL_EXPORT int cxl_dport_get_id(struct cxl_dport *dport)
e0018b
+{
e0018b
+	return dport->id;
e0018b
+}
e0018b
+
e0018b
 static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)
e0018b
 {
e0018b
 	const char *devname = devpath_to_devname(cxlbus_base);
e0018b
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
e0018b
index ce01298..0190b13 100644
e0018b
--- a/cxl/lib/libcxl.sym
e0018b
+++ b/cxl/lib/libcxl.sym
e0018b
@@ -101,6 +101,8 @@ global:
e0018b
 	cxl_port_get_host;
e0018b
 	cxl_port_get_bus;
e0018b
 	cxl_port_hosts_memdev;
e0018b
+	cxl_port_get_nr_dports;
e0018b
+	cxl_port_get_next_all;
e0018b
 	cxl_endpoint_get_first;
e0018b
 	cxl_endpoint_get_next;
e0018b
 	cxl_endpoint_get_devname;
e0018b
@@ -142,4 +144,9 @@ global:
e0018b
 	cxl_target_get_devname;
e0018b
 	cxl_target_maps_memdev;
e0018b
 	cxl_target_get_physical_node;
e0018b
+	cxl_dport_get_first;
e0018b
+	cxl_dport_get_next;
e0018b
+	cxl_dport_get_devname;
e0018b
+	cxl_dport_get_physical_node;
e0018b
+	cxl_dport_get_id;
e0018b
 } LIBCXL_1;
e0018b
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
e0018b
index 7e7742d..f483c30 100644
e0018b
--- a/cxl/lib/private.h
e0018b
+++ b/cxl/lib/private.h
e0018b
@@ -38,6 +38,16 @@ struct cxl_memdev {
e0018b
 	struct cxl_endpoint *endpoint;
e0018b
 };
e0018b
 
e0018b
+struct cxl_dport {
e0018b
+	int id;
e0018b
+	void *dev_buf;
e0018b
+	size_t buf_len;
e0018b
+	char *dev_path;
e0018b
+	char *phys_path;
e0018b
+	struct cxl_port *port;
e0018b
+	struct list_node list;
e0018b
+};
e0018b
+
e0018b
 enum cxl_port_type {
e0018b
 	CXL_PORT_ROOT,
e0018b
 	CXL_PORT_SWITCH,
e0018b
@@ -53,6 +63,8 @@ struct cxl_port {
e0018b
 	int ports_init;
e0018b
 	int endpoints_init;
e0018b
 	int decoders_init;
e0018b
+	int dports_init;
e0018b
+	int nr_dports;
e0018b
 	struct cxl_ctx *ctx;
e0018b
 	struct cxl_bus *bus;
e0018b
 	enum cxl_port_type type;
e0018b
@@ -62,6 +74,7 @@ struct cxl_port {
e0018b
 	struct list_head child_ports;
e0018b
 	struct list_head endpoints;
e0018b
 	struct list_head decoders;
e0018b
+	struct list_head dports;
e0018b
 };
e0018b
 
e0018b
 struct cxl_bus {
e0018b
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
e0018b
index 0e484cc..07f4a31 100644
e0018b
--- a/cxl/libcxl.h
e0018b
+++ b/cxl/libcxl.h
e0018b
@@ -93,11 +93,23 @@ bool cxl_port_is_endpoint(struct cxl_port *port);
e0018b
 struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
e0018b
 const char *cxl_port_get_host(struct cxl_port *port);
e0018b
 bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);
e0018b
+int cxl_port_get_nr_dports(struct cxl_port *port);
e0018b
 
e0018b
 #define cxl_port_foreach(parent, port)                                         \
e0018b
 	for (port = cxl_port_get_first(parent); port != NULL;                  \
e0018b
 	     port = cxl_port_get_next(port))
e0018b
 
e0018b
+struct cxl_dport;
e0018b
+struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);
e0018b
+struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);
e0018b
+const char *cxl_dport_get_devname(struct cxl_dport *dport);
e0018b
+const char *cxl_dport_get_physical_node(struct cxl_dport *dport);
e0018b
+int cxl_dport_get_id(struct cxl_dport *dport);
e0018b
+
e0018b
+#define cxl_dport_foreach(port, dport)                                         \
e0018b
+	for (dport = cxl_dport_get_first(port); dport != NULL;                 \
e0018b
+	     dport = cxl_dport_get_next(dport))
e0018b
+
e0018b
 struct cxl_decoder;
e0018b
 struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);
e0018b
 struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);
e0018b
diff --git a/cxl/list.c b/cxl/list.c
e0018b
index 27c963a..de96ff9 100644
e0018b
--- a/cxl/list.c
e0018b
+++ b/cxl/list.c
e0018b
@@ -42,7 +42,7 @@ static const struct option options[] = {
e0018b
 	OPT_BOOLEAN('D', "decoders", &param.decoders,
e0018b
 		    "include CXL decoder info"),
e0018b
 	OPT_BOOLEAN('T', "targets", &param.targets,
e0018b
-		    "include CXL target data with decoders"),
e0018b
+		    "include CXL target data with decoders or ports"),
e0018b
 	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
e0018b
 	OPT_BOOLEAN('u', "human", &param.human,
e0018b
 		    "use human friendly number formats "),
e0018b
-- 
e0018b
2.27.0
e0018b