Linux CXL
 help / color / mirror / Atom feed
From: Dave Jiang <dave.jiang@intel.com>
To: Ben Cheatham <Benjamin.Cheatham@amd.com>,
	nvdimm@lists.linux.dev, alison.schofield@intel.com
Cc: linux-cxl@vger.kernel.org
Subject: Re: [PATCH 2/7] libcxl: Add CXL protocol errors
Date: Fri, 9 Jan 2026 10:54:50 -0700	[thread overview]
Message-ID: <c6f4f05b-b1b8-4b2b-b9d8-27be52b3e549@intel.com> (raw)
In-Reply-To: <20260109160720.1823-3-Benjamin.Cheatham@amd.com>



On 1/9/26 9:07 AM, Ben Cheatham wrote:
> The v6.11 Linux kernel adds CXL protocl (CXL.cache & CXL.mem) error
> injection for platforms that implement the error types as according to
> the v6.5+ ACPI specification. The interface for injecting these errors
> are provided by the kernel under the CXL debugfs. The relevant files in
> the interface are the einj_types file, which provides the available CXL
> error types for injection, and the einj_inject file, which injects the
> error into a CXL VH root port or CXL RCH downstream port.
> 
> Add a library API to retrieve the CXL error types and inject them. This
> API will be used in a later commit by the 'cxl-inject-error' and
> 'cxl-list' commands.
> 
> Signed-off-by: Ben Cheatham <Benjamin.Cheatham@amd.com>

Just a nit below. otherwise

Reviewed-by: Dave Jiang <dave.jiang@intel.com>

