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

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