Blame SOURCES/0159-cxl-bus-Add-bus-disable-support.patch

2eb93d
From 8a35aa8fd3e1db06228329a0ca900ce246ca329e Mon Sep 17 00:00:00 2001
2eb93d
From: Dan Williams <dan.j.williams@intel.com>
2eb93d
Date: Thu, 28 Apr 2022 15:10:27 -0700
2eb93d
Subject: [PATCH 159/217] cxl/bus: Add bus disable support
2eb93d
2eb93d
Route requests to disable the root back to unbinding the platform firmware
2eb93d
device, ACPI0017 for ACPI.CXL platforms.
2eb93d
2eb93d
Link: https://lore.kernel.org/r/165118382738.1676208.16851880881648171660.stgit@dwillia2-desk3.amr.corp.intel.com
2eb93d
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2eb93d
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
2eb93d
---
2eb93d
 Documentation/cxl/cxl-disable-bus.txt |  37 ++++++
2eb93d
 Documentation/cxl/lib/libcxl.txt      |  12 ++
2eb93d
 Documentation/cxl/meson.build         |   1 +
2eb93d
 cxl/builtin.h                         |   1 +
2eb93d
 cxl/bus.c                             | 159 ++++++++++++++++++++++++++
2eb93d
 cxl/cxl.c                             |   1 +
2eb93d
 cxl/filter.c                          |   3 +-
2eb93d
 cxl/filter.h                          |   1 +
2eb93d
 cxl/lib/libcxl.c                      |  15 +++
2eb93d
 cxl/lib/libcxl.sym                    |   1 +
2eb93d
 cxl/libcxl.h                          |   1 +
2eb93d
 cxl/meson.build                       |   1 +
2eb93d
 12 files changed, 231 insertions(+), 2 deletions(-)
2eb93d
 create mode 100644 Documentation/cxl/cxl-disable-bus.txt
2eb93d
 create mode 100644 cxl/bus.c
2eb93d
2eb93d
diff --git a/Documentation/cxl/cxl-disable-bus.txt b/Documentation/cxl/cxl-disable-bus.txt
2eb93d
new file mode 100644
2eb93d
index 0000000..65f695c
2eb93d
--- /dev/null
2eb93d
+++ b/Documentation/cxl/cxl-disable-bus.txt
2eb93d
@@ -0,0 +1,37 @@
2eb93d
+// SPDX-License-Identifier: GPL-2.0
2eb93d
+
2eb93d
+cxl-disable-bus(1)
2eb93d
+===================
2eb93d
+
2eb93d
+NAME
2eb93d
+----
2eb93d
+cxl-disable-bus - Shutdown an entire tree of CXL devices
2eb93d
+
2eb93d
+SYNOPSIS
2eb93d
+--------
2eb93d
+[verse]
2eb93d
+'cxl disable-bus' <root0> [<root1>..<rootN>] [<options>]
2eb93d
+
2eb93d
+For test and debug scenarios, disable a CXL bus and any associated
2eb93d
+memory devices from CXL.mem operations.
2eb93d
+
2eb93d
+OPTIONS
2eb93d
+-------
2eb93d
+-f::
2eb93d
+--force::
2eb93d
+	DANGEROUS: Override the safety measure that blocks attempts to disable a
2eb93d
+	bus if the tool determines a descendent memdev is in active usage.
2eb93d
+	Recall that CXL memory ranges might have been established by platform
2eb93d
+	firmware and disabling an active device is akin to force removing memory
2eb93d
+	from a running system.
2eb93d
+
2eb93d
+--debug::
2eb93d
+	If the cxl tool was built with debug disabled, turn on debug
2eb93d
+	messages.
2eb93d
+
2eb93d
+
2eb93d
+include::../copyright.txt[]
2eb93d
+
2eb93d
+SEE ALSO
2eb93d
+--------
2eb93d
+linkcxl:cxl-disable-port[1]
2eb93d
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
2eb93d
index 7b223cb..f8f0e66 100644
2eb93d
--- a/Documentation/cxl/lib/libcxl.txt
2eb93d
+++ b/Documentation/cxl/lib/libcxl.txt
2eb93d
@@ -216,6 +216,18 @@ discovery order. The possible provider names are 'ACPI.CXL' and
2eb93d
 the kernel device names that are subject to change based on discovery
2eb93d
 order.
2eb93d
 
2eb93d
+=== BUS: Control
2eb93d
+----
2eb93d
+int cxl_bus_disable_invalidate(struct cxl_bus *bus);
2eb93d
+----
2eb93d
+
2eb93d
+An entire CXL topology can be torn down with this API. Like other
2eb93d
+_invalidate APIs callers must assume that all library objects have been
2eb93d
+freed. This one goes one step further and also frees the @bus argument.
2eb93d
+This may crash the system and is only useful in kernel driver
2eb93d
+development scenarios.
2eb93d
+
2eb93d
+
2eb93d
 PORTS
2eb93d
 -----
2eb93d
 CXL ports track the PCIe hierarchy between a platform firmware CXL root
2eb93d
diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build
2eb93d
index e927644..974a5a4 100644
2eb93d
--- a/Documentation/cxl/meson.build
2eb93d
+++ b/Documentation/cxl/meson.build
2eb93d
@@ -34,6 +34,7 @@ cxl_manpages = [
2eb93d
   'cxl-disable-memdev.txt',
2eb93d
   'cxl-enable-port.txt',
2eb93d
   'cxl-disable-port.txt',
2eb93d
+  'cxl-disable-bus.txt',
2eb93d
   'cxl-set-partition.txt',
2eb93d
 ]
2eb93d
 
2eb93d
diff --git a/cxl/builtin.h b/cxl/builtin.h
2eb93d
index 7bbad98..a437bc3 100644
2eb93d
--- a/cxl/builtin.h
2eb93d
+++ b/cxl/builtin.h
2eb93d
@@ -15,4 +15,5 @@ int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
2eb93d
 int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);
2eb93d
 int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);
2eb93d
 int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx);
2eb93d
+int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx);
2eb93d
 #endif /* _CXL_BUILTIN_H_ */
2eb93d
diff --git a/cxl/bus.c b/cxl/bus.c
2eb93d
new file mode 100644
2eb93d
index 0000000..3321295
2eb93d
--- /dev/null
2eb93d
+++ b/cxl/bus.c
2eb93d
@@ -0,0 +1,159 @@
2eb93d
+// SPDX-License-Identifier: GPL-2.0
2eb93d
+/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */
2eb93d
+#include <stdio.h>
2eb93d
+#include <errno.h>
2eb93d
+#include <stdlib.h>
2eb93d
+#include <unistd.h>
2eb93d
+#include <limits.h>
2eb93d
+#include <util/log.h>
2eb93d
+#include <cxl/libcxl.h>
2eb93d
+#include <util/parse-options.h>
2eb93d
+#include <ccan/minmax/minmax.h>
2eb93d
+#include <ccan/array_size/array_size.h>
2eb93d
+
2eb93d
+#include "filter.h"
2eb93d
+
2eb93d
+static struct parameters {
2eb93d
+	bool debug;
2eb93d
+	bool force;
2eb93d
+} param;
2eb93d
+
2eb93d
+static struct log_ctx bl;
2eb93d
+
2eb93d
+#define BASE_OPTIONS()                                                 \
2eb93d
+OPT_BOOLEAN(0, "debug", &param.debug, "turn on debug")
2eb93d
+
2eb93d
+#define DISABLE_OPTIONS()                                              \
2eb93d
+OPT_BOOLEAN('f', "force", &param.force,                                \
2eb93d
+	    "DANGEROUS: override active memdev safety checks")
2eb93d
+
2eb93d
+static const struct option disable_options[] = {
2eb93d
+	BASE_OPTIONS(),
2eb93d
+	DISABLE_OPTIONS(),
2eb93d
+	OPT_END(),
2eb93d
+};
2eb93d
+
2eb93d
+static int action_disable(struct cxl_bus *bus)
2eb93d
+{
2eb93d
+	const char *devname = cxl_bus_get_devname(bus);
2eb93d
+	struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);
2eb93d
+	struct cxl_memdev *memdev;
2eb93d
+	int active_memdevs = 0;
2eb93d
+
2eb93d
+	cxl_memdev_foreach(ctx, memdev)
2eb93d
+		if (bus == cxl_memdev_get_bus(memdev))
2eb93d
+			active_memdevs++;
2eb93d
+
2eb93d
+	if (active_memdevs && !param.force) {
2eb93d
+		/*
2eb93d
+		 * TODO: actually detect rather than assume active just
2eb93d
+		 * because the memdev is enabled
2eb93d
+		 */
2eb93d
+		log_err(&bl,
2eb93d
+			"%s hosts %d memdev%s which %s part of an active region\n",
2eb93d
+			devname, active_memdevs, active_memdevs > 1 ? "s" : "",
2eb93d
+			active_memdevs > 1 ? "are" : "is");
2eb93d
+		log_err(&bl,
2eb93d
+			"See 'cxl list -M -b %s' to see impacted device%s\n",
2eb93d
+			devname, active_memdevs > 1 ? "s" : "");
2eb93d
+		return -EBUSY;
2eb93d
+	}
2eb93d
+
2eb93d
+	return cxl_bus_disable_invalidate(bus);
2eb93d
+}
2eb93d
+
2eb93d
+static struct cxl_bus *find_cxl_bus(struct cxl_ctx *ctx, const char *ident)
2eb93d
+{
2eb93d
+	struct cxl_bus *bus;
2eb93d
+
2eb93d
+	cxl_bus_foreach(ctx, bus)
2eb93d
+		if (util_cxl_bus_filter(bus, ident))
2eb93d
+			return bus;
2eb93d
+	return NULL;
2eb93d
+}
2eb93d
+
2eb93d
+static int bus_action(int argc, const char **argv, struct cxl_ctx *ctx,
2eb93d
+		      int (*action)(struct cxl_bus *bus),
2eb93d
+		      const struct option *options, const char *usage)
2eb93d
+{
2eb93d
+	int i, rc = 0, count = 0, err = 0;
2eb93d
+	const char * const u[] = {
2eb93d
+		usage,
2eb93d
+		NULL
2eb93d
+	};
2eb93d
+	unsigned long id;
2eb93d
+
2eb93d
+	log_init(&bl, "cxl bus", "CXL_PORT_LOG");
2eb93d
+	argc = parse_options(argc, argv, options, u, 0);
2eb93d
+
2eb93d
+	if (argc == 0)
2eb93d
+		usage_with_options(u, options);
2eb93d
+	for (i = 0; i < argc; i++) {
2eb93d
+		if (strcmp(argv[i], "all") == 0) {
2eb93d
+			argv[0] = "all";
2eb93d
+			argc = 1;
2eb93d
+			break;
2eb93d
+		}
2eb93d
+
2eb93d
+		if (sscanf(argv[i], "root%lu", &id) == 1)
2eb93d
+			continue;
2eb93d
+		if (sscanf(argv[i], "%lu", &id) == 1)
2eb93d
+			continue;
2eb93d
+
2eb93d
+		log_err(&bl, "'%s' is not a valid bus identifer\n", argv[i]);
2eb93d
+		err++;
2eb93d
+	}
2eb93d
+
2eb93d
+	if (err == argc) {
2eb93d
+		usage_with_options(u, options);
2eb93d
+		return -EINVAL;
2eb93d
+	}
2eb93d
+
2eb93d
+	if (param.debug) {
2eb93d
+		cxl_set_log_priority(ctx, LOG_DEBUG);
2eb93d
+		bl.log_priority = LOG_DEBUG;
2eb93d
+	} else
2eb93d
+		bl.log_priority = LOG_INFO;
2eb93d
+
2eb93d
+	rc = 0;
2eb93d
+	err = 0;
2eb93d
+	count = 0;
2eb93d
+
2eb93d
+	for (i = 0; i < argc; i++) {
2eb93d
+		struct cxl_bus *bus;
2eb93d
+
2eb93d
+		bus = find_cxl_bus(ctx, argv[i]);
2eb93d
+		if (!bus) {
2eb93d
+			log_dbg(&bl, "bus: %s not found\n", argv[i]);
2eb93d
+			continue;
2eb93d
+		}
2eb93d
+
2eb93d
+		log_dbg(&bl, "run action on bus: %s\n",
2eb93d
+			cxl_bus_get_devname(bus));
2eb93d
+		rc = action(bus);
2eb93d
+		if (rc == 0)
2eb93d
+			count++;
2eb93d
+		else if (rc && !err)
2eb93d
+			err = rc;
2eb93d
+	}
2eb93d
+	rc = err;
2eb93d
+
2eb93d
+	/*
2eb93d
+	 * count if some actions succeeded, 0 if none were attempted,
2eb93d
+	 * negative error code otherwise.
2eb93d
+	 */
2eb93d
+	if (count > 0)
2eb93d
+		return count;
2eb93d
+	return rc;
2eb93d
+}
2eb93d
+
2eb93d
+ int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx)
2eb93d
+ {
2eb93d
+	 int count = bus_action(
2eb93d
+		 argc, argv, ctx, action_disable, disable_options,
2eb93d
+		 "cxl disable-bus <bus0> [<bus1>..<busN>] [<options>]");
2eb93d
+
2eb93d
+	 log_info(&bl, "disabled %d bus%s\n", count >= 0 ? count : 0,
2eb93d
+		  count > 1 ? "s" : "");
2eb93d
+	 return count >= 0 ? 0 : EXIT_FAILURE;
2eb93d
+ }
2eb93d
diff --git a/cxl/cxl.c b/cxl/cxl.c
2eb93d
index ab4bbec..aa4ce61 100644
2eb93d
--- a/cxl/cxl.c
2eb93d
+++ b/cxl/cxl.c
2eb93d
@@ -69,6 +69,7 @@ static struct cmd_struct commands[] = {
2eb93d
 	{ "disable-port", .c_fn = cmd_disable_port },
2eb93d
 	{ "enable-port", .c_fn = cmd_enable_port },
2eb93d
 	{ "set-partition", .c_fn = cmd_set_partition },
2eb93d
+	{ "disable-bus", .c_fn = cmd_disable_bus },
2eb93d
 };
2eb93d
 
2eb93d
 int main(int argc, const char **argv)
2eb93d
diff --git a/cxl/filter.c b/cxl/filter.c
2eb93d
index b339642..c6ab9eb 100644
2eb93d
--- a/cxl/filter.c
2eb93d
+++ b/cxl/filter.c
2eb93d
@@ -176,8 +176,7 @@ util_cxl_decoder_filter_by_port(struct cxl_decoder *decoder, const char *ident,
2eb93d
 	return NULL;
2eb93d
 }
2eb93d
 
2eb93d
-static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,
2eb93d
-					   const char *__ident)
2eb93d
+struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident)
2eb93d
 {
2eb93d
 	char *ident, *save;
2eb93d
 	const char *arg;
2eb93d
diff --git a/cxl/filter.h b/cxl/filter.h
2eb93d
index 697b777..9557943 100644
2eb93d
--- a/cxl/filter.h
2eb93d
+++ b/cxl/filter.h
2eb93d
@@ -41,6 +41,7 @@ enum cxl_port_filter_mode {
2eb93d
 
2eb93d
 struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident,
2eb93d
 				      enum cxl_port_filter_mode mode);
2eb93d
+struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident);
2eb93d
 struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,
2eb93d
 					      const char *__ident);
2eb93d
 struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target,
2eb93d
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
2eb93d
index 59e1644..0e8dd20 100644
2eb93d
--- a/cxl/lib/libcxl.c
2eb93d
+++ b/cxl/lib/libcxl.c
2eb93d
@@ -556,6 +556,21 @@ static void bus_invalidate(struct cxl_bus *bus)
2eb93d
 	cxl_flush(ctx);
2eb93d
 }
2eb93d
 
2eb93d
+CXL_EXPORT int cxl_bus_disable_invalidate(struct cxl_bus *bus)
2eb93d
+{
2eb93d
+	struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);
2eb93d
+	struct cxl_port *port = cxl_bus_get_port(bus);
2eb93d
+	int rc;
2eb93d
+
2eb93d
+	rc = util_unbind(port->uport, ctx);
2eb93d
+	if (rc)
2eb93d
+		return rc;
2eb93d
+
2eb93d
+	free_bus(bus, &ctx->buses);
2eb93d
+	cxl_flush(ctx);
2eb93d
+	return 0;
2eb93d
+}
2eb93d
+
2eb93d
 CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)
2eb93d
 {
2eb93d
 	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
2eb93d
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
2eb93d
index aab1112..dffcb60 100644
2eb93d
--- a/cxl/lib/libcxl.sym
2eb93d
+++ b/cxl/lib/libcxl.sym
2eb93d
@@ -86,6 +86,7 @@ global:
2eb93d
 	cxl_bus_get_id;
2eb93d
 	cxl_bus_get_port;
2eb93d
 	cxl_bus_get_ctx;
2eb93d
+	cxl_bus_disable_invalidate;
2eb93d
 	cxl_port_get_first;
2eb93d
 	cxl_port_get_next;
2eb93d
 	cxl_port_get_devname;
2eb93d
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
2eb93d
index 0063d31..0007f4d 100644
2eb93d
--- a/cxl/libcxl.h
2eb93d
+++ b/cxl/libcxl.h
2eb93d
@@ -73,6 +73,7 @@ const char *cxl_bus_get_devname(struct cxl_bus *bus);
2eb93d
 int cxl_bus_get_id(struct cxl_bus *bus);
2eb93d
 struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);
2eb93d
 struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus);
2eb93d
+int cxl_bus_disable_invalidate(struct cxl_bus *bus);
2eb93d
 
2eb93d
 #define cxl_bus_foreach(ctx, bus)                                              \
2eb93d
 	for (bus = cxl_bus_get_first(ctx); bus != NULL;                        \
2eb93d
diff --git a/cxl/meson.build b/cxl/meson.build
2eb93d
index 671c8e1..d63dcb1 100644
2eb93d
--- a/cxl/meson.build
2eb93d
+++ b/cxl/meson.build
2eb93d
@@ -2,6 +2,7 @@ cxl_src = [
2eb93d
   'cxl.c',
2eb93d
   'list.c',
2eb93d
   'port.c',
2eb93d
+  'bus.c',
2eb93d
   'memdev.c',
2eb93d
   'json.c',
2eb93d
   'filter.c',
2eb93d
-- 
2eb93d
2.27.0
2eb93d