> ---
>  cxl/lib/libcxl.c   | 194 +++++++++++++++++++++++++++++++++++++++++++++
>  cxl/lib/libcxl.sym |   5 ++
>  cxl/lib/private.h  |  14 ++++
>  cxl/libcxl.h       |  13 +++
>  4 files changed, 226 insertions(+)
> 
> diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
> index 6b7e92c..27ff037 100644
> --- a/cxl/lib/libcxl.c
> +++ b/cxl/lib/libcxl.c
> @@ -48,11 +48,13 @@ struct cxl_ctx {
>  	void *userdata;
>  	int memdevs_init;
>  	int buses_init;
> +	int perrors_init;
>  	unsigned long timeout;
>  	struct udev *udev;
>  	struct udev_queue *udev_queue;
>  	struct list_head memdevs;
>  	struct list_head buses;
> +	struct list_head perrors;
>  	struct kmod_ctx *kmod_ctx;
>  	struct daxctl_ctx *daxctl_ctx;
>  	void *private_data;
> @@ -207,6 +209,14 @@ static void free_bus(struct cxl_bus *bus, struct list_head *head)
>  	free(bus);
>  }
>  
> +static void free_protocol_error(struct cxl_protocol_error *perror,
> +				struct list_head *head)
> +{
> +	if (head)
> +		list_del_from(head, &perror->list);
> +	free(perror);
> +}
> +
>  /**
>   * cxl_get_userdata - retrieve stored data pointer from library context
>   * @ctx: cxl library context
> @@ -325,6 +335,7 @@ CXL_EXPORT int cxl_new(struct cxl_ctx **ctx)
>  	*ctx = c;
>  	list_head_init(&c->memdevs);
>  	list_head_init(&c->buses);
> +	list_head_init(&c->perrors);
>  	c->kmod_ctx = kmod_ctx;
>  	c->daxctl_ctx = daxctl_ctx;
>  	c->udev = udev;
> @@ -366,6 +377,7 @@ CXL_EXPORT struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx)
>   */
>  CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)
>  {
> +	struct cxl_protocol_error *perror, *_p;
>  	struct cxl_memdev *memdev, *_d;
>  	struct cxl_bus *bus, *_b;
>  
> @@ -381,6 +393,9 @@ CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)
>  	list_for_each_safe(&ctx->buses, bus, _b, port.list)
>  		free_bus(bus, &ctx->buses);
>  
> +	list_for_each_safe(&ctx->perrors, perror, _p, list)
> +		free_protocol_error(perror, &ctx->perrors);
> +
>  	udev_queue_unref(ctx->udev_queue);
>  	udev_unref(ctx->udev);
>  	kmod_unref(ctx->kmod_ctx);
> @@ -3423,6 +3438,185 @@ CXL_EXPORT int cxl_port_decoders_committed(struct cxl_port *port)
>  	return port->decoders_committed;
>  }
>  
> +const struct cxl_protocol_error cxl_protocol_errors[] = {
> +	CXL_PROTOCOL_ERROR(0x1000, "cache-correctable"),
> +	CXL_PROTOCOL_ERROR(0x2000, "cache-uncorrectable"),
> +	CXL_PROTOCOL_ERROR(0x4000, "cache-fatal"),
> +	CXL_PROTOCOL_ERROR(0x8000, "mem-correctable"),
> +	CXL_PROTOCOL_ERROR(0x10000, "mem-uncorrectable"),
> +	CXL_PROTOCOL_ERROR(0x20000, "mem-fatal")
> +};
> +
> +static struct cxl_protocol_error *create_cxl_protocol_error(struct cxl_ctx *ctx,
> +							    unsigned int n)
> +{
> +	struct cxl_protocol_error *perror;
> +
> +	for (unsigned long i = 0; i < ARRAY_SIZE(cxl_protocol_errors); i++) {
> +		if (n != cxl_protocol_errors[i].num)
> +			continue;
> +
> +		perror = calloc(1, sizeof(*perror));
> +		if (!perror)
> +			return NULL;
> +
> +		*perror = cxl_protocol_errors[i];
> +		perror->ctx = ctx;
> +		return perror;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void cxl_add_protocol_errors(struct cxl_ctx *ctx)
> +{
> +	struct cxl_protocol_error *perror;
> +	char buf[SYSFS_ATTR_SIZE];
> +	char *path, *num, *save;
> +	size_t path_len, len;
> +	unsigned long n;
> +	int rc = 0;
> +
> +	if (!ctx->cxl_debugfs)
> +		return;
> +
> +	path_len = strlen(ctx->cxl_debugfs) + 100;
> +	path = calloc(1, path_len);

Maybe just use PATH_MAX from <linux/limits.h>.

DJ

> +	if (!path)
> +		return;
> +
> +	len = snprintf(path, path_len, "%s/einj_types", ctx->cxl_debugfs);
> +	if (len >= path_len) {
> +		err(ctx, "Buffer too small\n");
> +		goto err;
> +	}
> +
> +	rc = access(path, F_OK);
> +	if (rc) {
> +		err(ctx, "failed to access %s: %s\n", path, strerror(errno));
> +		goto err;
> +	}
> +
> +	rc = sysfs_read_attr(ctx, path, buf);
> +	if (rc) {
> +		err(ctx, "failed to read %s: %s\n", path, strerror(-rc));
> +		goto err;
> +	}
> +
> +	/*
> +	 * The format of the output of the einj_types attr is:
> +	 * <Error number in hex 1> <Error name 1>
> +	 * <Error number in hex 2> <Error name 2>
> +	 * ...
> +	 *
> +	 * We only need the number, so parse that and skip the rest of
> +	 * the line.
> +	 */
> +	num = strtok_r(buf, " \n", &save);
> +	while (num) {
> +		n = strtoul(num, NULL, 16);
> +		perror = create_cxl_protocol_error(ctx, n);
> +		if (perror)
> +			list_add_tail(&ctx->perrors, &perror->list);
> +
> +		num = strtok_r(NULL, "\n", &save);
> +		if (!num)
> +			break;
> +
> +		num = strtok_r(NULL, " \n", &save);
> +	}
> +
> +err:
> +	free(path);
> +}
> +
> +static void cxl_protocol_errors_init(struct cxl_ctx *ctx)
> +{
> +	if (ctx->perrors_init)
> +		return;
> +
> +	ctx->perrors_init = 1;
> +	cxl_add_protocol_errors(ctx);
> +}
> +
> +CXL_EXPORT struct cxl_protocol_error *
> +cxl_protocol_error_get_first(struct cxl_ctx *ctx)
> +{
> +	cxl_protocol_errors_init(ctx);
> +
> +	return list_top(&ctx->perrors, struct cxl_protocol_error, list);
> +}
> +
> +CXL_EXPORT struct cxl_protocol_error *
> +cxl_protocol_error_get_next(struct cxl_protocol_error *perror)
> +{
> +	struct cxl_ctx *ctx = perror->ctx;
> +
> +	return list_next(&ctx->perrors, perror, list);
> +}
> +
> +CXL_EXPORT unsigned int
> +cxl_protocol_error_get_num(struct cxl_protocol_error *perror)
> +{
> +	return perror->num;
> +}
> +
> +CXL_EXPORT const char *
> +cxl_protocol_error_get_str(struct cxl_protocol_error *perror)
> +{
> +	return perror->string;
> +}
> +
> +CXL_EXPORT int cxl_dport_protocol_error_inject(struct cxl_dport *dport,
> +					       unsigned int error)
> +{
> +	struct cxl_ctx *ctx = dport->port->ctx;
> +	char buf[32] = { 0 };
> +	size_t path_len, len;
> +	char *path;
> +	int rc;
> +
> +	if (!ctx->cxl_debugfs)
> +		return -ENOENT;
> +
> +	path_len = strlen(ctx->cxl_debugfs) + 100;
> +	path = calloc(path_len, sizeof(char));
> +	if (!path)
> +		return -ENOMEM;
> +
> +	len = snprintf(path, path_len, "%s/%s/einj_inject", ctx->cxl_debugfs,
> +		      cxl_dport_get_devname(dport));
> +	if (len >= path_len) {
> +		err(ctx, "%s: buffer too small\n", cxl_dport_get_devname(dport));
> +		free(path);
> +		return -ENOMEM;
> +	}
> +
> +	rc = access(path, F_OK);
> +	if (rc) {
> +		err(ctx, "failed to access %s: %s\n", path, strerror(errno));
> +		free(path);
> +		return -errno;
> +	}
> +
> +	len = snprintf(buf, sizeof(buf), "0x%x\n", error);
> +	if (len >= sizeof(buf)) {
> +		err(ctx, "%s: buffer too small\n", cxl_dport_get_devname(dport));
> +		free(path);
> +		return -ENOMEM;
> +	}
> +
> +	rc = sysfs_write_attr(ctx, path, buf);
> +	if (rc) {
> +		err(ctx, "failed to write %s: %s\n", path, strerror(-rc));
> +		free(path);
> +		return -errno;
> +	}
> +
> +	free(path);
> +	return 0;
> +}
> +
>  static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)
>  {
>  	const char *devname = devpath_to_devname(cxlbus_base);
> diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
> index 36a93c3..c683b83 100644
> --- a/cxl/lib/libcxl.sym
> +++ b/cxl/lib/libcxl.sym
> @@ -304,4 +304,9 @@ global:
>  LIBCXL_11 {
>  global:
>  	cxl_region_get_extended_linear_cache_size;
> +	cxl_protocol_error_get_first;
> +	cxl_protocol_error_get_next;
> +	cxl_protocol_error_get_num;
> +	cxl_protocol_error_get_str;
> +	cxl_dport_protocol_error_inject;
>  } LIBCXL_10;
> diff --git a/cxl/lib/private.h b/cxl/lib/private.h
> index 542cdb7..582eebf 100644
> --- a/cxl/lib/private.h
> +++ b/cxl/lib/private.h
> @@ -108,6 +108,20 @@ struct cxl_port {
>  	struct list_head dports;
>  };
>  
> +struct cxl_protocol_error {
> +	unsigned int num;
> +	const char *string;
> +	struct cxl_ctx *ctx;
> +	struct list_node list;
> +};
> +
> +#define CXL_PROTOCOL_ERROR(n, str)	\
> +	((struct cxl_protocol_error){	\
> +		.num = (n),		\
> +		.string = (str),	\
> +		.ctx = NULL,		\
> +	})
> +
>  struct cxl_bus {
>  	struct cxl_port port;
>  };
> diff --git a/cxl/libcxl.h b/cxl/libcxl.h
> index 9371aac..faef62e 100644
> --- a/cxl/libcxl.h
> +++ b/cxl/libcxl.h
> @@ -498,6 +498,19 @@ int cxl_cmd_alert_config_set_enable_alert_actions(struct cxl_cmd *cmd,
>  						  int enable);
>  struct cxl_cmd *cxl_cmd_new_set_alert_config(struct cxl_memdev *memdev);
>  
> +struct cxl_protocol_error;
> +struct cxl_protocol_error *cxl_protocol_error_get_first(struct cxl_ctx *ctx);
> +struct cxl_protocol_error *
> +cxl_protocol_error_get_next(struct cxl_protocol_error *perror);
> +unsigned int cxl_protocol_error_get_num(struct cxl_protocol_error *perror);
> +const char *cxl_protocol_error_get_str(struct cxl_protocol_error *perror);
> +int cxl_dport_protocol_error_inject(struct cxl_dport *dport,
> +				    unsigned int error);
> +
> +#define cxl_protocol_error_foreach(ctx, perror)				       \
> +	for (perror = cxl_protocol_error_get_first(ctx); perror != NULL;       \
> +	     perror = cxl_protocol_error_get_next(perror))
> +
>  #ifdef __cplusplus
>  } /* extern "C" */
>  #endif


  reply	other threads:[~2026-01-09 17:54 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-09 16:07 [ndctl PATCH v6 0/7] Add error injection support Ben Cheatham
2026-01-09 16:07 ` [PATCH 1/7] libcxl: Add debugfs path to CXL context Ben Cheatham
2026-01-09 17:43   ` Dave Jiang
2026-01-09 16:07 ` [PATCH 2/7] libcxl: Add CXL protocol errors Ben Cheatham
2026-01-09 17:54   ` Dave Jiang [this message]
2026-01-12 17:20     ` Cheatham, Benjamin
2026-01-09 16:07 ` [PATCH 3/7] libcxl: Add poison injection support Ben Cheatham
2026-01-09 18:03   ` Dave Jiang
2026-01-12 17:20     ` Cheatham, Benjamin
2026-01-09 16:07 ` [PATCH 4/7] cxl: Add inject-error command Ben Cheatham
2026-01-09 21:53   ` Dave Jiang
2026-01-12 17:20     ` Cheatham, Benjamin
2026-01-09 16:07 ` [PATCH 5/7] cxl: Add clear-error command Ben Cheatham
2026-01-09 22:12   ` Dave Jiang
2026-01-09 16:07 ` [PATCH 6/7] cxl/list: Add injectable errors in output Ben Cheatham
2026-01-09 22:17   ` Dave Jiang
2026-01-09 16:07 ` [PATCH 7/7] Documentation: Add docs for inject/clear-error commands Ben Cheatham
2026-01-09 22:25   ` Dave Jiang
  -- strict thread matches above, loose matches on Subject: below --
2026-01-22 20:37 [ndctl PATCH v7 0/7] Add error injection support Ben Cheatham
2026-01-22 20:37 ` [PATCH 2/7] libcxl: Add CXL protocol errors Ben Cheatham

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c6f4f05b-b1b8-4b2b-b9d8-27be52b3e549@intel.com \
    --to=dave.jiang@intel.com \
    --cc=Benjamin.Cheatham@amd.com \
    --cc=alison.schofield@intel.com \
    --cc=linux-cxl@vger.kernel.org \
    --cc=nvdimm@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox