anitazha / rpms / ndctl

Forked from rpms/ndctl a year ago
Clone

Blame 0122-cxl-port-Add-disable-enable-port-command.patch

Jeff Moyer 2c91dc
From 1cfb7570369ae6bed832bde908435d38fa990f9d Mon Sep 17 00:00:00 2001
Jeff Moyer 2c91dc
From: Dan Williams <dan.j.williams@intel.com>
Jeff Moyer 2c91dc
Date: Sun, 23 Jan 2022 16:55:01 -0800
Jeff Moyer 2c91dc
Subject: [PATCH 122/217] cxl/port: Add {disable,enable}-port command
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
The {disable,enable}-port commands are used for debugging port enumeration
Jeff Moyer 2c91dc
corner cases and testing the kernel CXL device hotplug implementation.
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
In addition to unbinding the port from its driver, which also kicks of
Jeff Moyer 2c91dc
unregistration of descendent ports, the disable operation also flushes the
Jeff Moyer 2c91dc
kernels delayed workqueue for memory device removal.
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
Link: https://lore.kernel.org/r/164298570117.3021641.14546710754812021284.stgit@dwillia2-desk3.amr.corp.intel.com
Jeff Moyer 2c91dc
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Jeff Moyer 2c91dc
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Jeff Moyer 2c91dc
---
Jeff Moyer 2c91dc
 Documentation/cxl/cxl-disable-port.txt |  46 +++++
Jeff Moyer 2c91dc
 Documentation/cxl/cxl-enable-port.txt  |  43 +++++
Jeff Moyer 2c91dc
 Documentation/cxl/lib/libcxl.txt       |  11 ++
Jeff Moyer 2c91dc
 Documentation/cxl/meson.build          |   2 +
Jeff Moyer 2c91dc
 cxl/builtin.h                          |   2 +
Jeff Moyer 2c91dc
 cxl/cxl.c                              |   2 +
Jeff Moyer 2c91dc
 cxl/filter.c                           |  21 +-
Jeff Moyer 2c91dc
 cxl/filter.h                           |  13 ++
Jeff Moyer 2c91dc
 cxl/lib/libcxl.c                       |  95 +++++++++-
Jeff Moyer 2c91dc
 cxl/lib/libcxl.sym                     |   3 +
Jeff Moyer 2c91dc
 cxl/libcxl.h                           |   3 +
Jeff Moyer 2c91dc
 cxl/meson.build                        |   1 +
Jeff Moyer 2c91dc
 cxl/port.c                             | 253 +++++++++++++++++++++++++
Jeff Moyer 2c91dc
 13 files changed, 471 insertions(+), 24 deletions(-)
Jeff Moyer 2c91dc
 create mode 100644 Documentation/cxl/cxl-disable-port.txt
Jeff Moyer 2c91dc
 create mode 100644 Documentation/cxl/cxl-enable-port.txt
Jeff Moyer 2c91dc
 create mode 100644 cxl/port.c
Jeff Moyer 2c91dc
Jeff Moyer 2c91dc
diff --git a/Documentation/cxl/cxl-disable-port.txt b/Documentation/cxl/cxl-disable-port.txt
Jeff Moyer 2c91dc
new file mode 100644
Jeff Moyer 2c91dc
index 0000000..de13c07
Jeff Moyer 2c91dc
--- /dev/null
Jeff Moyer 2c91dc
+++ b/Documentation/cxl/cxl-disable-port.txt
Jeff Moyer 2c91dc
@@ -0,0 +1,46 @@
Jeff Moyer 2c91dc
+// SPDX-License-Identifier: GPL-2.0
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+cxl-disable-port(1)
Jeff Moyer 2c91dc
+===================
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+NAME
Jeff Moyer 2c91dc
+----
Jeff Moyer 2c91dc
+cxl-disable-port - activate / hot-add a given CXL port
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+SYNOPSIS
Jeff Moyer 2c91dc
+--------
Jeff Moyer 2c91dc
+[verse]
Jeff Moyer 2c91dc
+'cxl disable-port' <port0> [<port1>..<portN>] [<options>]
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+For test and debug scenarios, disable a CXL port and any memory devices
Jeff Moyer 2c91dc
+dependent on this port being active for CXL.mem operation.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+OPTIONS
Jeff Moyer 2c91dc
+-------
Jeff Moyer 2c91dc
+-e::
Jeff Moyer 2c91dc
+--endpoint::
Jeff Moyer 2c91dc
+	Toggle from treating the port arguments as Switch Port identifiers to
Jeff Moyer 2c91dc
+	Endpoint Port identifiers.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+-f::
Jeff Moyer 2c91dc
+--force::
Jeff Moyer 2c91dc
+	DANGEROUS: Override the safety measure that blocks attempts to disable a
Jeff Moyer 2c91dc
+	port if the tool determines a descendent memdev is in active usage.
Jeff Moyer 2c91dc
+	Recall that CXL memory ranges might have been established by platform
Jeff Moyer 2c91dc
+	firmware and disabling an active device is akin to force removing memory
Jeff Moyer 2c91dc
+	from a running system.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	Toggle from treating the port arguments as Switch Port identifiers to
Jeff Moyer 2c91dc
+	Endpoint Port identifiers.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+--debug::
Jeff Moyer 2c91dc
+	If the cxl tool was built with debug disabled, turn on debug
Jeff Moyer 2c91dc
+	messages.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+include::../copyright.txt[]
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+SEE ALSO
Jeff Moyer 2c91dc
+--------
Jeff Moyer 2c91dc
+linkcxl:cxl-disable-port[1]
Jeff Moyer 2c91dc
diff --git a/Documentation/cxl/cxl-enable-port.txt b/Documentation/cxl/cxl-enable-port.txt
Jeff Moyer 2c91dc
new file mode 100644
Jeff Moyer 2c91dc
index 0000000..9a37cef
Jeff Moyer 2c91dc
--- /dev/null
Jeff Moyer 2c91dc
+++ b/Documentation/cxl/cxl-enable-port.txt
Jeff Moyer 2c91dc
@@ -0,0 +1,43 @@
Jeff Moyer 2c91dc
+// SPDX-License-Identifier: GPL-2.0
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+cxl-enable-port(1)
Jeff Moyer 2c91dc
+==================
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+NAME
Jeff Moyer 2c91dc
+----
Jeff Moyer 2c91dc
+cxl-enable-port - activate / hot-add a given CXL port
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+SYNOPSIS
Jeff Moyer 2c91dc
+--------
Jeff Moyer 2c91dc
+[verse]
Jeff Moyer 2c91dc
+'cxl enable-port' <port0> [<port1>..<portN>] [<options>]
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+A port typically autoenables at initial device discovery. However, if it
Jeff Moyer 2c91dc
+was manually disabled this command can trigger the kernel to activate it
Jeff Moyer 2c91dc
+again. This involves detecting the state of the HDM (Host Managed Device
Jeff Moyer 2c91dc
+Memory) Decoders and validating that CXL.mem is enabled for each port in
Jeff Moyer 2c91dc
+the device's hierarchy.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+OPTIONS
Jeff Moyer 2c91dc
+-------
Jeff Moyer 2c91dc
+-e::
Jeff Moyer 2c91dc
+--endpoint::
Jeff Moyer 2c91dc
+	Toggle from treating the port arguments as Switch Port identifiers to
Jeff Moyer 2c91dc
+	Endpoint Port identifiers.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+-m::
Jeff Moyer 2c91dc
+--enable-memdevs::
Jeff Moyer 2c91dc
+	Try to enable descendant memdevs after enabling the port. Recall that a
Jeff Moyer 2c91dc
+	memdev is only enabled after all CXL ports in its device topology
Jeff Moyer 2c91dc
+	ancestry are enabled.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+--debug::
Jeff Moyer 2c91dc
+	If the cxl tool was built with debug enabled, turn on debug
Jeff Moyer 2c91dc
+	messages.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+include::../copyright.txt[]
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+SEE ALSO
Jeff Moyer 2c91dc
+--------
Jeff Moyer 2c91dc
+linkcxl:cxl-disable-port[1]
Jeff Moyer 2c91dc
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
Jeff Moyer 2c91dc
index a0fcee9..27eb29e 100644
Jeff Moyer 2c91dc
--- a/Documentation/cxl/lib/libcxl.txt
Jeff Moyer 2c91dc
+++ b/Documentation/cxl/lib/libcxl.txt
Jeff Moyer 2c91dc
@@ -247,6 +247,16 @@ Port, or Switch Upstream Port with CXL capabilities.
Jeff Moyer 2c91dc
 The cxl_port_foreach_all() helper does a depth first iteration of all
Jeff Moyer 2c91dc
 ports beneath the 'top' port argument.
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
+=== PORT: Control
Jeff Moyer 2c91dc
+---
Jeff Moyer 2c91dc
+int cxl_port_disable_invalidate(struct cxl_port *port);
Jeff Moyer 2c91dc
+int cxl_port_enable(struct cxl_port *port);
Jeff Moyer 2c91dc
+---
Jeff Moyer 2c91dc
+cxl_port_disable_invalidate() is a violent operation that disables
Jeff Moyer 2c91dc
+entire sub-tree of CXL Memory Device and Ports, only use it for test /
Jeff Moyer 2c91dc
+debug scenarios, or ensuring that all impacted devices are deactivated
Jeff Moyer 2c91dc
+first.
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
 === PORT: Attributes
Jeff Moyer 2c91dc
 ----
Jeff Moyer 2c91dc
 const char *cxl_port_get_devname(struct cxl_port *port);
Jeff Moyer 2c91dc
@@ -315,6 +325,7 @@ struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
Jeff Moyer 2c91dc
 struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
Jeff Moyer 2c91dc
 const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);
Jeff Moyer 2c91dc
 struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);
Jeff Moyer 2c91dc
+struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port);
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 #define cxl_endpoint_foreach(port, endpoint)                                 \
Jeff Moyer 2c91dc
        for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;       \
Jeff Moyer 2c91dc
diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build
Jeff Moyer 2c91dc
index 7618c97..96f4666 100644
Jeff Moyer 2c91dc
--- a/Documentation/cxl/meson.build
Jeff Moyer 2c91dc
+++ b/Documentation/cxl/meson.build
Jeff Moyer 2c91dc
@@ -32,6 +32,8 @@ cxl_manpages = [
Jeff Moyer 2c91dc
   'cxl-zero-labels.txt',
Jeff Moyer 2c91dc
   'cxl-enable-memdev.txt',
Jeff Moyer 2c91dc
   'cxl-disable-memdev.txt',
Jeff Moyer 2c91dc
+  'cxl-enable-port.txt',
Jeff Moyer 2c91dc
+  'cxl-disable-port.txt',
Jeff Moyer 2c91dc
 ]
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 foreach man : cxl_manpages
Jeff Moyer 2c91dc
diff --git a/cxl/builtin.h b/cxl/builtin.h
Jeff Moyer 2c91dc
index 621c85c..3123d5e 100644
Jeff Moyer 2c91dc
--- a/cxl/builtin.h
Jeff Moyer 2c91dc
+++ b/cxl/builtin.h
Jeff Moyer 2c91dc
@@ -12,4 +12,6 @@ int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx);
Jeff Moyer 2c91dc
 int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx);
Jeff Moyer 2c91dc
 int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
Jeff Moyer 2c91dc
 int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
Jeff Moyer 2c91dc
+int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);
Jeff Moyer 2c91dc
+int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);
Jeff Moyer 2c91dc
 #endif /* _CXL_BUILTIN_H_ */
Jeff Moyer 2c91dc
diff --git a/cxl/cxl.c b/cxl/cxl.c
Jeff Moyer 2c91dc
index 78d2e9a..c20c569 100644
Jeff Moyer 2c91dc
--- a/cxl/cxl.c
Jeff Moyer 2c91dc
+++ b/cxl/cxl.c
Jeff Moyer 2c91dc
@@ -66,6 +66,8 @@ static struct cmd_struct commands[] = {
Jeff Moyer 2c91dc
 	{ "write-labels", .c_fn = cmd_write_labels },
Jeff Moyer 2c91dc
 	{ "disable-memdev", .c_fn = cmd_disable_memdev },
Jeff Moyer 2c91dc
 	{ "enable-memdev", .c_fn = cmd_enable_memdev },
Jeff Moyer 2c91dc
+	{ "disable-port", .c_fn = cmd_disable_port },
Jeff Moyer 2c91dc
+	{ "enable-port", .c_fn = cmd_enable_port },
Jeff Moyer 2c91dc
 };
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 int main(int argc, const char **argv)
Jeff Moyer 2c91dc
diff --git a/cxl/filter.c b/cxl/filter.c
Jeff Moyer 2c91dc
index c691edf..f6a23b7 100644
Jeff Moyer 2c91dc
--- a/cxl/filter.c
Jeff Moyer 2c91dc
+++ b/cxl/filter.c
Jeff Moyer 2c91dc
@@ -47,8 +47,8 @@ bool cxl_filter_has(const char *__filter, const char *needle)
Jeff Moyer 2c91dc
 	return false;
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
-static struct cxl_endpoint *
Jeff Moyer 2c91dc
-util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident)
Jeff Moyer 2c91dc
+struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,
Jeff Moyer 2c91dc
+					      const char *__ident)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	char *ident, *save;
Jeff Moyer 2c91dc
 	const char *arg;
Jeff Moyer 2c91dc
@@ -124,11 +124,6 @@ static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,
Jeff Moyer 2c91dc
 	return NULL;
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
-enum cxl_port_filter_mode {
Jeff Moyer 2c91dc
-	CXL_PF_SINGLE,
Jeff Moyer 2c91dc
-	CXL_PF_ANCESTRY,
Jeff Moyer 2c91dc
-};
Jeff Moyer 2c91dc
-
Jeff Moyer 2c91dc
 static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	if (p->single)
Jeff Moyer 2c91dc
@@ -136,9 +131,8 @@ static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p)
Jeff Moyer 2c91dc
 	return CXL_PF_ANCESTRY;
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
-static struct cxl_port *util_cxl_port_filter(struct cxl_port *port,
Jeff Moyer 2c91dc
-					     const char *ident,
Jeff Moyer 2c91dc
-					     enum cxl_port_filter_mode mode)
Jeff Moyer 2c91dc
+struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident,
Jeff Moyer 2c91dc
+				      enum cxl_port_filter_mode mode)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	struct cxl_port *iter = port;
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
@@ -358,9 +352,9 @@ util_cxl_endpoint_filter_by_memdev(struct cxl_endpoint *endpoint,
Jeff Moyer 2c91dc
 	return NULL;
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
-static struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,
Jeff Moyer 2c91dc
-						       const char *ident,
Jeff Moyer 2c91dc
-						       const char *serial)
Jeff Moyer 2c91dc
+struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,
Jeff Moyer 2c91dc
+						const char *ident,
Jeff Moyer 2c91dc
+						const char *serial)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
Jeff Moyer 2c91dc
 	struct cxl_memdev *memdev;
Jeff Moyer 2c91dc
@@ -958,7 +952,6 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
Jeff Moyer 2c91dc
 					continue;
Jeff Moyer 2c91dc
 				}
Jeff Moyer 2c91dc
 			}
Jeff Moyer 2c91dc
-
Jeff Moyer 2c91dc
 		}
Jeff Moyer 2c91dc
 walk_children:
Jeff Moyer 2c91dc
 		dbg(p, "walk decoders\n");
Jeff Moyer 2c91dc
diff --git a/cxl/filter.h b/cxl/filter.h
Jeff Moyer 2c91dc
index 6fd469f..850df70 100644
Jeff Moyer 2c91dc
--- a/cxl/filter.h
Jeff Moyer 2c91dc
+++ b/cxl/filter.h
Jeff Moyer 2c91dc
@@ -29,6 +29,19 @@ struct cxl_filter_params {
Jeff Moyer 2c91dc
 struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
Jeff Moyer 2c91dc
 					  const char *__ident,
Jeff Moyer 2c91dc
 					  const char *serials);
Jeff Moyer 2c91dc
+struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,
Jeff Moyer 2c91dc
+						const char *ident,
Jeff Moyer 2c91dc
+						const char *serial);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+enum cxl_port_filter_mode {
Jeff Moyer 2c91dc
+	CXL_PF_SINGLE,
Jeff Moyer 2c91dc
+	CXL_PF_ANCESTRY,
Jeff Moyer 2c91dc
+};
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident,
Jeff Moyer 2c91dc
+				      enum cxl_port_filter_mode mode);
Jeff Moyer 2c91dc
+struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,
Jeff Moyer 2c91dc
+					      const char *__ident);
Jeff Moyer 2c91dc
 int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);
Jeff Moyer 2c91dc
 bool cxl_filter_has(const char *needle, const char *__filter);
Jeff Moyer 2c91dc
 #endif /* _CXL_UTIL_FILTER_H_ */
Jeff Moyer 2c91dc
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
Jeff Moyer 2c91dc
index dcfc826..1a7dccb 100644
Jeff Moyer 2c91dc
--- a/cxl/lib/libcxl.c
Jeff Moyer 2c91dc
+++ b/cxl/lib/libcxl.c
Jeff Moyer 2c91dc
@@ -258,6 +258,11 @@ CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)
Jeff Moyer 2c91dc
 	free(ctx);
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
+static int cxl_flush(struct cxl_ctx *ctx)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	return sysfs_write_attr(ctx, "/sys/bus/cxl/flush", "1\n");
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
 /**
Jeff Moyer 2c91dc
  * cxl_set_log_fn - override default log routine
Jeff Moyer 2c91dc
  * @ctx: cxl library context
Jeff Moyer 2c91dc
@@ -530,11 +535,31 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
Jeff Moyer 2c91dc
 	return memdev->firmware_version;
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
+static void bus_invalidate(struct cxl_bus *bus)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);
Jeff Moyer 2c91dc
+	struct cxl_port *bus_port, *port, *_p;
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	/*
Jeff Moyer 2c91dc
+	 * Something happend to cause the state of all ports to be
Jeff Moyer 2c91dc
+	 * indeterminate, delete them all and start over.
Jeff Moyer 2c91dc
+	 */
Jeff Moyer 2c91dc
+	cxl_memdev_foreach(ctx, memdev)
Jeff Moyer 2c91dc
+		if (cxl_memdev_get_bus(memdev) == bus)
Jeff Moyer 2c91dc
+			memdev->endpoint = NULL;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	bus_port = cxl_bus_get_port(bus);
Jeff Moyer 2c91dc
+	list_for_each_safe(&bus_port->child_ports, port, _p, list)
Jeff Moyer 2c91dc
+		free_port(port, &bus_port->child_ports);
Jeff Moyer 2c91dc
+	bus_port->ports_init = 0;
Jeff Moyer 2c91dc
+	cxl_flush(ctx);
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
 CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
Jeff Moyer 2c91dc
 	const char *devname = cxl_memdev_get_devname(memdev);
Jeff Moyer 2c91dc
-	struct cxl_port *port, *_p, *bus_port;
Jeff Moyer 2c91dc
 	struct cxl_bus *bus;
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 	if (!cxl_memdev_is_enabled(memdev))
Jeff Moyer 2c91dc
@@ -553,15 +578,7 @@ CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)
Jeff Moyer 2c91dc
 		return -EBUSY;
Jeff Moyer 2c91dc
 	}
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
-	/*
Jeff Moyer 2c91dc
-	 * The state of all ports is now indeterminate, delete them all
Jeff Moyer 2c91dc
-	 * and start over.
Jeff Moyer 2c91dc
-	 */
Jeff Moyer 2c91dc
-	bus_port = cxl_bus_get_port(bus);
Jeff Moyer 2c91dc
-	list_for_each_safe(&bus_port->child_ports, port, _p, list)
Jeff Moyer 2c91dc
-		free_port(port, &bus_port->child_ports);
Jeff Moyer 2c91dc
-	bus_port->ports_init = 0;
Jeff Moyer 2c91dc
-	memdev->endpoint = NULL;
Jeff Moyer 2c91dc
+	bus_invalidate(bus);
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
 	dbg(ctx, "%s: disabled\n", devname);
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
@@ -1352,6 +1369,57 @@ CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)
Jeff Moyer 2c91dc
 	return is_enabled(path);
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
+CXL_EXPORT int cxl_port_disable_invalidate(struct cxl_port *port)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	const char *devname = cxl_port_get_devname(port);
Jeff Moyer 2c91dc
+	struct cxl_bus *bus = cxl_port_get_bus(port);
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (cxl_port_is_root(port)) {
Jeff Moyer 2c91dc
+		err(ctx, "%s: can not be disabled through this interface\n",
Jeff Moyer 2c91dc
+		    devname);
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (!bus) {
Jeff Moyer 2c91dc
+		err(ctx, "%s: failed to invalidate\n", devname);
Jeff Moyer 2c91dc
+		return -ENXIO;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	util_unbind(port->dev_path, ctx);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (cxl_port_is_enabled(port)) {
Jeff Moyer 2c91dc
+		err(ctx, "%s: failed to disable\n", devname);
Jeff Moyer 2c91dc
+		return -EBUSY;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	dbg(ctx, "%s: disabled\n", devname);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	bus_invalidate(bus);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return 0;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+CXL_EXPORT int cxl_port_enable(struct cxl_port *port)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
Jeff Moyer 2c91dc
+	const char *devname = cxl_port_get_devname(port);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (cxl_port_is_enabled(port))
Jeff Moyer 2c91dc
+		return 0;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	util_bind(devname, port->module, "cxl", ctx);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (!cxl_port_is_enabled(port)) {
Jeff Moyer 2c91dc
+		err(ctx, "%s: failed to enable\n", devname);
Jeff Moyer 2c91dc
+		return -ENXIO;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	dbg(ctx, "%s: enabled\n", devname);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return 0;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
 CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	if (!cxl_port_is_root(port))
Jeff Moyer 2c91dc
@@ -1359,6 +1427,13 @@ CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)
Jeff Moyer 2c91dc
 	return container_of(port, struct cxl_bus, port);
Jeff Moyer 2c91dc
 }
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
+CXL_EXPORT struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	if (!cxl_port_is_endpoint(port))
Jeff Moyer 2c91dc
+		return NULL;
Jeff Moyer 2c91dc
+	return container_of(port, struct cxl_endpoint, port);
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
 static void *add_cxl_dport(void *parent, int id, const char *cxldport_base)
Jeff Moyer 2c91dc
 {
Jeff Moyer 2c91dc
 	const char *devname = devpath_to_devname(cxldport_base);
Jeff Moyer 2c91dc
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
Jeff Moyer 2c91dc
index 2c8358e..67c7fd5 100644
Jeff Moyer 2c91dc
--- a/cxl/lib/libcxl.sym
Jeff Moyer 2c91dc
+++ b/cxl/lib/libcxl.sym
Jeff Moyer 2c91dc
@@ -97,11 +97,14 @@ global:
Jeff Moyer 2c91dc
 	cxl_port_is_switch;
Jeff Moyer 2c91dc
 	cxl_port_to_bus;
Jeff Moyer 2c91dc
 	cxl_port_is_endpoint;
Jeff Moyer 2c91dc
+	cxl_port_to_endpoint;
Jeff Moyer 2c91dc
 	cxl_port_get_bus;
Jeff Moyer 2c91dc
 	cxl_port_get_host;
Jeff Moyer 2c91dc
 	cxl_port_get_bus;
Jeff Moyer 2c91dc
 	cxl_port_hosts_memdev;
Jeff Moyer 2c91dc
 	cxl_port_get_nr_dports;
Jeff Moyer 2c91dc
+	cxl_port_disable_invalidate;
Jeff Moyer 2c91dc
+	cxl_port_enable;
Jeff Moyer 2c91dc
 	cxl_port_get_next_all;
Jeff Moyer 2c91dc
 	cxl_endpoint_get_first;
Jeff Moyer 2c91dc
 	cxl_endpoint_get_next;
Jeff Moyer 2c91dc
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
Jeff Moyer 2c91dc
index c8d07bb..1aac396 100644
Jeff Moyer 2c91dc
--- a/cxl/libcxl.h
Jeff Moyer 2c91dc
+++ b/cxl/libcxl.h
Jeff Moyer 2c91dc
@@ -90,10 +90,13 @@ bool cxl_port_is_root(struct cxl_port *port);
Jeff Moyer 2c91dc
 bool cxl_port_is_switch(struct cxl_port *port);
Jeff Moyer 2c91dc
 struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);
Jeff Moyer 2c91dc
 bool cxl_port_is_endpoint(struct cxl_port *port);
Jeff Moyer 2c91dc
+struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port);
Jeff Moyer 2c91dc
 struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
Jeff Moyer 2c91dc
 const char *cxl_port_get_host(struct cxl_port *port);
Jeff Moyer 2c91dc
 bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);
Jeff Moyer 2c91dc
 int cxl_port_get_nr_dports(struct cxl_port *port);
Jeff Moyer 2c91dc
+int cxl_port_disable_invalidate(struct cxl_port *port);
Jeff Moyer 2c91dc
+int cxl_port_enable(struct cxl_port *port);
Jeff Moyer 2c91dc
 struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,
Jeff Moyer 2c91dc
 				       const struct cxl_port *top);
Jeff Moyer 2c91dc
 
Jeff Moyer 2c91dc
diff --git a/cxl/meson.build b/cxl/meson.build
Jeff Moyer 2c91dc
index fc7ee71..87cfea7 100644
Jeff Moyer 2c91dc
--- a/cxl/meson.build
Jeff Moyer 2c91dc
+++ b/cxl/meson.build
Jeff Moyer 2c91dc
@@ -1,6 +1,7 @@
Jeff Moyer 2c91dc
 cxl_src = [
Jeff Moyer 2c91dc
   'cxl.c',
Jeff Moyer 2c91dc
   'list.c',
Jeff Moyer 2c91dc
+  'port.c',
Jeff Moyer 2c91dc
   'memdev.c',
Jeff Moyer 2c91dc
   '../util/json.c',
Jeff Moyer 2c91dc
   '../util/log.c',
Jeff Moyer 2c91dc
diff --git a/cxl/port.c b/cxl/port.c
Jeff Moyer 2c91dc
new file mode 100644
Jeff Moyer 2c91dc
index 0000000..46a8f32
Jeff Moyer 2c91dc
--- /dev/null
Jeff Moyer 2c91dc
+++ b/cxl/port.c
Jeff Moyer 2c91dc
@@ -0,0 +1,253 @@
Jeff Moyer 2c91dc
+// SPDX-License-Identifier: GPL-2.0
Jeff Moyer 2c91dc
+/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */
Jeff Moyer 2c91dc
+#include <stdio.h>
Jeff Moyer 2c91dc
+#include <errno.h>
Jeff Moyer 2c91dc
+#include <stdlib.h>
Jeff Moyer 2c91dc
+#include <unistd.h>
Jeff Moyer 2c91dc
+#include <limits.h>
Jeff Moyer 2c91dc
+#include <util/log.h>
Jeff Moyer 2c91dc
+#include <cxl/libcxl.h>
Jeff Moyer 2c91dc
+#include <util/parse-options.h>
Jeff Moyer 2c91dc
+#include <ccan/minmax/minmax.h>
Jeff Moyer 2c91dc
+#include <ccan/array_size/array_size.h>
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+#include "filter.h"
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static struct parameters {
Jeff Moyer 2c91dc
+	bool debug;
Jeff Moyer 2c91dc
+	bool force;
Jeff Moyer 2c91dc
+	bool memdevs;
Jeff Moyer 2c91dc
+	bool endpoint;
Jeff Moyer 2c91dc
+} param;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static struct log_ctx pl;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+#define BASE_OPTIONS()                                                 \
Jeff Moyer 2c91dc
+OPT_BOOLEAN(0, "debug", &param.debug, "turn on debug"),                \
Jeff Moyer 2c91dc
+OPT_BOOLEAN('e', "endpoint", &param.endpoint,                          \
Jeff Moyer 2c91dc
+	    "target endpoints instead of switch ports")
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+#define ENABLE_OPTIONS()                                               \
Jeff Moyer 2c91dc
+OPT_BOOLEAN('m', "enable-memdevs", &param.memdevs,                   \
Jeff Moyer 2c91dc
+	    "enable downstream memdev(s)")
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+#define DISABLE_OPTIONS()                                              \
Jeff Moyer 2c91dc
+OPT_BOOLEAN('f', "force", &param.force,                                \
Jeff Moyer 2c91dc
+	    "DANGEROUS: override active memdev safety checks")
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static const struct option disable_options[] = {
Jeff Moyer 2c91dc
+	BASE_OPTIONS(),
Jeff Moyer 2c91dc
+	DISABLE_OPTIONS(),
Jeff Moyer 2c91dc
+	OPT_END(),
Jeff Moyer 2c91dc
+};
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static const struct option enable_options[] = {
Jeff Moyer 2c91dc
+	BASE_OPTIONS(),
Jeff Moyer 2c91dc
+	ENABLE_OPTIONS(),
Jeff Moyer 2c91dc
+	OPT_END(),
Jeff Moyer 2c91dc
+};
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int action_disable(struct cxl_port *port)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	const char *devname = cxl_port_get_devname(port);
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev;
Jeff Moyer 2c91dc
+	int active_memdevs = 0;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (!cxl_port_is_enabled(port)) {
Jeff Moyer 2c91dc
+		log_dbg(&pl, "%s already disabled\n", devname);
Jeff Moyer 2c91dc
+		return 0;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (param.endpoint) {
Jeff Moyer 2c91dc
+		struct cxl_endpoint *endpoint = cxl_port_to_endpoint(port);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		if (cxl_endpoint_get_memdev(endpoint))
Jeff Moyer 2c91dc
+			active_memdevs++;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cxl_memdev_foreach(ctx, memdev) {
Jeff Moyer 2c91dc
+		if (!cxl_port_get_dport_by_memdev(port, memdev))
Jeff Moyer 2c91dc
+			continue;
Jeff Moyer 2c91dc
+		if (cxl_memdev_is_enabled(memdev))
Jeff Moyer 2c91dc
+			active_memdevs++;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (active_memdevs && !param.force) {
Jeff Moyer 2c91dc
+		/*
Jeff Moyer 2c91dc
+		 * TODO: actually detect rather than assume active just
Jeff Moyer 2c91dc
+		 * because the memdev is enabled
Jeff Moyer 2c91dc
+		 */
Jeff Moyer 2c91dc
+		log_err(&pl,
Jeff Moyer 2c91dc
+			"%s hosts %d memdev%s which %s part of an active region\n",
Jeff Moyer 2c91dc
+			devname, active_memdevs, active_memdevs > 1 ? "s" : "",
Jeff Moyer 2c91dc
+			active_memdevs > 1 ? "are" : "is");
Jeff Moyer 2c91dc
+		log_err(&pl,
Jeff Moyer 2c91dc
+			"See 'cxl list -M -p %s' to see impacted device%s\n",
Jeff Moyer 2c91dc
+			devname, active_memdevs > 1 ? "s" : "");
Jeff Moyer 2c91dc
+		return -EBUSY;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	return cxl_port_disable_invalidate(port);
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int action_enable(struct cxl_port *port)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_ctx *ctx = cxl_port_get_ctx(port);
Jeff Moyer 2c91dc
+	struct cxl_memdev *memdev;
Jeff Moyer 2c91dc
+	int rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = cxl_port_enable(port);
Jeff Moyer 2c91dc
+	if (rc || !param.memdevs)
Jeff Moyer 2c91dc
+		return rc;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cxl_memdev_foreach(ctx, memdev)
Jeff Moyer 2c91dc
+		if (cxl_port_get_dport_by_memdev(port, memdev))
Jeff Moyer 2c91dc
+			cxl_memdev_enable(memdev);
Jeff Moyer 2c91dc
+	return 0;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static struct cxl_port *find_cxl_port(struct cxl_ctx *ctx, const char *ident)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_bus *bus;
Jeff Moyer 2c91dc
+	struct cxl_port *port;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cxl_bus_foreach(ctx, bus)
Jeff Moyer 2c91dc
+		cxl_port_foreach_all(cxl_bus_get_port(bus), port)
Jeff Moyer 2c91dc
+			if (util_cxl_port_filter(port, ident, CXL_PF_SINGLE))
Jeff Moyer 2c91dc
+				return port;
Jeff Moyer 2c91dc
+	return NULL;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static struct cxl_endpoint *find_cxl_endpoint(struct cxl_ctx *ctx,
Jeff Moyer 2c91dc
+					      const char *ident)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	struct cxl_bus *bus;
Jeff Moyer 2c91dc
+	struct cxl_port *port;
Jeff Moyer 2c91dc
+	struct cxl_endpoint *endpoint;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	cxl_bus_foreach(ctx, bus)
Jeff Moyer 2c91dc
+		cxl_port_foreach_all(cxl_bus_get_port(bus), port)
Jeff Moyer 2c91dc
+			cxl_endpoint_foreach(port, endpoint)
Jeff Moyer 2c91dc
+				if (util_cxl_endpoint_filter(endpoint, ident))
Jeff Moyer 2c91dc
+					return endpoint;
Jeff Moyer 2c91dc
+	return NULL;
Jeff Moyer 2c91dc
+}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+static int port_action(int argc, const char **argv, struct cxl_ctx *ctx,
Jeff Moyer 2c91dc
+		       int (*action)(struct cxl_port *port),
Jeff Moyer 2c91dc
+		       const struct option *options, const char *usage)
Jeff Moyer 2c91dc
+{
Jeff Moyer 2c91dc
+	int i, rc = 0, count = 0, err = 0;
Jeff Moyer 2c91dc
+	const char * const u[] = {
Jeff Moyer 2c91dc
+		usage,
Jeff Moyer 2c91dc
+		NULL
Jeff Moyer 2c91dc
+	};
Jeff Moyer 2c91dc
+	unsigned long id;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	log_init(&pl, "cxl port", "CXL_PORT_LOG");
Jeff Moyer 2c91dc
+	argc = parse_options(argc, argv, options, u, 0);
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (argc == 0)
Jeff Moyer 2c91dc
+		usage_with_options(u, options);
Jeff Moyer 2c91dc
+	for (i = 0; i < argc; i++) {
Jeff Moyer 2c91dc
+		const char *fmt;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		if (strcmp(argv[i], "all") == 0) {
Jeff Moyer 2c91dc
+			argc = 1;
Jeff Moyer 2c91dc
+			break;
Jeff Moyer 2c91dc
+		}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		if (param.endpoint)
Jeff Moyer 2c91dc
+			fmt = "endpoint%lu";
Jeff Moyer 2c91dc
+		else
Jeff Moyer 2c91dc
+			fmt = "port%lu";
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		if (sscanf(argv[i], fmt, &id) == 1)
Jeff Moyer 2c91dc
+			continue;
Jeff Moyer 2c91dc
+		if (sscanf(argv[i], "%lu", &id) == 1)
Jeff Moyer 2c91dc
+			continue;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		log_err(&pl, "'%s' is not a valid %s identifer\n", argv[i],
Jeff Moyer 2c91dc
+			param.endpoint ? "endpoint" : "port");
Jeff Moyer 2c91dc
+		err++;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (err == argc) {
Jeff Moyer 2c91dc
+		usage_with_options(u, options);
Jeff Moyer 2c91dc
+		return -EINVAL;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	if (param.debug) {
Jeff Moyer 2c91dc
+		cxl_set_log_priority(ctx, LOG_DEBUG);
Jeff Moyer 2c91dc
+		pl.log_priority = LOG_DEBUG;
Jeff Moyer 2c91dc
+	} else
Jeff Moyer 2c91dc
+		pl.log_priority = LOG_INFO;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	rc = 0;
Jeff Moyer 2c91dc
+	err = 0;
Jeff Moyer 2c91dc
+	count = 0;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	for (i = 0; i < argc; i++) {
Jeff Moyer 2c91dc
+		struct cxl_port *port;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		if (param.endpoint) {
Jeff Moyer 2c91dc
+			struct cxl_endpoint *endpoint;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+			endpoint = find_cxl_endpoint(ctx, argv[i]);
Jeff Moyer 2c91dc
+			if (!endpoint) {
Jeff Moyer 2c91dc
+				log_dbg(&pl, "endpoint: %s not found\n",
Jeff Moyer 2c91dc
+					argv[i]);
Jeff Moyer 2c91dc
+				continue;
Jeff Moyer 2c91dc
+			}
Jeff Moyer 2c91dc
+			port = cxl_endpoint_get_port(endpoint);
Jeff Moyer 2c91dc
+		} else {
Jeff Moyer 2c91dc
+			port = find_cxl_port(ctx, argv[i]);
Jeff Moyer 2c91dc
+			if (!port) {
Jeff Moyer 2c91dc
+				log_dbg(&pl, "port: %s not found\n", argv[i]);
Jeff Moyer 2c91dc
+				continue;
Jeff Moyer 2c91dc
+			}
Jeff Moyer 2c91dc
+		}
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+		log_dbg(&pl, "run action on port: %s\n",
Jeff Moyer 2c91dc
+			cxl_port_get_devname(port));
Jeff Moyer 2c91dc
+		rc = action(port);
Jeff Moyer 2c91dc
+		if (rc == 0)
Jeff Moyer 2c91dc
+			count++;
Jeff Moyer 2c91dc
+		else if (rc && !err)
Jeff Moyer 2c91dc
+			err = rc;
Jeff Moyer 2c91dc
+	}
Jeff Moyer 2c91dc
+	rc = err;
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	/*
Jeff Moyer 2c91dc
+	 * count if some actions succeeded, 0 if none were attempted,
Jeff Moyer 2c91dc
+	 * negative error code otherwise.
Jeff Moyer 2c91dc
+	 */
Jeff Moyer 2c91dc
+	if (count > 0)
Jeff Moyer 2c91dc
+		return count;
Jeff Moyer 2c91dc
+	return rc;
Jeff Moyer 2c91dc
+ }
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+ int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx)
Jeff Moyer 2c91dc
+ {
Jeff Moyer 2c91dc
+	 int count = port_action(
Jeff Moyer 2c91dc
+		 argc, argv, ctx, action_disable, disable_options,
Jeff Moyer 2c91dc
+		 "cxl disable-port <port0> [<port1>..<portN>] [<options>]");
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	 log_info(&pl, "disabled %d port%s\n", count >= 0 ? count : 0,
Jeff Moyer 2c91dc
+		  count > 1 ? "s" : "");
Jeff Moyer 2c91dc
+	 return count >= 0 ? 0 : EXIT_FAILURE;
Jeff Moyer 2c91dc
+ }
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+ int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx)
Jeff Moyer 2c91dc
+ {
Jeff Moyer 2c91dc
+	 int count = port_action(
Jeff Moyer 2c91dc
+		 argc, argv, ctx, action_enable, enable_options,
Jeff Moyer 2c91dc
+		 "cxl enable-port <port0> [<port1>..<portN>] [<options>]");
Jeff Moyer 2c91dc
+
Jeff Moyer 2c91dc
+	 log_info(&pl, "enabled %d port%s\n", count >= 0 ? count : 0,
Jeff Moyer 2c91dc
+		  count > 1 ? "s" : "");
Jeff Moyer 2c91dc
+	 return count >= 0 ? 0 : EXIT_FAILURE;
Jeff Moyer 2c91dc
+ }
Jeff Moyer 2c91dc
-- 
Jeff Moyer 2c91dc
2.27.0
Jeff Moyer 2c91dc