#3 71.1-8.1: Sync c9 updates and latest elake patches
Merged 9 months ago by anitazha. Opened 9 months ago by anitazha.
rpms/ anitazha/ndctl c8s-sig-hyperscale  into  c8s-sig-hyperscale

@@ -0,0 +1,51 @@ 

+ From ee7fabed859d07809dc3cfe6b23b7ad3b0c6cd73 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Tue, 12 Jan 2021 23:14:58 -0800

+ Subject: [PATCH 003/217] ndctl/test: Fix btt expect table compile warning

+ 

+ ../test/libndctl.c:989:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]

+   989 |  unsigned long long expect_table[][2] = {

+       |  ^~~~~~~~

+ 

+ ...just move the declaration a few lines up.

+ 

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/161052209839.1804207.11951679046842122849.stgit@dwillia2-desk3.amr.corp.intel.com

+ ---

+  test/libndctl.c | 12 ++++++------

+  1 file changed, 6 insertions(+), 6 deletions(-)

+ 

+ diff --git a/test/libndctl.c b/test/libndctl.c

+ index 24d72b3..fc65149 100644

+ --- a/test/libndctl.c

+ +++ b/test/libndctl.c

+ @@ -980,12 +980,6 @@ static int check_btt_size(struct ndctl_btt *btt)

+  	struct ndctl_ctx *ctx = ndctl_btt_get_ctx(btt);

+  	struct ndctl_test *test = ndctl_get_private_data(ctx);

+  	struct ndctl_namespace *ndns = ndctl_btt_get_namespace(btt);

+ -

+ -	if (!ndns)

+ -		return -ENXIO;

+ -

+ -	ns_size = ndctl_namespace_get_size(ndns);

+ -	sect_size = ndctl_btt_get_sector_size(btt);

+  	unsigned long long expect_table[][2] = {

+  		[0] = {

+  			[0] = 0x11b5400,

+ @@ -1001,6 +995,12 @@ static int check_btt_size(struct ndctl_btt *btt)

+  		},

+  	};

+  

+ +	if (!ndns)

+ +		return -ENXIO;

+ +

+ +	ns_size = ndctl_namespace_get_size(ndns);

+ +	sect_size = ndctl_btt_get_sector_size(btt);

+ +

+  	if (sect_size >= SZ_4K)

+  		sect_select = 1;

+  	else if (sect_size >= 512)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,57 @@ 

+ From ff4030e88da2cdcaf52c0d7457cd30264ea8915b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Tue, 12 Jan 2021 23:15:03 -0800

+ Subject: [PATCH 004/217] ndctl/test: Cleanup unnecessary out label

+ 

+ There are no cleanup actions to take in test_dax_remap(), and it is already

+ inconsistent for having a single return point, so remove the out label.

+ 

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/161052210395.1804207.7318263492906073721.stgit@dwillia2-desk3.amr.corp.intel.com

+ ---

+  test/dax-pmd.c | 12 ++++--------

+  1 file changed, 4 insertions(+), 8 deletions(-)

+ 

+ diff --git a/test/dax-pmd.c b/test/dax-pmd.c

+ index 401826d..b1251db 100644

+ --- a/test/dax-pmd.c

+ +++ b/test/dax-pmd.c

+ @@ -83,20 +83,18 @@ int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, voi

+  	act.sa_flags = SA_SIGINFO;

+  	if (sigaction(SIGBUS, &act, 0)) {

+  		perror("sigaction");

+ -		rc = EXIT_FAILURE;

+ -		goto out;

+ +		return EXIT_FAILURE;

+  	}

+  

+  	/* test fault after device-dax instance disabled */

+  	if (sigsetjmp(sj_env, 1)) {

+  		if (!fsdax && align > SZ_4K) {

+  			fprintf(stderr, "got expected SIGBUS after mremap() of device-dax\n");

+ -			rc = 0;

+ +			return 0;

+  		} else {

+  			fprintf(stderr, "unpexpected SIGBUS after mremap()\n");

+ -			rc = -EIO;

+ +			return -EIO;

+  		}

+ -		goto out;

+  	}

+  

+  	*(int *) anon = 0xAA;

+ @@ -107,9 +105,7 @@ int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, voi

+  		return -ENXIO;

+  	}

+  

+ -	rc = 0;

+ -out:

+ -	return rc;

+ +	return 0;

+  }

+  

+  int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t offset)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,40 @@ 

+ From 6694afe31dd67d186199a58d2252be5ea3472692 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Tue, 12 Jan 2021 23:15:09 -0800

+ Subject: [PATCH 005/217] ndctl/test: Fix device-dax mremap() test

+ 

+ The test_dax_remap() test is a regression check for mishandling of mremap()

+ in the presence of pmd_devmap(). My understanding is that it was a fuzzing

+ condition not something an application would want to do in practice.

+ 

+ On recent kernels with commit 73d5e0629919 ("mremap: check if it's possible

+ to split original vma"), the test fails for device-dax. That seems an

+ equally acceptable result of attempting this remap, so update the test

+ rather than ask the kernel to preserve the old behaviour.

+ 

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/161052210936.1804207.17896246772670985157.stgit@dwillia2-desk3.amr.corp.intel.com

+ ---

+  test/dax-pmd.c | 5 +++++

+  1 file changed, 5 insertions(+)

+ 

+ diff --git a/test/dax-pmd.c b/test/dax-pmd.c

+ index b1251db..7648e34 100644

+ --- a/test/dax-pmd.c

+ +++ b/test/dax-pmd.c

+ @@ -69,6 +69,11 @@ int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, voi

+  

+  	remap = mremap(addr, REMAP_SIZE, REMAP_SIZE, MREMAP_MAYMOVE|MREMAP_FIXED, anon);

+  

+ +	if (remap == MAP_FAILED) {

+ +		fprintf(stderr, "%s: mremap failed, that's ok too\n", __func__);

+ +		return 0;

+ +	}

+ +

+  	if (remap != anon) {

+  		rc = -ENXIO;

+  		perror("mremap");

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,134 @@ 

+ From 940acf65a61595e8c0db3aebe1c74307acbbef68 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Tue, 12 Jan 2021 23:15:14 -0800

+ Subject: [PATCH 006/217] ndctl/test: Exercise soft_offline_page() corner cases

+ 

+ Test soft-offline injection into PMEM namespace metadata and user mapped

+ space. Both attempts should fail on kernels with a pfn_to_online_page()

+ implementation that considers subsection ZONE_DEVICE ranges.

+ 

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/161052211455.1804207.13884321454837200896.stgit@dwillia2-desk3.amr.corp.intel.com

+ ---

+  test/dax-poison.c | 19 +++++++++++++++++++

+  test/device-dax.c | 45 +++++++++++++++++++++++++++++++++++++++++++++

+  2 files changed, 64 insertions(+)

+ 

+ diff --git a/test/dax-poison.c b/test/dax-poison.c

+ index a4ef12e..4e09761 100644

+ --- a/test/dax-poison.c

+ +++ b/test/dax-poison.c

+ @@ -5,6 +5,7 @@

+  #include <signal.h>

+  #include <setjmp.h>

+  #include <sys/mman.h>

+ +#include <linux/mman.h>

+  #include <fcntl.h>

+  #include <string.h>

+  #include <errno.h>

+ @@ -49,6 +50,7 @@ int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,

+  	unsigned char *addr = MAP_FAILED;

+  	struct sigaction act;

+  	unsigned x = x;

+ +	FILE *smaps;

+  	void *buf;

+  	int rc;

+  

+ @@ -94,6 +96,9 @@ int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,

+  		goto out;

+  	}

+  

+ +	fprintf(stderr, "%s: mmap got %p align: %ld offset: %zd\n",

+ +			__func__, addr, align, offset);

+ +

+  	if (sigsetjmp(sj_env, 1)) {

+  		if (sig_mcerr_ar) {

+  			fprintf(stderr, "madvise triggered 'action required' sigbus\n");

+ @@ -104,6 +109,20 @@ int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,

+  		}

+  	}

+  

+ +	rc = madvise(addr + align / 2, 4096, MADV_SOFT_OFFLINE);

+ +	if (rc == 0) {

+ +		fprintf(stderr, "softoffline should always fail for dax\n");

+ +		smaps = fopen("/proc/self/smaps", "r");

+ +		do {

+ +			rc = fread(buf, 1, 4096, smaps);

+ +			fwrite(buf, 1, rc, stderr);

+ +		} while (rc);

+ +		fclose(smaps);

+ +		fail();

+ +		rc = -ENXIO;

+ +		goto out;

+ +	}

+ +

+  	rc = madvise(addr + align / 2, 4096, MADV_HWPOISON);

+  	if (rc) {

+  		fail();

+ diff --git a/test/device-dax.c b/test/device-dax.c

+ index 5f0da29..aad8fa5 100644

+ --- a/test/device-dax.c

+ +++ b/test/device-dax.c

+ @@ -128,6 +128,44 @@ static int verify_data(struct daxctl_dev *dev, char *dax_buf,

+  	return 0;

+  }

+  

+ +static int test_dax_soft_offline(struct ndctl_test *test, struct ndctl_namespace *ndns)

+ +{

+ +	unsigned long long resource = ndctl_namespace_get_resource(ndns);

+ +	int fd, rc;

+ +	char *buf;

+ +

+ +	if (resource == ULLONG_MAX) {

+ +		fprintf(stderr, "failed to get resource: %s\n",

+ +				ndctl_namespace_get_devname(ndns));

+ +		return -ENXIO;

+ +	}

+ +

+ +	fd = open("/sys/devices/system/memory/soft_offline_page", O_WRONLY);

+ +	if (fd < 0) {

+ +		fprintf(stderr, "failed to open soft_offline_page\n");

+ +		return -ENOENT;

+ +	}

+ +

+ +	rc = asprintf(&buf, "%#llx\n", resource);

+ +	if (rc < 0) {

+ +		fprintf(stderr, "failed to alloc resource\n");

+ +		close(fd);

+ +		return -ENOMEM;

+ +	}

+ +

+ +	fprintf(stderr, "%s: try to offline page @%#llx\n", __func__, resource);

+ +	rc = write(fd, buf, rc);

+ +	free(buf);

+ +	close(fd);

+ +

+ +	if (rc >= 0) {

+ +		fprintf(stderr, "%s: should have failed\n", __func__);

+ +		return -ENXIO;

+ +	}

+ +

+ +	return 0;

+ +}

+ +

+  static int __test_device_dax(unsigned long align, int loglevel,

+  		struct ndctl_test *test, struct ndctl_ctx *ctx)

+  {

+ @@ -278,6 +316,13 @@ static int __test_device_dax(unsigned long align, int loglevel,

+  			goto out;

+  		}

+  

+ +		rc = test_dax_soft_offline(test, ndns);

+ +		if (rc) {

+ +			fprintf(stderr, "%s: failed dax soft offline\n",

+ +					ndctl_namespace_get_devname(ndns));

+ +			goto out;

+ +		}

+ +

+  		rc = test_dax_poison(test, fd, align, NULL, 0, devdax);

+  		if (rc) {

+  			fprintf(stderr, "%s: failed dax poison\n",

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,73 @@ 

+ From 11357d68b77392e4360ae2824e75bf8397a84885 Mon Sep 17 00:00:00 2001

+ From: Redhairer Li <redhairer.li@intel.com>

+ Date: Sat, 9 Jan 2021 23:36:33 +0800

+ Subject: [PATCH 007/217] msft: Add xlat_firmware_status for JEDEC Byte

+  Addressable Energy Backed DSM

+ 

+ Translate the status codes of the result of JEDEC Byte Addressable Energy Backed

+ DSM to generic errno style error codes.

+ 

+ Signed-off-by: Li Redhairer <redhairer.li@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/20210109153633.8493-1-redhairer.li@intel.com

+ ---

+  ndctl/lib/msft.c | 22 ++++++++++++++++++++++

+  ndctl/lib/msft.h |  6 ++++++

+  2 files changed, 28 insertions(+)

+ 

+ diff --git a/ndctl/lib/msft.c b/ndctl/lib/msft.c

+ index 145872c..3112799 100644

+ --- a/ndctl/lib/msft.c

+ +++ b/ndctl/lib/msft.c

+ @@ -149,10 +149,32 @@ static unsigned int msft_cmd_smart_get_life_used(struct ndctl_cmd *cmd)

+  	return 100 - CMD_MSFT_SMART(cmd)->nvm_lifetime;

+  }

+  

+ +static int msft_cmd_xlat_firmware_status(struct ndctl_cmd *cmd)

+ +{

+ +	unsigned int status;

+ +

+ +	status = cmd->get_firmware_status(cmd) & NDN_MSFT_STATUS_MASK;

+ +

+ +	/* Common statuses */

+ +	switch (status) {

+ +	case NDN_MSFT_STATUS_SUCCESS:

+ +		return 0;

+ +	case NDN_MSFT_STATUS_NOTSUPP:

+ +		return -EOPNOTSUPP;

+ +	case NDN_MSFT_STATUS_INVALPARM:

+ +		return -EINVAL;

+ +	case NDN_MSFT_STATUS_I2CERR:

+ +		return -EIO;

+ +	}

+ +

+ +	return -ENOMSG;

+ +}

+ +

+  struct ndctl_dimm_ops * const msft_dimm_ops = &(struct ndctl_dimm_ops) {

+  	.new_smart = msft_dimm_cmd_new_smart,

+  	.smart_get_flags = msft_cmd_smart_get_flags,

+  	.smart_get_health = msft_cmd_smart_get_health,

+  	.smart_get_media_temperature = msft_cmd_smart_get_media_temperature,

+  	.smart_get_life_used = msft_cmd_smart_get_life_used,

+ +	.xlat_firmware_status = msft_cmd_xlat_firmware_status,

+  };

+ diff --git a/ndctl/lib/msft.h b/ndctl/lib/msft.h

+ index 7cfd26f..978cc11 100644

+ --- a/ndctl/lib/msft.h

+ +++ b/ndctl/lib/msft.h

+ @@ -50,4 +50,10 @@ struct ndn_pkg_msft {

+  	union ndn_msft_cmd	u;

+  } __attribute__((packed));

+  

+ +#define NDN_MSFT_STATUS_MASK		0xffff

+ +#define NDN_MSFT_STATUS_SUCCESS	0

+ +#define NDN_MSFT_STATUS_NOTSUPP	1

+ +#define NDN_MSFT_STATUS_INVALPARM	2

+ +#define NDN_MSFT_STATUS_I2CERR		3

+ +

+  #endif /* __NDCTL_MSFT_H__ */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,140 @@ 

+ From fe626a8a8a1b1bc94ea95c693ec672109909e3dc Mon Sep 17 00:00:00 2001

+ From: Redhairer Li <redhairer.li@intel.com>

+ Date: Thu, 28 Jan 2021 22:03:39 +0800

+ Subject: [PATCH 008/217] ndctl/namespace: Fix disable-namespace accounting

+  relative to seed devices

+ 

+ Seed namespaces are included in "ndctl disable-namespace all". However

+ since the user never "creates" them it is surprising to see

+ "disable-namespace" report 1 more namespace relative to the number that

+ have been created. Catch attempts to disable a zero-sized namespace:

+ 

+ Before:

+ {

+   "dev":"namespace1.0",

+   "size":"492.00 MiB (515.90 MB)",

+   "blockdev":"pmem1"

+ }

+ {

+   "dev":"namespace1.1",

+   "size":"492.00 MiB (515.90 MB)",

+   "blockdev":"pmem1.1"

+ }

+ {

+   "dev":"namespace1.2",

+   "size":"492.00 MiB (515.90 MB)",

+   "blockdev":"pmem1.2"

+ }

+ disabled 4 namespaces

+ 

+ After:

+ {

+   "dev":"namespace1.0",

+   "size":"492.00 MiB (515.90 MB)",

+   "blockdev":"pmem1"

+ }

+ {

+   "dev":"namespace1.3",

+   "size":"492.00 MiB (515.90 MB)",

+   "blockdev":"pmem1.3"

+ }

+ {

+   "dev":"namespace1.1",

+   "size":"492.00 MiB (515.90 MB)",

+   "blockdev":"pmem1.1"

+ }

+ disabled 3 namespaces

+ 

+ Signed-off-by: Redhairer Li <redhairer.li@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/linux-nvdimm/20210128140339.3080-1-redhairer.li@intel.com/

+ ---

+  ndctl/lib/libndctl.c | 10 ++++++++--

+  ndctl/namespace.c    |  8 ++++----

+  ndctl/region.c       |  2 +-

+  3 files changed, 13 insertions(+), 7 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 36fb6fe..2f6d806 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -4602,6 +4602,7 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)

+  	const char *bdev = NULL;

+  	char path[50];

+  	int fd;

+ +	unsigned long long size = ndctl_namespace_get_size(ndns);

+  

+  	if (pfn && ndctl_pfn_is_enabled(pfn))

+  		bdev = ndctl_pfn_get_block_device(pfn);

+ @@ -4631,8 +4632,13 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)

+  					devname, bdev, strerror(errno));

+  			return -errno;

+  		}

+ -	} else

+ -		ndctl_namespace_disable_invalidate(ndns);

+ +	} else {

+ +		if (size == 0)

+ +			/* No disable necessary due to no capacity allocated */

+ +			return 1;

+ +		else

+ +			ndctl_namespace_disable_invalidate(ndns);

+ +	}

+  

+  	return 0;

+  }

+ diff --git a/ndctl/namespace.c b/ndctl/namespace.c

+ index 0c8df9f..1feb74d 100644

+ --- a/ndctl/namespace.c

+ +++ b/ndctl/namespace.c

+ @@ -1125,7 +1125,7 @@ static int namespace_prep_reconfig(struct ndctl_region *region,

+  	}

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc)

+ +	if (rc < 0)

+  		return rc;

+  

+  	ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_RAW);

+ @@ -1431,7 +1431,7 @@ static int dax_clear_badblocks(struct ndctl_dax *dax)

+  		return -ENXIO;

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc) {

+ +	if (rc < 0) {

+  		error("%s: unable to disable namespace: %s\n", devname,

+  			strerror(-rc));

+  		return rc;

+ @@ -1455,7 +1455,7 @@ static int pfn_clear_badblocks(struct ndctl_pfn *pfn)

+  		return -ENXIO;

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc) {

+ +	if (rc < 0) {

+  		error("%s: unable to disable namespace: %s\n", devname,

+  			strerror(-rc));

+  		return rc;

+ @@ -1478,7 +1478,7 @@ static int raw_clear_badblocks(struct ndctl_namespace *ndns)

+  		return -ENXIO;

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc) {

+ +	if (rc < 0) {

+  		error("%s: unable to disable namespace: %s\n", devname,

+  			strerror(-rc));

+  		return rc;

+ diff --git a/ndctl/region.c b/ndctl/region.c

+ index 3edb9b3..4552c4a 100644

+ --- a/ndctl/region.c

+ +++ b/ndctl/region.c

+ @@ -70,7 +70,7 @@ static int region_action(struct ndctl_region *region, enum device_action mode)

+  	case ACTION_DISABLE:

+  		ndctl_namespace_foreach(region, ndns) {

+  			rc = ndctl_namespace_disable_safe(ndns);

+ -			if (rc)

+ +			if (rc < 0)

+  				return rc;

+  		}

+  		rc = ndctl_region_disable_invalidate(region);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,50 @@ 

+ From fb13dfb8d84c4f0a749665c8f07179450b199f3e Mon Sep 17 00:00:00 2001

+ From: Jeff Moyer <jmoyer@redhat.com>

+ Date: Tue, 9 Feb 2021 16:51:53 -0500

+ Subject: [PATCH 009/217] zero_info_block: skip seed devices

+ 

+ Currently, ndctl destroy-namespace -f all will output errors of the

+ form:

+ 

+   Error: destroy namespace: namespace0.0 failed to enable for zeroing, continuing

+ 

+ for any zero-sized namespace.  That particular namespace looks like this:

+ 

+   {

+     "dev":"namespace0.0",

+     "mode":"raw",

+     "size":0,

+     "uuid":"00000000-0000-0000-0000-000000000000",

+     "sector_size":512,

+     "state":"disabled"

+   }

+ 

+ This patch skips over namespaces with size=0 when zeroing out info

+ blocks.

+ 

+ Fixes: 46654c2d60b70 ("ndctl/namespace: Always zero info-blocks")

+ Reported-by: Zhang Yi <yizhan@redhat.com>

+ Signed-off-by: Jeff Moyer <jmoyer@redhat.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/x49r1lohpty.fsf@segfault.boston.devel.redhat.com

+ ---

+  ndctl/namespace.c | 3 +++

+  1 file changed, 3 insertions(+)

+ 

+ diff --git a/ndctl/namespace.c b/ndctl/namespace.c

+ index 1feb74d..1e8a2cd 100644

+ --- a/ndctl/namespace.c

+ +++ b/ndctl/namespace.c

+ @@ -1052,6 +1052,9 @@ static int zero_info_block(struct ndctl_namespace *ndns)

+  	void *buf = NULL, *read_buf = NULL;

+  	char path[50];

+  

+ +	if (ndctl_namespace_get_size(ndns) == 0)

+ +		return 1;

+ +

+  	ndctl_namespace_set_raw_mode(ndns, 1);

+  	rc = ndctl_namespace_enable(ndns);

+  	if (rc < 0) {

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,51 @@ 

+ From 5d0d4dc5ae1de82de92212c98297b24fbba09227 Mon Sep 17 00:00:00 2001

+ From: QI Fuli <qi.fuli@fujitsu.com>

+ Date: Tue, 2 Feb 2021 22:02:06 +0900

+ Subject: [PATCH 010/217] ndctl: update .gitignore

+ 

+ Add Documentation/ndctl/attrs.adoc and *.lo to .gitignore.

+ 

+ Signed-off-by: QI Fuli <qi.fuli@fujitsu.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/20210202130206.3761-1-qi.fuli@fujitsu.com

+ ---

+  .gitignore | 5 ++---

+  1 file changed, 2 insertions(+), 3 deletions(-)

+ 

+ diff --git a/.gitignore b/.gitignore

+ index 3ef9ff7..53512b2 100644

+ --- a/.gitignore

+ +++ b/.gitignore

+ @@ -1,4 +1,5 @@

+  *.o

+ +*.lo

+  *.xml

+  .deps/

+  .libs/

+ @@ -15,13 +16,13 @@ Makefile.in

+  *.1

+  Documentation/daxctl/asciidoc.conf

+  Documentation/ndctl/asciidoc.conf

+ +Documentation/ndctl/attrs.adoc

+  Documentation/daxctl/asciidoctor-extensions.rb

+  Documentation/ndctl/asciidoctor-extensions.rb

+  .dirstamp

+  daxctl/config.h

+  daxctl/daxctl

+  daxctl/lib/libdaxctl.la

+ -daxctl/lib/libdaxctl.lo

+  daxctl/lib/libdaxctl.pc

+  *.a

+  ndctl/config.h

+ @@ -29,8 +30,6 @@ ndctl/lib/libndctl.pc

+  ndctl/ndctl

+  rhel/

+  sles/ndctl.spec

+ -util/log.lo

+ -util/sysfs.lo

+  version.m4

+  *.swp

+  cscope.files

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,127 @@ 

+ From 7ce2fddfa3f108036a2d81de4d2e66ac29e4631e Mon Sep 17 00:00:00 2001

+ From: QI Fuli <qi.fuli@fujitsu.com>

+ Date: Wed, 3 Feb 2021 22:21:08 +0900

+ Subject: [PATCH 011/217] ndctl/test: add checking the presence of jq command

+  ahead

+ 

+ Due to the lack of jq command, the result of the test will be 'fail'.

+ This patch adds checking the presence of jq commmand ahead.

+ If there is no jq command in the system, the test will be marked as 'skip'.

+ 

+ Signed-off-by: QI Fuli <qi.fuli@fujitsu.com>

+ Link: https://github.com/pmem/ndctl/issues/141

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/20210203132108.6246-1-qi.fuli@fujitsu.com

+ ---

+  test/daxdev-errors.sh           | 1 +

+  test/inject-error.sh            | 2 ++

+  test/inject-smart.sh            | 1 +

+  test/label-compat.sh            | 1 +

+  test/max_available_extent_ns.sh | 1 +

+  test/monitor.sh                 | 2 ++

+  test/multi-dax.sh               | 1 +

+  test/sector-mode.sh             | 2 ++

+  8 files changed, 11 insertions(+)

+ 

+ diff --git a/test/daxdev-errors.sh b/test/daxdev-errors.sh

+ index 6281f32..9547d78 100755

+ --- a/test/daxdev-errors.sh

+ +++ b/test/daxdev-errors.sh

+ @@ -9,6 +9,7 @@ rc=77

+  . $(dirname $0)/common

+  

+  check_min_kver "4.12" || do_skip "lacks dax dev error handling"

+ +check_prereq "jq"

+  

+  trap 'err $LINENO' ERR

+  

+ diff --git a/test/inject-error.sh b/test/inject-error.sh

+ index c636033..7d0b826 100755

+ --- a/test/inject-error.sh

+ +++ b/test/inject-error.sh

+ @@ -11,6 +11,8 @@ err_count=8

+  

+  . $(dirname $0)/common

+  

+ +check_prereq "jq"

+ +

+  trap 'err $LINENO' ERR

+  

+  # sample json:

+ diff --git a/test/inject-smart.sh b/test/inject-smart.sh

+ index 94705df..4ca83b8 100755

+ --- a/test/inject-smart.sh

+ +++ b/test/inject-smart.sh

+ @@ -166,6 +166,7 @@ do_tests()

+  }

+  

+  check_min_kver "4.19" || do_skip "kernel $KVER may not support smart (un)injection"

+ +check_prereq "jq"

+  modprobe nfit_test

+  rc=1

+  

+ diff --git a/test/label-compat.sh b/test/label-compat.sh

+ index 340b93d..8ab2858 100755

+ --- a/test/label-compat.sh

+ +++ b/test/label-compat.sh

+ @@ -10,6 +10,7 @@ BASE=$(dirname $0)

+  . $BASE/common

+  

+  check_min_kver "4.11" || do_skip "may not provide reliable isetcookie values"

+ +check_prereq "jq"

+  

+  trap 'err $LINENO' ERR

+  

+ diff --git a/test/max_available_extent_ns.sh b/test/max_available_extent_ns.sh

+ index 14d741d..343f3c9 100755

+ --- a/test/max_available_extent_ns.sh

+ +++ b/test/max_available_extent_ns.sh

+ @@ -9,6 +9,7 @@ rc=77

+  trap 'err $LINENO' ERR

+  

+  check_min_kver "4.19" || do_skip "kernel $KVER may not support max_available_size"

+ +check_prereq "jq"

+  

+  init()

+  {

+ diff --git a/test/monitor.sh b/test/monitor.sh

+ index cdab5e1..28c5541 100755

+ --- a/test/monitor.sh

+ +++ b/test/monitor.sh

+ @@ -13,6 +13,8 @@ smart_supported_bus=""

+  

+  . $(dirname $0)/common

+  

+ +check_prereq "jq"

+ +

+  trap 'err $LINENO' ERR

+  

+  check_min_kver "4.15" || do_skip "kernel $KVER may not support monitor service"

+ diff --git a/test/multi-dax.sh b/test/multi-dax.sh

+ index e932569..8496619 100755

+ --- a/test/multi-dax.sh

+ +++ b/test/multi-dax.sh

+ @@ -9,6 +9,7 @@ rc=77

+  . $(dirname $0)/common

+  

+  check_min_kver "4.13" || do_skip "may lack multi-dax support"

+ +check_prereq "jq"

+  

+  trap 'err $LINENO' ERR

+  

+ diff --git a/test/sector-mode.sh b/test/sector-mode.sh

+ index dd7013e..54fa806 100755

+ --- a/test/sector-mode.sh

+ +++ b/test/sector-mode.sh

+ @@ -6,6 +6,8 @@ rc=77

+  

+  . $(dirname $0)/common

+  

+ +check_prereq "jq"

+ +

+  set -e

+  trap 'err $LINENO' ERR

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,78 @@ 

+ From c81fa15bafb1295aaa7d7f09500c3fbdd68b0011 Mon Sep 17 00:00:00 2001

+ From: "Tsaur, Erwin" <erwin.tsaur@intel.com>

+ Date: Thu, 4 Mar 2021 17:18:04 -0800

+ Subject: [PATCH 012/217] Expose ndctl_bus_nfit_translate_spa as a public

+  function.

+ 

+ The motivation is to allow access to ACPI defined NVDIMM Root Device

+ _DSM Function Index 5(Translate SPA).  The rest of the _DSM functions,

+ which are mostly ARS related, are already public.

+ 

+ Basically move ndctl_bus_nfit_translate_spa declaration from private.h

+ to libndctl.h.

+ 

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: "Tsaur, Erwin" <erwin.tsaur@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/20210305011804.3573-1-erwin.tsaur@intel.com

+ ---

+  ndctl/lib/libndctl.sym | 4 ++++

+  ndctl/lib/nfit.c       | 2 +-

+  ndctl/lib/private.h    | 2 --

+  ndctl/libndctl.h       | 2 ++

+  4 files changed, 7 insertions(+), 3 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym

+ index 0a82616..58afb74 100644

+ --- a/ndctl/lib/libndctl.sym

+ +++ b/ndctl/lib/libndctl.sym

+ @@ -451,3 +451,7 @@ LIBNDCTL_25 {

+  	ndctl_bus_clear_fw_activate_nosuspend;

+  	ndctl_bus_activate_firmware;

+  } LIBNDCTL_24;

+ +

+ +LIBNDCTL_26 {

+ +	ndctl_bus_nfit_translate_spa;

+ +} LIBNDCTL_25;

+ diff --git a/ndctl/lib/nfit.c b/ndctl/lib/nfit.c

+ index 6f68fcf..d85682f 100644

+ --- a/ndctl/lib/nfit.c

+ +++ b/ndctl/lib/nfit.c

+ @@ -114,7 +114,7 @@ static int is_valid_spa(struct ndctl_bus *bus, unsigned long long spa)

+   *

+   * If success, returns zero, store dimm's @handle, and @dpa.

+   */

+ -int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus,

+ +NDCTL_EXPORT int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus,

+  	unsigned long long address, unsigned int *handle, unsigned long long *dpa)

+  {

+  

+ diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h

+ index ede1300..8f4510e 100644

+ --- a/ndctl/lib/private.h

+ +++ b/ndctl/lib/private.h

+ @@ -370,8 +370,6 @@ static inline int check_kmod(struct kmod_ctx *kmod_ctx)

+  	return kmod_ctx ? 0 : -ENXIO;

+  }

+  

+ -int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus, unsigned long long addr,

+ -		unsigned int *handle, unsigned long long *dpa);

+  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj(struct ndctl_bus *bus);

+  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus);

+  struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_stat(struct ndctl_bus *bus,

+ diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h

+ index 60e1288..87d07b7 100644

+ --- a/ndctl/libndctl.h

+ +++ b/ndctl/libndctl.h

+ @@ -152,6 +152,8 @@ int ndctl_bus_clear_fw_activate_noidle(struct ndctl_bus *bus);

+  int ndctl_bus_set_fw_activate_nosuspend(struct ndctl_bus *bus);

+  int ndctl_bus_clear_fw_activate_nosuspend(struct ndctl_bus *bus);

+  int ndctl_bus_activate_firmware(struct ndctl_bus *bus, enum ndctl_fwa_method method);

+ +int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus, unsigned long long addr,

+ +		unsigned int *handle, unsigned long long *dpa);

+  

+  struct ndctl_dimm;

+  struct ndctl_dimm *ndctl_dimm_get_first(struct ndctl_bus *bus);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,72 @@ 

+ From 43e48c0d2f271cba4237f6eefc3e4912a74c102b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Tue, 9 Mar 2021 22:09:49 -0800

+ Subject: [PATCH 013/217] test/libndctl: Use ndctl_region_set_ro() to change

+  disk read-only state

+ 

+ Kernel commit 52f019d43c22 ("block: add a hard-readonly flag to struct

+ gendisk") broke the read-only management test, by fixing the broken

+ behavior that BLKROSET could make a block device read-write even when the

+ disk is read-only. The fix [1] propagates changes of the region

+ read-only state to the underlying disk. Add ndctl_region_set_ro() ahead of

+ BLKROSET so that BLKROSET does not conflict the block_device state with the

+ disk state.

+ 

+ [1]: http://lore.kernel.org/r/161534060720.528671.2341213328968989192.stgit@dwillia2-desk3.amr.corp.intel.com

+ 

+ Reported-by: kernel test robot <lkp@intel.com>

+ Reported-by: Vishal Verma <vishal.l.verma@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://lore.kernel.org/r/161535658913.530219.12194565167385663385.stgit@dwillia2-desk3.amr.corp.intel.com

+ ---

+  test/libndctl.c | 18 +++++++++++++++++-

+  1 file changed, 17 insertions(+), 1 deletion(-)

+ 

+ diff --git a/test/libndctl.c b/test/libndctl.c

+ index fc65149..c42f785 100644

+ --- a/test/libndctl.c

+ +++ b/test/libndctl.c

+ @@ -1541,6 +1541,7 @@ static int validate_bdev(const char *devname, struct ndctl_btt *btt,

+  		struct ndctl_pfn *pfn, struct ndctl_namespace *ndns,

+  		struct namespace *namespace, void *buf)

+  {

+ +	struct ndctl_region *region = ndctl_namespace_get_region(ndns);

+  	char bdevpath[50];

+  	int fd, rc, ro;

+  

+ @@ -1578,6 +1579,13 @@ static int validate_bdev(const char *devname, struct ndctl_btt *btt,

+  	}

+  

+  	ro = 0;

+ +	rc = ndctl_region_set_ro(region, ro);

+ +	if (rc < 0) {

+ +		fprintf(stderr, "%s: ndctl_region_set_ro failed\n", devname);

+ +		rc = -errno;

+ +		goto out;

+ +	}

+ +

+  	rc = ioctl(fd, BLKROSET, &ro);

+  	if (rc < 0) {

+  		fprintf(stderr, "%s: BLKROSET failed\n",

+ @@ -1605,8 +1613,16 @@ static int validate_bdev(const char *devname, struct ndctl_btt *btt,

+  		rc = -ENXIO;

+  		goto out;

+  	}

+ +

+ +	rc = ndctl_region_set_ro(region, namespace->ro);

+ +	if (rc < 0) {

+ +		fprintf(stderr, "%s: ndctl_region_set_ro reset failed\n", devname);

+ +		rc = -errno;

+ +		goto out;

+ +	}

+ +

+  	rc = 0;

+ - out:

+ +out:

+  	close(fd);

+  	return rc;

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,221 @@ 

+ From 99415dfc7c5167c49a5732f577836f68872645b2 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 24 Mar 2021 12:09:29 -0700

+ Subject: [PATCH 014/217] daxctl: fail reconfigure-device based on kernel

+  onlining policy

+ 

+ If the kernel has a policy set to auto-online any new memory blocks, we

+ know that an attempt to reconfigure a device either in ZONE_MOVABLE, or

+ with the --no-online is going to fail. While we detect this race after

+ the fact, and print a warning, that is often insufficient as the user

+ may be forced to reboot to get out of the situation, resulting in an

+ unpleasant experience.

+ 

+ Detect whether the kernel policy is set to auto-online. If so, fail

+ device reconfigure operations that we know can't be satisfied. Allow

+ for overriding this safety check via the -f (--force) option. Update the

+ man page to talk about this, and the unit test to test for an expected

+ failure by enabling auto-onlining.

+ 

+ Cc: Dave Hansen <dave.hansen@intel.com>

+ Reported-by: Chunye Xu <chunye.xu@intel.com>

+ Reported-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .../daxctl/daxctl-reconfigure-device.txt      | 12 ++++++-

+  daxctl/device.c                               | 10 ++++++

+  daxctl/lib/libdaxctl-private.h                |  1 +

+  daxctl/lib/libdaxctl.c                        | 21 +++++++++++

+  daxctl/lib/libdaxctl.sym                      |  5 +++

+  daxctl/libdaxctl.h                            |  1 +

+  test/daxctl-devices.sh                        | 36 +++++++++++++++++++

+  7 files changed, 85 insertions(+), 1 deletion(-)

+ 

+ diff --git a/Documentation/daxctl/daxctl-reconfigure-device.txt b/Documentation/daxctl/daxctl-reconfigure-device.txt

+ index ad33eda..f112b3c 100644

+ --- a/Documentation/daxctl/daxctl-reconfigure-device.txt

+ +++ b/Documentation/daxctl/daxctl-reconfigure-device.txt

+ @@ -119,6 +119,10 @@ recommended to use the --no-online option described below. This will abridge

+  the device reconfiguration operation to just hotplugging the memory, and

+  refrain from then onlining it.

+  

+ +In case daxctl detects that there is a kernel policy to auto-online blocks

+ +(via /sys/devices/system/memory/auto_online_blocks), then reconfiguring to

+ +system-ram will result in a failure. This can be overridden with '--force'.

+ +

+  OPTIONS

+  -------

+  include::region-option.txt[]

+ @@ -162,12 +166,18 @@ include::movable-options.txt[]

+  

+  -f::

+  --force::

+ -	When converting from "system-ram" mode to "devdax", it is expected

+ +	- When converting from "system-ram" mode to "devdax", it is expected

+  	that all the memory sections are first made offline. By default,

+  	daxctl won't touch online memory. However with this option, attempt

+  	to offline the memory on the NUMA node associated with the dax device

+  	before converting it back to "devdax" mode.

+  

+ +	- Additionally, if a kernel policy to auto-online blocks is detected,

+ +	reconfiguration to system-ram fails. With this option, the failure can

+ +	be overridden to allow reconfiguration regardless of kernel policy.

+ +	Doing this may result in a successful reconfiguration, but it may

+ +	not be possible to subsequently offline the memory without a reboot.

+ +

+  

+  include::human-option.txt[]

+  

+ diff --git a/daxctl/device.c b/daxctl/device.c

+ index 0721a57..a427b7d 100644

+ --- a/daxctl/device.c

+ +++ b/daxctl/device.c

+ @@ -541,8 +541,18 @@ static int disable_devdax_device(struct daxctl_dev *dev)

+  

+  static int reconfig_mode_system_ram(struct daxctl_dev *dev)

+  {

+ +	const char *devname = daxctl_dev_get_devname(dev);

+  	int rc, skip_enable = 0;

+  

+ +	if (param.no_online || !param.no_movable) {

+ +		if (!param.force && daxctl_dev_will_auto_online_memory(dev)) {

+ +			fprintf(stderr,

+ +				"%s: error: kernel policy will auto-online memory, aborting\n",

+ +				devname);

+ +			return -EBUSY;

+ +		}

+ +	}

+ +

+  	if (daxctl_dev_is_enabled(dev)) {

+  		rc = disable_devdax_device(dev);

+  		if (rc < 0)

+ diff --git a/daxctl/lib/libdaxctl-private.h b/daxctl/lib/libdaxctl-private.h

+ index af257fd..ae45311 100644

+ --- a/daxctl/lib/libdaxctl-private.h

+ +++ b/daxctl/lib/libdaxctl-private.h

+ @@ -111,6 +111,7 @@ struct daxctl_memory {

+  	char *node_path;

+  	unsigned long block_size;

+  	enum memory_zones zone;

+ +	bool auto_online;

+  };

+  

+  

+ diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c

+ index 479e8f6..879f7e6 100644

+ --- a/daxctl/lib/libdaxctl.c

+ +++ b/daxctl/lib/libdaxctl.c

+ @@ -1644,3 +1644,24 @@ DAXCTL_EXPORT int daxctl_memory_is_movable(struct daxctl_memory *mem)

+  		return rc;

+  	return (mem->zone == MEM_ZONE_MOVABLE) ? 1 : 0;

+  }

+ +

+ +DAXCTL_EXPORT int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev)

+ +{

+ +	const char *auto_path = "/sys/devices/system/memory/auto_online_blocks";

+ +	const char *devname = daxctl_dev_get_devname(dev);

+ +	struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	/*

+ +	 * If we can't read the policy for some reason, don't fail yet. Assume

+ +	 * the auto-onlining policy is absent, and carry on. If onlining blocks

+ +	 * does result in the memory being in an inconsistent state, we have a

+ +	 * check and warning for it after the fact

+ +	 */

+ +	if (sysfs_read_attr(ctx, auto_path, buf) != 0)

+ +		err(ctx, "%s: Unable to determine auto-online policy: %s\n",

+ +				devname, strerror(errno));

+ +

+ +	/* match both "online" and "online_movable" */

+ +	return !strncmp(buf, "online", 6);

+ +}

+ diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym

+ index a4e1684..892e393 100644

+ --- a/daxctl/lib/libdaxctl.sym

+ +++ b/daxctl/lib/libdaxctl.sym

+ @@ -91,3 +91,8 @@ global:

+  	daxctl_mapping_get_size;

+  	daxctl_dev_set_mapping;

+  } LIBDAXCTL_7;

+ +

+ +LIBDAXCTL_9 {

+ +global:

+ +	daxctl_dev_will_auto_online_memory;

+ +} LIBDAXCTL_8;

+ diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h

+ index e82b274..30ab51a 100644

+ --- a/daxctl/libdaxctl.h

+ +++ b/daxctl/libdaxctl.h

+ @@ -71,6 +71,7 @@ int daxctl_dev_disable(struct daxctl_dev *dev);

+  int daxctl_dev_enable_devdax(struct daxctl_dev *dev);

+  int daxctl_dev_enable_ram(struct daxctl_dev *dev);

+  int daxctl_dev_get_target_node(struct daxctl_dev *dev);

+ +int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev);

+  

+  struct daxctl_memory;

+  struct daxctl_memory *daxctl_dev_get_memory(struct daxctl_dev *dev);

+ diff --git a/test/daxctl-devices.sh b/test/daxctl-devices.sh

+ index 496e4f2..eed5906 100755

+ --- a/test/daxctl-devices.sh

+ +++ b/test/daxctl-devices.sh

+ @@ -64,6 +64,26 @@ daxctl_get_mode()

+  	"$DAXCTL" list -d "$1" | jq -er '.[].mode'

+  }

+  

+ +set_online_policy()

+ +{

+ +	echo "online" > /sys/devices/system/memory/auto_online_blocks

+ +}

+ +

+ +unset_online_policy()

+ +{

+ +	echo "offline" > /sys/devices/system/memory/auto_online_blocks

+ +}

+ +

+ +save_online_policy()

+ +{

+ +	saved_policy="$(cat /sys/devices/system/memory/auto_online_blocks)"

+ +}

+ +

+ +restore_online_policy()

+ +{

+ +	echo "$saved_policy" > /sys/devices/system/memory/auto_online_blocks

+ +}

+ +

+  daxctl_test()

+  {

+  	local daxdev

+ @@ -71,6 +91,9 @@ daxctl_test()

+  	daxdev=$(daxctl_get_dev "$testdev")

+  	test -n "$daxdev"

+  

+ +	# these tests need to run with kernel onlining policy turned off

+ +	save_online_policy

+ +	unset_online_policy

+  	"$DAXCTL" reconfigure-device -N -m system-ram "$daxdev"

+  	[[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]

+  	"$DAXCTL" online-memory "$daxdev"

+ @@ -81,6 +104,19 @@ daxctl_test()

+  	[[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]

+  	"$DAXCTL" reconfigure-device -f -m devdax "$daxdev"

+  	[[ $(daxctl_get_mode "$daxdev") == "devdax" ]]

+ +

+ +	# this tests for reconfiguration failure if an online-policy is set

+ +	set_online_policy

+ +	: "This command is expected to fail:"

+ +	if ! "$DAXCTL" reconfigure-device -N -m system-ram "$daxdev"; then

+ +		echo "reconfigure failed as expected"

+ +	else

+ +		echo "reconfigure succeded, expected failure"

+ +		restore_online_policy

+ +		return 1

+ +	fi

+ +

+ +	restore_online_policy

+  }

+  

+  find_testdev

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,63 @@ 

+ From e563e6a7c55e65c554e07db6215f8bcb2d411d3b Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 30 Mar 2021 20:50:37 -0600

+ Subject: [PATCH 015/217] libdaxctl: add an API to check if a device is active

+ 

+ Add an API to check whether a daxctl device is active in system-ram

+ mode. This would be used from libndctl during

+ ndctl_namespace_disable_safe(), so that we don't disable/destroy an

+ underlying namespace while the memory is active and online.

+ 

+ Reported-by: Chunye Xu <chunye.xu@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Cc: Dave Hansen <dave.hansen@linux.intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  daxctl/lib/libdaxctl.c   | 10 ++++++++++

+  daxctl/lib/libdaxctl.sym |  1 +

+  daxctl/libdaxctl.h       |  1 +

+  3 files changed, 12 insertions(+)

+ 

+ diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c

+ index 879f7e6..860bd9c 100644

+ --- a/daxctl/lib/libdaxctl.c

+ +++ b/daxctl/lib/libdaxctl.c

+ @@ -1665,3 +1665,13 @@ DAXCTL_EXPORT int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev)

+  	/* match both "online" and "online_movable" */

+  	return !strncmp(buf, "online", 6);

+  }

+ +

+ +DAXCTL_EXPORT int daxctl_dev_has_online_memory(struct daxctl_dev *dev)

+ +{

+ +	struct daxctl_memory *mem = daxctl_dev_get_memory(dev);

+ +

+ +	if (mem)

+ +		return daxctl_memory_is_online(mem);

+ +	else

+ +		return 0;

+ +}

+ diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym

+ index 892e393..a13e93d 100644

+ --- a/daxctl/lib/libdaxctl.sym

+ +++ b/daxctl/lib/libdaxctl.sym

+ @@ -95,4 +95,5 @@ global:

+  LIBDAXCTL_9 {

+  global:

+  	daxctl_dev_will_auto_online_memory;

+ +	daxctl_dev_has_online_memory;

+  } LIBDAXCTL_8;

+ diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h

+ index 30ab51a..683ae9c 100644

+ --- a/daxctl/libdaxctl.h

+ +++ b/daxctl/libdaxctl.h

+ @@ -72,6 +72,7 @@ int daxctl_dev_enable_devdax(struct daxctl_dev *dev);

+  int daxctl_dev_enable_ram(struct daxctl_dev *dev);

+  int daxctl_dev_get_target_node(struct daxctl_dev *dev);

+  int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev);

+ +int daxctl_dev_has_online_memory(struct daxctl_dev *dev);

+  

+  struct daxctl_memory;

+  struct daxctl_memory *daxctl_dev_get_memory(struct daxctl_dev *dev);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,113 @@ 

+ From 573f0d46cff15fff2804b3fb444d1e34f482e788 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 30 Mar 2021 20:54:55 -0600

+ Subject: [PATCH 016/217] libndctl: check for active system-ram before

+  disabling daxctl devices

+ 

+ Teach ndctl_namespace_disable_safe() to look at the state of a

+ daxctl_dev with respect to whether it is active in 'system-ram' mode

+ before disabling it. This is similar to checking whether a filesystem is

+ actively mounted on a namespace before disabling it.

+ 

+ Without this, libndctl would happily disable a devdax namespace while the

+ device was active in system-ram mode. If the namespace was subsequently

+ also destroyed, this would leave the memory without any sort of a

+ 'handle' to perform any subsequent operation on it, and the system would

+ have to be rebooted to get out of this situation.

+ 

+ Reported-by: Chunye Xu <chunye.xu@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Cc: Dave Hansen <dave.hansen@linux.intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c   | 25 ++++++++++++++++++++++++-

+  test/daxctl-devices.sh | 16 ++++++++++++++++

+  2 files changed, 40 insertions(+), 1 deletion(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 2f6d806..2eda56c 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -4593,21 +4593,40 @@ NDCTL_EXPORT int ndctl_namespace_disable_invalidate(struct ndctl_namespace *ndns

+  	return ndctl_namespace_disable(ndns);

+  }

+  

+ +static int ndctl_dax_has_active_memory(struct ndctl_dax *dax)

+ +{

+ +	struct daxctl_region *dax_region;

+ +	struct daxctl_dev *dax_dev;

+ +

+ +	dax_region = ndctl_dax_get_daxctl_region(dax);

+ +	if (!dax_region)

+ +		return 0;

+ +

+ +	daxctl_dev_foreach(dax_region, dax_dev)

+ +		if (daxctl_dev_has_online_memory(dax_dev))

+ +			return 1;

+ +

+ +	return 0;

+ +}

+ +

+  NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)

+  {

+  	const char *devname = ndctl_namespace_get_devname(ndns);

+  	struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns);

+  	struct ndctl_pfn *pfn = ndctl_namespace_get_pfn(ndns);

+  	struct ndctl_btt *btt = ndctl_namespace_get_btt(ndns);

+ +	struct ndctl_dax *dax = ndctl_namespace_get_dax(ndns);

+  	const char *bdev = NULL;

+ +	int fd, active = 0;

+  	char path[50];

+ -	int fd;

+  	unsigned long long size = ndctl_namespace_get_size(ndns);

+  

+  	if (pfn && ndctl_pfn_is_enabled(pfn))

+  		bdev = ndctl_pfn_get_block_device(pfn);

+  	else if (btt && ndctl_btt_is_enabled(btt))

+  		bdev = ndctl_btt_get_block_device(btt);

+ +	else if (dax && ndctl_dax_is_enabled(dax))

+ +		active = ndctl_dax_has_active_memory(dax);

+  	else if (ndctl_namespace_is_enabled(ndns))

+  		bdev = ndctl_namespace_get_block_device(ndns);

+  

+ @@ -4632,6 +4651,10 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)

+  					devname, bdev, strerror(errno));

+  			return -errno;

+  		}

+ +	} else if (active) {

+ +		dbg(ctx, "%s: active as system-ram, refusing to disable\n",

+ +				devname);

+ +		return -EBUSY;

+  	} else {

+  		if (size == 0)

+  			/* No disable necessary due to no capacity allocated */

+ diff --git a/test/daxctl-devices.sh b/test/daxctl-devices.sh

+ index eed5906..56c9691 100755

+ --- a/test/daxctl-devices.sh

+ +++ b/test/daxctl-devices.sh

+ @@ -105,6 +105,22 @@ daxctl_test()

+  	"$DAXCTL" reconfigure-device -f -m devdax "$daxdev"

+  	[[ $(daxctl_get_mode "$daxdev") == "devdax" ]]

+  

+ +	# fail 'ndctl-disable-namespace' while the devdax namespace is active

+ +	# as system-ram. If this test fails, a reboot will be required to

+ +	# recover from the resulting state.

+ +	test -n "$testdev"

+ +	"$DAXCTL" reconfigure-device -m system-ram "$daxdev"

+ +	[[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]

+ +	if ! "$NDCTL" disable-namespace "$testdev"; then

+ +		echo "disable-namespace failed as expected"

+ +	else

+ +		echo "disable-namespace succeded, expected failure"

+ +		echo "reboot required to recover from this state"

+ +		return 1

+ +	fi

+ +	"$DAXCTL" reconfigure-device -f -m devdax "$daxdev"

+ +	[[ $(daxctl_get_mode "$daxdev") == "devdax" ]]

+ +

+  	# this tests for reconfiguration failure if an online-policy is set

+  	set_online_policy

+  	: "This command is expected to fail:"

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,49 @@ 

+ From e81f890c7ae1c940c7f52b8984e8728706489728 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 31 Mar 2021 13:51:35 -0600

+ Subject: [PATCH 017/217] daxctl: emit counts of total and online memblocks

+ 

+ Fir daxctl device listings, if in 'system-ram' mode, it is useful to

+ know whether the memory associated with the device is online or not.

+ Since the memory is comprised of a number of 'memblocks', and it is

+ possible (albeit rare) to have a subset of them online, and the rest

+ offline, we can't just use a boolean online-or-offline flag for the

+ state.

+ 

+ Add a couple of counts, one for the total number of memblocks associated

+ with the device, and another for the ones that are online.

+ 

+ Link: https://github.com/pmem/ndctl/issues/139

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Cc: Dave Hansen <dave.hansen@linux.intel.com>

+ Reported-by: Steve Scargall <steve.scargall@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/json.c | 11 +++++++++++

+  1 file changed, 11 insertions(+)

+ 

+ diff --git a/util/json.c b/util/json.c

+ index ca0167b..a8d2412 100644

+ --- a/util/json.c

+ +++ b/util/json.c

+ @@ -482,6 +482,17 @@ struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,

+  		json_object_object_add(jdev, "mode", jobj);

+  

+  	if (mem && daxctl_dev_get_resource(dev) != 0) {

+ +		int num_sections = daxctl_memory_num_sections(mem);

+ +		int num_online = daxctl_memory_is_online(mem);

+ +

+ +		jobj = json_object_new_int(num_online);

+ +		if (jobj)

+ +			json_object_object_add(jdev, "online_memblocks", jobj);

+ +

+ +		jobj = json_object_new_int(num_sections);

+ +		if (jobj)

+ +			json_object_object_add(jdev, "total_memblocks", jobj);

+ +

+  		movable = daxctl_memory_is_movable(mem);

+  		if (movable == 1)

+  			jobj = json_object_new_boolean(true);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,220 @@ 

+ From daef3a386a9c45105a2c045ddee46600e265939f Mon Sep 17 00:00:00 2001

+ From: Santosh Sivaraj <santosh@fossix.org>

+ Date: Thu, 13 May 2021 11:42:15 +0530

+ Subject: [PATCH 018/217] libndctl: Unify adding dimms for papr and nfit

+  families

+ 

+ In preparation for enabling tests on non-nfit devices, unify both, already very

+ similar, functions into one. This will help in adding all attributes needed for

+ the unit tests. Since the function doesn't fail if some of the dimm attributes

+ are missing, this will work fine on PAPR platforms though only part of the DIMM

+ attributes are provided (This doesn't mean that all of the DIMM attributes can

+ be missing).

+ 

+ Link: https://lore.kernel.org/r/20210513061218.760322-1-santosh@fossix.org

+ Signed-off-by: Santosh Sivaraj <santosh@fossix.org>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 103 ++++++++++++++++---------------------------

+  1 file changed, 38 insertions(+), 65 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 2f6d806..e45353f 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -1646,41 +1646,9 @@ static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,

+  static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath);

+  static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias);

+  

+ -static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base)

+ -{

+ -	int rc = -ENODEV;

+ -	char buf[SYSFS_ATTR_SIZE];

+ -	struct ndctl_ctx *ctx = dimm->bus->ctx;

+ -	char *path = calloc(1, strlen(dimm_base) + 100);

+ -	const char * const devname = ndctl_dimm_get_devname(dimm);

+ -

+ -	dbg(ctx, "%s: Probing of_pmem dimm at %s\n", devname, dimm_base);

+ -

+ -	if (!path)

+ -		return -ENOMEM;

+ -

+ -	/* construct path to the papr compatible dimm flags file */

+ -	sprintf(path, "%s/papr/flags", dimm_base);

+ -

+ -	if (ndctl_bus_is_papr_scm(dimm->bus) &&

+ -	    sysfs_read_attr(ctx, path, buf) == 0) {

+ -

+ -		dbg(ctx, "%s: Adding papr-scm dimm flags:\"%s\"\n", devname, buf);

+ -		dimm->cmd_family = NVDIMM_FAMILY_PAPR;

+ -

+ -		/* Parse dimm flags */

+ -		parse_papr_flags(dimm, buf);

+ -

+ -		/* Allocate monitor mode fd */

+ -		dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);

+ -		rc = 0;

+ -	}

+ -

+ -	free(path);

+ -	return rc;

+ -}

+ -

+ -static int add_nfit_dimm(struct ndctl_dimm *dimm, const char *dimm_base)

+ +static int populate_dimm_attributes(struct ndctl_dimm *dimm,

+ +				    const char *dimm_base,

+ +				    const char *bus_prefix)

+  {

+  	int i, rc = -1;

+  	char buf[SYSFS_ATTR_SIZE];

+ @@ -1694,7 +1662,7 @@ static int add_nfit_dimm(struct ndctl_dimm *dimm, const char *dimm_base)

+  	 * 'unique_id' may not be available on older kernels, so don't

+  	 * fail if the read fails.

+  	 */

+ -	sprintf(path, "%s/nfit/id", dimm_base);

+ +	sprintf(path, "%s/%s/id", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0) {

+  		unsigned int b[9];

+  

+ @@ -1709,68 +1677,74 @@ static int add_nfit_dimm(struct ndctl_dimm *dimm, const char *dimm_base)

+  		}

+  	}

+  

+ -	sprintf(path, "%s/nfit/handle", dimm_base);

+ +	sprintf(path, "%s/%s/handle", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+  	dimm->handle = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/phys_id", dimm_base);

+ +	sprintf(path, "%s/%s/phys_id", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+  	dimm->phys_id = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/serial", dimm_base);

+ +	sprintf(path, "%s/%s/serial", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->serial = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/vendor", dimm_base);

+ +	sprintf(path, "%s/%s/vendor", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->vendor_id = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/device", dimm_base);

+ +	sprintf(path, "%s/%s/device", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->device_id = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/rev_id", dimm_base);

+ +	sprintf(path, "%s/%s/rev_id", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->revision_id = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/dirty_shutdown", dimm_base);

+ +	sprintf(path, "%s/%s/dirty_shutdown", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->dirty_shutdown = strtoll(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/subsystem_vendor", dimm_base);

+ +	sprintf(path, "%s/%s/subsystem_vendor", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->subsystem_vendor_id = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/subsystem_device", dimm_base);

+ +	sprintf(path, "%s/%s/subsystem_device", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->subsystem_device_id = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/subsystem_rev_id", dimm_base);

+ +	sprintf(path, "%s/%s/subsystem_rev_id", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->subsystem_revision_id = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/family", dimm_base);

+ +	sprintf(path, "%s/%s/family", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->cmd_family = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/dsm_mask", dimm_base);

+ +	sprintf(path, "%s/%s/dsm_mask", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->nfit_dsm_mask = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/format", dimm_base);

+ +	sprintf(path, "%s/%s/format", dimm_base, bus_prefix);

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		dimm->format[0] = strtoul(buf, NULL, 0);

+  	for (i = 1; i < dimm->formats; i++) {

+ -		sprintf(path, "%s/nfit/format%d", dimm_base, i);

+ +		sprintf(path, "%s/%s/format%d", dimm_base, bus_prefix, i);

+  		if (sysfs_read_attr(ctx, path, buf) == 0)

+  			dimm->format[i] = strtoul(buf, NULL, 0);

+  	}

+  

+ -	sprintf(path, "%s/nfit/flags", dimm_base);

+ -	if (sysfs_read_attr(ctx, path, buf) == 0)

+ -		parse_nfit_mem_flags(dimm, buf);

+ +	sprintf(path, "%s/%s/flags", dimm_base, bus_prefix);

+ +	if (sysfs_read_attr(ctx, path, buf) == 0) {

+ +		if (ndctl_bus_has_nfit(dimm->bus))

+ +			parse_nfit_mem_flags(dimm, buf);

+ +		else if (ndctl_bus_is_papr_scm(dimm->bus)) {

+ +			dimm->cmd_family = NVDIMM_FAMILY_PAPR;

+ +			parse_papr_flags(dimm, buf);

+ +		}

+ +	}

+  

+  	dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);

+  	rc = 0;

+ @@ -1792,7 +1766,8 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)

+  	if (!path)

+  		return NULL;

+  

+ -	sprintf(path, "%s/nfit/formats", dimm_base);

+ +	sprintf(path, "%s/%s/formats", dimm_base,

+ +		ndctl_bus_has_nfit(bus) ? "nfit" : "papr");

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		formats = 1;

+  	else

+ @@ -1866,13 +1841,12 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)

+  	else

+  		dimm->fwa_result = fwa_result_to_result(buf);

+  

+ +	dimm->formats = formats;

+  	/* Check if the given dimm supports nfit */

+  	if (ndctl_bus_has_nfit(bus)) {

+ -		dimm->formats = formats;

+ -		rc = add_nfit_dimm(dimm, dimm_base);

+ -	} else if (ndctl_bus_has_of_node(bus)) {

+ -		rc = add_papr_dimm(dimm, dimm_base);

+ -	}

+ +		rc = populate_dimm_attributes(dimm, dimm_base, "nfit");

+ +	} else if (ndctl_bus_has_of_node(bus))

+ +		rc = populate_dimm_attributes(dimm, dimm_base, "papr");

+  

+  	if (rc == -ENODEV) {

+  		/* Unprobed dimm with no family */

+ @@ -2531,13 +2505,12 @@ static void *add_region(void *parent, int id, const char *region_base)

+  		goto err_read;

+  	region->num_mappings = strtoul(buf, NULL, 0);

+  

+ -	sprintf(path, "%s/nfit/range_index", region_base);

+ -	if (ndctl_bus_has_nfit(bus)) {

+ -		if (sysfs_read_attr(ctx, path, buf) < 0)

+ -			goto err_read;

+ -		region->range_index = strtoul(buf, NULL, 0);

+ -	} else

+ +	sprintf(path, "%s/%s/range_index", region_base,

+ +		ndctl_bus_has_nfit(bus) ? "nfit": "papr");

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		region->range_index = -1;

+ +	else

+ +		region->range_index = strtoul(buf, NULL, 0);

+  

+  	sprintf(path, "%s/read_only", region_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,211 @@ 

+ From 1649ad9c3e2c6e9c47870c8d3b54f10b24177bc7 Mon Sep 17 00:00:00 2001

+ From: Santosh Sivaraj <santosh@fossix.org>

+ Date: Thu, 13 May 2021 11:42:16 +0530

+ Subject: [PATCH 019/217] test: Don't skip tests if nfit modules are missing

+ 

+ For NFIT to be available ACPI is a must, so don't fail when nfit modules

+ are missing on a platform that doesn't support ACPI.

+ 

+ Link: https://lore.kernel.org/r/20210513061218.760322-2-santosh@fossix.org

+ Signed-off-by: Santosh Sivaraj <santosh@fossix.org>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test.h                        |  2 +-

+  test/ack-shutdown-count-set.c |  2 +-

+  test/blk_namespaces.c         |  2 +-

+  test/core.c                   | 28 ++++++++++++++++++++++++++--

+  test/dpa-alloc.c              |  2 +-

+  test/dsm-fail.c               |  2 +-

+  test/libndctl.c               |  2 +-

+  test/multi-pmem.c             |  2 +-

+  test/parent-uuid.c            |  2 +-

+  test/pmem_namespaces.c        |  2 +-

+  10 files changed, 35 insertions(+), 11 deletions(-)

+ 

+ diff --git a/test.h b/test.h

+ index cba8d41..7de13fe 100644

+ --- a/test.h

+ +++ b/test.h

+ @@ -20,7 +20,7 @@ void builtin_xaction_namespace_reset(void);

+  

+  struct kmod_ctx;

+  struct kmod_module;

+ -int nfit_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,

+ +int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,

+  		struct ndctl_ctx *nd_ctx, int log_level,

+  		struct ndctl_test *test);

+  

+ diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c

+ index fb1d82b..c561ff3 100644

+ --- a/test/ack-shutdown-count-set.c

+ +++ b/test/ack-shutdown-count-set.c

+ @@ -99,7 +99,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test,

+  	int result = EXIT_FAILURE, err;

+  

+  	ndctl_set_log_priority(ctx, loglevel);

+ -	err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+ +	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+  	if (err < 0) {

+  		result = 77;

+  		ndctl_test_skip(test);

+ diff --git a/test/blk_namespaces.c b/test/blk_namespaces.c

+ index d7f00cb..f076e85 100644

+ --- a/test/blk_namespaces.c

+ +++ b/test/blk_namespaces.c

+ @@ -228,7 +228,7 @@ int test_blk_namespaces(int log_level, struct ndctl_test *test,

+  

+  	if (!bus) {

+  		fprintf(stderr, "ACPI.NFIT unavailable falling back to nfit_test\n");

+ -		rc = nfit_test_init(&kmod_ctx, &mod, NULL, log_level, test);

+ +		rc = ndctl_test_init(&kmod_ctx, &mod, NULL, log_level, test);

+  		ndctl_invalidate(ctx);

+  		bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");

+  		if (rc < 0 || !bus) {

+ diff --git a/test/core.c b/test/core.c

+ index cc7d8d9..2b03aa9 100644

+ --- a/test/core.c

+ +++ b/test/core.c

+ @@ -11,6 +11,7 @@

+  #include <util/log.h>

+  #include <util/sysfs.h>

+  #include <ndctl/libndctl.h>

+ +#include <ndctl/ndctl.h>

+  #include <ccan/array_size/array_size.h>

+  

+  #define KVER_STRLEN 20

+ @@ -106,11 +107,11 @@ int ndctl_test_get_skipped(struct ndctl_test *test)

+  	return test->skip;

+  }

+  

+ -int nfit_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,

+ +int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,

+  		struct ndctl_ctx *nd_ctx, int log_level,

+  		struct ndctl_test *test)

+  {

+ -	int rc;

+ +	int rc, family = -1;

+  	unsigned int i;

+  	const char *name;

+  	struct ndctl_bus *bus;

+ @@ -127,10 +128,28 @@ int nfit_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,

+  		"nd_e820",

+  		"nd_pmem",

+  	};

+ +	char *test_env;

+  

+  	log_init(&log_ctx, "test/init", "NDCTL_TEST");

+  	log_ctx.log_priority = log_level;

+  

+ +	/*

+ +	 * The following two checks determine the platform family. For

+ +	 * Intel/platforms which support ACPI, check sysfs; for other platforms

+ +	 * determine from the environment variable NVDIMM_TEST_FAMILY

+ +	 */

+ +	if (access("/sys/bus/acpi", F_OK) == 0)

+ +		family = NVDIMM_FAMILY_INTEL;

+ +

+ +	test_env = getenv("NDCTL_TEST_FAMILY");

+ +	if (test_env && strcmp(test_env, "PAPR") == 0)

+ +		family = NVDIMM_FAMILY_PAPR;

+ +

+ +	if (family == -1) {

+ +		log_err(&log_ctx, "Cannot determine NVDIMM family\n");

+ +		return -ENOTSUP;

+ +	}

+ +

+  	*ctx = kmod_new(NULL, NULL);

+  	if (!*ctx)

+  		return -ENXIO;

+ @@ -185,6 +204,11 @@ retry:

+  

+  		path = kmod_module_get_path(*mod);

+  		if (!path) {

+ +			if (family != NVDIMM_FAMILY_INTEL &&

+ +			    (strcmp(name, "nfit") == 0 ||

+ +			     strcmp(name, "nd_e820") == 0))

+ +				continue;

+ +

+  			log_err(&log_ctx, "%s.ko: failed to get path\n", name);

+  			break;

+  		}

+ diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c

+ index e922009..0b3bb7a 100644

+ --- a/test/dpa-alloc.c

+ +++ b/test/dpa-alloc.c

+ @@ -289,7 +289,7 @@ int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)

+  		return 77;

+  

+  	ndctl_set_log_priority(ctx, loglevel);

+ -	err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+ +	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+  	if (err < 0) {

+  		ndctl_test_skip(test);

+  		fprintf(stderr, "nfit_test unavailable skipping tests\n");

+ diff --git a/test/dsm-fail.c b/test/dsm-fail.c

+ index 9dfd8b0..0a6383d 100644

+ --- a/test/dsm-fail.c

+ +++ b/test/dsm-fail.c

+ @@ -346,7 +346,7 @@ int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)

+  	int result = EXIT_FAILURE, err;

+  

+  	ndctl_set_log_priority(ctx, loglevel);

+ -	err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+ +	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+  	if (err < 0) {

+  		result = 77;

+  		ndctl_test_skip(test);

+ diff --git a/test/libndctl.c b/test/libndctl.c

+ index c42f785..d9b50f4 100644

+ --- a/test/libndctl.c

+ +++ b/test/libndctl.c

+ @@ -2708,7 +2708,7 @@ int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)

+  	daxctl_set_log_priority(daxctl_ctx, loglevel);

+  	ndctl_set_private_data(ctx, test);

+  

+ -	err = nfit_test_init(&kmod_ctx, &mod, ctx, loglevel, test);

+ +	err = ndctl_test_init(&kmod_ctx, &mod, ctx, loglevel, test);

+  	if (err < 0) {

+  		ndctl_test_skip(test);

+  		fprintf(stderr, "nfit_test unavailable skipping tests\n");

+ diff --git a/test/multi-pmem.c b/test/multi-pmem.c

+ index 3d10952..3ea08cc 100644

+ --- a/test/multi-pmem.c

+ +++ b/test/multi-pmem.c

+ @@ -249,7 +249,7 @@ int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx

+  

+  	ndctl_set_log_priority(ctx, loglevel);

+  

+ -	err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+ +	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+  	if (err < 0) {

+  		result = 77;

+  		ndctl_test_skip(test);

+ diff --git a/test/parent-uuid.c b/test/parent-uuid.c

+ index 6424e9f..bded33a 100644

+ --- a/test/parent-uuid.c

+ +++ b/test/parent-uuid.c

+ @@ -218,7 +218,7 @@ int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ct

+  		return 77;

+  

+  	ndctl_set_log_priority(ctx, loglevel);

+ -	err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+ +	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);

+  	if (err < 0) {

+  		ndctl_test_skip(test);

+  		fprintf(stderr, "nfit_test unavailable skipping tests\n");

+ diff --git a/test/pmem_namespaces.c b/test/pmem_namespaces.c

+ index f0f2edd..a4db1ae 100644

+ --- a/test/pmem_namespaces.c

+ +++ b/test/pmem_namespaces.c

+ @@ -191,7 +191,7 @@ int test_pmem_namespaces(int log_level, struct ndctl_test *test,

+  

+  	if (!bus) {

+  		fprintf(stderr, "ACPI.NFIT unavailable falling back to nfit_test\n");

+ -		rc = nfit_test_init(&kmod_ctx, &mod, NULL, log_level, test);

+ +		rc = ndctl_test_init(&kmod_ctx, &mod, NULL, log_level, test);

+  		ndctl_invalidate(ctx);

+  		bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");

+  		if (rc < 0 || !bus) {

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,41 @@ 

+ From f081f302505209430df46908775a3cffb875a5c7 Mon Sep 17 00:00:00 2001

+ From: Santosh Sivaraj <santosh@fossix.org>

+ Date: Thu, 13 May 2021 11:42:17 +0530

+ Subject: [PATCH 020/217] papr: Add support to parse save_fail flag for dimm

+ 

+ This will help in getting the dimm fail tests to run on papr family too.

+ Also add nvdimm_test compatibility string for recognizing the test module.

+ 

+ Link: https://lore.kernel.org/r/20210513061218.760322-3-santosh@fossix.org

+ Signed-off-by: Santosh Sivaraj <santosh@fossix.org>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 5 ++++-

+  1 file changed, 4 insertions(+), 1 deletion(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index e45353f..a8b99ea 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -805,6 +805,8 @@ static void parse_papr_flags(struct ndctl_dimm *dimm, char *flags)

+  			dimm->flags.f_restore = 1;

+  		else if (strcmp(start, "smart_notify") == 0)

+  			dimm->flags.f_smart = 1;

+ +		else if (strcmp(start, "save_fail") == 0)

+ +			dimm->flags.f_save = 1;

+  		start = end + 1;

+  	}

+  	if (end != start)

+ @@ -1035,7 +1037,8 @@ NDCTL_EXPORT int ndctl_bus_is_papr_scm(struct ndctl_bus *bus)

+  	if (sysfs_read_attr(bus->ctx, bus->bus_buf, buf) < 0)

+  		return 0;

+  

+ -	return (strcmp(buf, "ibm,pmemory") == 0);

+ +	return (strcmp(buf, "ibm,pmemory") == 0 ||

+ +		strcmp(buf, "nvdimm_test") == 0);

+  }

+  

+  /**

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,129 @@ 

+ From fe831b526b88f6ca7a27fdb149b8a7d2ecddbc55 Mon Sep 17 00:00:00 2001

+ From: Santosh Sivaraj <santosh@fossix.org>

+ Date: Thu, 13 May 2021 11:42:18 +0530

+ Subject: [PATCH 021/217] Use page size as alignment value

+ 

+ The alignment sizes passed to ndctl in the tests are all hardcoded to 4k,

+ the default page size on x86. Change those to the default page size on that

+ architecture (sysconf/getconf). No functional changes otherwise.

+ 

+ Link: https://lore.kernel.org/r/20210513061218.760322-4-santosh@fossix.org

+ Signed-off-by: Santosh Sivaraj <santosh@fossix.org>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/dpa-alloc.c    | 15 ++++++++-------

+  test/multi-dax.sh   |  6 ++++--

+  test/sector-mode.sh |  4 +++-

+  3 files changed, 15 insertions(+), 10 deletions(-)

+ 

+ diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c

+ index 0b3bb7a..59185cf 100644

+ --- a/test/dpa-alloc.c

+ +++ b/test/dpa-alloc.c

+ @@ -38,12 +38,13 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  	struct ndctl_region *region, *blk_region = NULL;

+  	struct ndctl_namespace *ndns;

+  	struct ndctl_dimm *dimm;

+ -	unsigned long size;

+ +	unsigned long size, page_size;

+  	struct ndctl_bus *bus;

+  	char uuid_str[40];

+  	int round;

+  	int rc;

+  

+ +	page_size = sysconf(_SC_PAGESIZE);

+  	/* disable nfit_test.1, not used in this test */

+  	bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER1);

+  	if (!bus)

+ @@ -124,11 +125,11 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  			return rc;

+  		}

+  		ndctl_namespace_disable_invalidate(ndns);

+ -		rc = ndctl_namespace_set_size(ndns, SZ_4K);

+ +		rc = ndctl_namespace_set_size(ndns, page_size);

+  		if (rc) {

+ -			fprintf(stderr, "failed to init %s to size: %d\n",

+ +			fprintf(stderr, "failed to init %s to size: %lu\n",

+  					ndctl_namespace_get_devname(ndns),

+ -					SZ_4K);

+ +					page_size);

+  			return rc;

+  		}

+  		namespaces[i].ndns = ndns;

+ @@ -150,7 +151,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  		ndns = namespaces[i % ARRAY_SIZE(namespaces)].ndns;

+  		if (i % ARRAY_SIZE(namespaces) == 0)

+  			round++;

+ -		size = SZ_4K * round;

+ +		size = page_size * round;

+  		rc = ndctl_namespace_set_size(ndns, size);

+  		if (rc) {

+  			fprintf(stderr, "%s: set_size: %lx failed: %d\n",

+ @@ -166,7 +167,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  	i--;

+  	round++;

+  	ndns = namespaces[i % ARRAY_SIZE(namespaces)].ndns;

+ -	size = SZ_4K * round;

+ +	size = page_size * round;

+  	rc = ndctl_namespace_set_size(ndns, size);

+  	if (rc) {

+  		fprintf(stderr, "%s failed to update while labels full\n",

+ @@ -175,7 +176,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  	}

+  

+  	round--;

+ -	size = SZ_4K * round;

+ +	size = page_size * round;

+  	rc = ndctl_namespace_set_size(ndns, size);

+  	if (rc) {

+  		fprintf(stderr, "%s failed to reduce size while labels full\n",

+ diff --git a/test/multi-dax.sh b/test/multi-dax.sh

+ index 8496619..b343a38 100755

+ --- a/test/multi-dax.sh

+ +++ b/test/multi-dax.sh

+ @@ -13,6 +13,8 @@ check_prereq "jq"

+  

+  trap 'err $LINENO' ERR

+  

+ +ALIGN_SIZE=`getconf PAGESIZE`

+ +

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+  $NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ @@ -23,9 +25,9 @@ rc=1

+  query=". | sort_by(.available_size) | reverse | .[0].dev"

+  region=$($NDCTL list -b $NFIT_TEST_BUS0 -t pmem -Ri | jq -r "$query")

+  

+ -json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -r $region -t pmem -m devdax -a 4096 -s 16M)

+ +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -r $region -t pmem -m devdax -a $ALIGN_SIZE -s 16M)

+  chardev1=$(echo $json | jq ". | select(.mode == \"devdax\") | .daxregion.devices[0].chardev")

+ -json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -r $region -t pmem -m devdax -a 4096 -s 16M)

+ +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -r $region -t pmem -m devdax -a $ALIGN_SIZE -s 16M)

+  chardev2=$(echo $json | jq ". | select(.mode == \"devdax\") | .daxregion.devices[0].chardev")

+  

+  _cleanup

+ diff --git a/test/sector-mode.sh b/test/sector-mode.sh

+ index 54fa806..7a2faea 100755

+ --- a/test/sector-mode.sh

+ +++ b/test/sector-mode.sh

+ @@ -11,6 +11,8 @@ check_prereq "jq"

+  set -e

+  trap 'err $LINENO' ERR

+  

+ +ALIGN_SIZE=`getconf PAGESIZE`

+ +

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+  $NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ @@ -27,7 +29,7 @@ NAMESPACE=$($NDCTL list -b $NFIT_TEST_BUS1 -N | jq -r "$query")

+  REGION=$($NDCTL list -R --namespace=$NAMESPACE | jq -r "(.[]) | .dev")

+  echo 0 > /sys/bus/nd/devices/$REGION/read_only

+  $NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K

+ -$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m dax -f -a 4K

+ +$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m dax -f -a $ALIGN_SIZE

+  $NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K

+  

+  _cleanup

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,38 @@ 

+ From 561af4f919b3f1b3d1a213137f1d024420996d56 Mon Sep 17 00:00:00 2001

+ From: Santosh Sivaraj <santosh@fossix.org>

+ Date: Sun, 28 Mar 2021 05:43:51 +0530

+ Subject: [PATCH 022/217] libndctl: Remove redundant checks and assignments

+ 

+ check_udev already checks for udev allocation failure, remove the redundant

+ check.

+ 

+ Link: https://lore.kernel.org/r/20210328001351.2245032-1-santosh@fossix.org

+ Signed-off-by: Santosh Sivaraj <santosh@fossix.org>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 9 +++------

+  1 file changed, 3 insertions(+), 6 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index bf0968c..3a496ed 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -323,12 +323,9 @@ NDCTL_EXPORT int ndctl_new(struct ndctl_ctx **ctx)

+  		dbg(c, "timeout = %ld\n", tmo);

+  	}

+  

+ -	if (udev) {

+ -		c->udev = udev;

+ -		c->udev_queue = udev_queue_new(udev);

+ -		if (!c->udev_queue)

+ -			err(c, "failed to retrieve udev queue\n");

+ -	}

+ +	c->udev_queue = udev_queue_new(udev);

+ +	if (!c->udev_queue)

+ +		err(c, "failed to retrieve udev queue\n");

+  

+  	c->kmod_ctx = kmod_ctx;

+  	c->daxctl_ctx = daxctl_ctx;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,56 @@ 

+ From 063af7c447d257397a925df81897da2c71e31653 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 18 May 2021 16:25:27 -0600

+ Subject: [PATCH 023/217] ndctl: Update nvdimm mailing list address

+ 

+ The 'nvdimm' mailing list has moved from lists.01.org to

+ lists.linux.dev. Update CONTRIBUTING.md and configure.ac to reflect

+ this.

+ 

+ Link: https://lore.kernel.org/r/20210518222527.550730-1-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  CONTRIBUTING.md | 7 ++++---

+  configure.ac    | 2 +-

+  2 files changed, 5 insertions(+), 4 deletions(-)

+ 

+ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md

+ index 4c29d31..4f4865d 100644

+ --- a/CONTRIBUTING.md

+ +++ b/CONTRIBUTING.md

+ @@ -6,13 +6,14 @@ The following is a set of guidelines that we adhere to, and request that

+  contributors follow.

+  

+  1. The libnvdimm (kernel subsystem) and ndctl developers primarily use

+ -   the [linux-nvdimm](https://lists.01.org/postorius/lists/linux-nvdimm.lists.01.org/)

+ +   the [nvdimm](https://subspace.kernel.org/lists.linux.dev.html)

+     mailing list for everything. It is recommended to send patches to

+ -   **```linux-nvdimm@lists.01.org```**

+ +   **```nvdimm@lists.linux.dev```**

+ +   An archive is available on [lore](https://lore.kernel.org/nvdimm/)

+  

+  1. Github [issues](https://github.com/pmem/ndctl/issues) are an acceptable

+     way to report a problem, but if you just have a question,

+ -   [email](mailto:linux-nvdimm@lists.01.org) the above list.

+ +   [email](mailto:nvdimm@lists.linux.dev) the above list.

+  

+  1. We follow the Linux Kernel [Coding Style Guide][cs] as applicable.

+  

+ diff --git a/configure.ac b/configure.ac

+ index 5ec8d2f..dc39dbe 100644

+ --- a/configure.ac

+ +++ b/configure.ac

+ @@ -2,7 +2,7 @@ AC_PREREQ(2.60)

+  m4_include([version.m4])

+  AC_INIT([ndctl],

+          GIT_VERSION,

+ -        [linux-nvdimm@lists.01.org],

+ +        [nvdimm@lists.linux.dev],

+          [ndctl],

+          [https://github.com/pmem/ndctl])

+  AC_CONFIG_SRCDIR([ndctl/lib/libndctl.c])

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,122 @@ 

+ From e086106b4d81a2079141c848db7695451c04e877 Mon Sep 17 00:00:00 2001

+ From: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Date: Mon, 17 May 2021 21:18:24 +0530

+ Subject: [PATCH 024/217] libndctl/papr: Fix probe for papr-scm compatible

+  nvdimms

+ 

+ With recent changes introduced for unification of PAPR and NFIT

+ families the probe for papr-scm nvdimms is broken since they don't

+ expose 'handle' or 'phys_id' sysfs attributes. These attributes are

+ only exposed by NFIT and 'nvdimm_test' nvdimms. Since 'unable to read'

+ these sysfs attributes is a non-recoverable error hence this prevents

+ probing of 'PAPR-SCM' nvdimms and ndctl reports following error:

+ 

+ $ sudo NDCTL_LOG=debug ndctl list -DH

+ libndctl: ndctl_new: ctx 0x10015342c70 created

+ libndctl: add_dimm: nmem1: probe failed: Operation not permitted

+ libndctl: __sysfs_device_parse: nmem1: add_dev() failed

+ libndctl: add_dimm: nmem0: probe failed: Operation not permitted

+ libndctl: __sysfs_device_parse: nmem0: add_dev() failed

+ 

+ Fixing this bug is complicated by the fact these attributes are needed

+ for by the 'nvdimm_test' nvdimms which also uses the

+ NVDIMM_FAMILY_PAPR. Adding a two way comparison for these two

+ attributes in populate_dimm_attributes() to distinguish between

+ 'nvdimm_test' and papr-scm nvdimms will be clunky and make future

+ updates to populate_dimm_attributes() error prone.

+ 

+ So, this patch proposes to fix the issue by re-introducing

+ add_papr_dimm() to probe both papr-scm and 'nvdimm_test' nvdimms. The

+ 'compatible' sysfs attribute associated with the PAPR device is used

+ to distinguish between the two nvdimm types and in case an

+ 'nvdimm_test' device is detected then forward its probe to

+ populate_dimm_attributes().

+ 

+ families")

+ 

+ Link: https://lore.kernel.org/r/20210517154824.142237-1-vaibhav@linux.ibm.com

+ Fixes: daef3a386a9c("libndctl: Unify adding dimms for papr and nfit

+ Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 57 ++++++++++++++++++++++++++++++++++++++++++--

+  1 file changed, 55 insertions(+), 2 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 3a496ed..aa36a3c 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -1754,6 +1754,58 @@ static int populate_dimm_attributes(struct ndctl_dimm *dimm,

+  	return rc;

+  }

+  

+ +static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base)

+ +{

+ +	int rc = -ENODEV;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +	struct ndctl_ctx *ctx = dimm->bus->ctx;

+ +	char *path = calloc(1, strlen(dimm_base) + 100);

+ +	const char * const devname = ndctl_dimm_get_devname(dimm);

+ +

+ +	dbg(ctx, "%s: Probing of_pmem dimm at %s\n", devname, dimm_base);

+ +

+ +	if (!path)

+ +		return -ENOMEM;

+ +

+ +	/* Check the compatibility of the probed nvdimm */

+ +	sprintf(path, "%s/../of_node/compatible", dimm_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0) {

+ +		dbg(ctx, "%s: Unable to read compatible field\n", devname);

+ +		rc =  -ENODEV;

+ +		goto out;

+ +	}

+ +

+ +	dbg(ctx, "%s:Compatible of_pmem = '%s'\n", devname, buf);

+ +

+ +	/* Probe for papr-scm memory */

+ +	if (strcmp(buf, "ibm,pmemory") == 0) {

+ +		/* Read the dimm flags file */

+ +		sprintf(path, "%s/papr/flags", dimm_base);

+ +		if (sysfs_read_attr(ctx, path, buf) < 0) {

+ +			rc = -errno;

+ +			err(ctx, "%s: Unable to read dimm-flags\n", devname);

+ +			goto out;

+ +		}

+ +

+ +		dbg(ctx, "%s: Adding papr-scm dimm flags:\"%s\"\n", devname, buf);

+ +		dimm->cmd_family = NVDIMM_FAMILY_PAPR;

+ +

+ +		/* Parse dimm flags */

+ +		parse_papr_flags(dimm, buf);

+ +

+ +		/* Allocate monitor mode fd */

+ +		dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);

+ +		rc = 0;

+ +

+ +	} else if (strcmp(buf, "nvdimm_test") == 0) {

+ +		/* probe via common populate_dimm_attributes() */

+ +		rc = populate_dimm_attributes(dimm, dimm_base, "papr");

+ +	}

+ +out:

+ +	free(path);

+ +	return rc;

+ +}

+ +

+  static void *add_dimm(void *parent, int id, const char *dimm_base)

+  {

+  	int formats, i, rc = -ENODEV;

+ @@ -1845,8 +1897,9 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)

+  	/* Check if the given dimm supports nfit */

+  	if (ndctl_bus_has_nfit(bus)) {

+  		rc = populate_dimm_attributes(dimm, dimm_base, "nfit");

+ -	} else if (ndctl_bus_has_of_node(bus))

+ -		rc = populate_dimm_attributes(dimm, dimm_base, "papr");

+ +	} else if (ndctl_bus_has_of_node(bus)) {

+ +		rc = add_papr_dimm(dimm, dimm_base);

+ +	}

+  

+  	if (rc == -ENODEV) {

+  		/* Unprobed dimm with no family */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,38 @@ 

+ From c52109355b715bbe21e284090435bee7563863cc Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 26 May 2021 16:33:04 -0700

+ Subject: [PATCH 025/217] ndctl/scrub: Stop translating return values

+ 

+ In preparation for triggering a poll loop within ndctl_bus_start_scrub(),

+ stop translating return values into -EOPNOTSUPP.

+ 

+ Link: https://lore.kernel.org/r/162207198482.3715490.5994844104395495686.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 8 +-------

+  1 file changed, 1 insertion(+), 7 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index aa36a3c..e5641fe 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -1354,14 +1354,8 @@ static int __ndctl_bus_get_scrub_state(struct ndctl_bus *bus,

+  NDCTL_EXPORT int ndctl_bus_start_scrub(struct ndctl_bus *bus)

+  {

+  	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);

+ -	int rc;

+  

+ -	rc = sysfs_write_attr(ctx, bus->scrub_path, "1\n");

+ -	if (rc == -EBUSY)

+ -		return rc;

+ -	else if (rc < 0)

+ -		return -EOPNOTSUPP;

+ -	return 0;

+ +	return sysfs_write_attr(ctx, bus->scrub_path, "1\n");

+  }

+  

+  NDCTL_EXPORT int ndctl_bus_get_scrub_state(struct ndctl_bus *bus)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,48 @@ 

+ From 4e646fa490ba4b782afa188dd8818b94c419924e Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 26 May 2021 16:33:10 -0700

+ Subject: [PATCH 026/217] ndctl/scrub: Reread scrub-engine status at start

+ 

+ Given that the kernel has exponential backoff to cover the lack of

+ interrupts for scrub completion status there is a reasonable likelihood

+ that 'ndctl start-scrub' is issued while the hardware/platform scrub-state

+ is idle, but the kernel engine poll timer has not fired.

+ 

+ Trigger at least one poll cycle for the kernel to re-read the scrub-state

+ before reporting that ARS is busy.

+ 

+ Link: https://lore.kernel.org/r/162207199057.3715490.2469820075085914776.stgit@dwillia2-desk3.amr.corp.intel.com

+ Reported-by: Krzysztof Rusocki <krzysztof.rusocki@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 12 +++++++++++-

+  1 file changed, 11 insertions(+), 1 deletion(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index e5641fe..536e142 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -1354,8 +1354,18 @@ static int __ndctl_bus_get_scrub_state(struct ndctl_bus *bus,

+  NDCTL_EXPORT int ndctl_bus_start_scrub(struct ndctl_bus *bus)

+  {

+  	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);

+ +	int rc;

+ +

+ +	rc = sysfs_write_attr(ctx, bus->scrub_path, "1\n");

+  

+ -	return sysfs_write_attr(ctx, bus->scrub_path, "1\n");

+ +	/*

+ +	 * Try at least 1 poll cycle before reporting busy in case this

+ +	 * request hits the kernel's exponential backoff while the

+ +	 * hardware/platform scrub state is idle.

+ +	 */

+ +	if (rc == -EBUSY && ndctl_bus_poll_scrub_completion(bus, 1, 1) == 0)

+ +		return sysfs_write_attr(ctx, bus->scrub_path, "1\n");

+ +	return rc;

+  }

+  

+  NDCTL_EXPORT int ndctl_bus_get_scrub_state(struct ndctl_bus *bus)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,167 @@ 

+ From 7e98977c10ad5f4baf5e3bc4d5b4b2fd733a8b7e Mon Sep 17 00:00:00 2001

+ From: Jingqi Liu <jingqi.liu@intel.com>

+ Date: Thu, 8 Jul 2021 16:14:46 +0800

+ Subject: [PATCH 027/217] ndctl/dimm: Fix label index block calculations

+ 

+ The following bug is caused by setting the size of Label Index Block

+ to a fixed 256 bytes.

+ 

+ Use the following Qemu command to start a Guest with 2MB label-size:

+ 	-object memory-backend-file,id=mem1,share=on,mem-path=/dev/dax1.1,size=14G,align=2M

+ 	-device nvdimm,memdev=mem1,id=nv1,label-size=2M

+ 

+ There is a namespace in the Guest as follows:

+ 	$ ndctl list

+ 	[

+ 	  {

+ 	    "dev":"namespace0.0",

+ 	    "mode":"devdax",

+ 	    "map":"dev",

+ 	    "size":14780727296,

+ 	    "uuid":"58ad5282-5a16-404f-b8ee-e28b4c784eb8",

+ 	    "chardev":"dax0.0",

+ 	    "align":2097152,

+ 	    "name":"namespace0.0"

+ 	  }

+ 	]

+ 

+ Fail to read labels. The result is as follows:

+ 	$ ndctl read-labels -u nmem0

+ 	[

+ 	]

+ 	read 0 nmem

+ 

+ If using the following Qemu command to start the Guest with 128K

+ label-size, this label can be read correctly.

+ 	-object memory-backend-file,id=mem1,share=on,mem-path=/dev/dax1.1,size=14G,align=2M

+ 	-device nvdimm,memdev=mem1,id=nv1,label-size=128K

+ 

+ The size of a Label Index Block depends on how many label slots fit into

+ the label storage area. The minimum size of an index block is 256 bytes

+ and the size must be a multiple of 256 bytes. For a storage area of 128KB,

+ the corresponding Label Index Block size is 256 bytes. But if the label

+ storage area is not 128KB, the Label Index Block size should not be 256 bytes.

+ 

+ Namespace Label Index Block appears twice at the top of the label storage area.

+ Following the two index blocks, an array for storing labels takes up the

+ remainder of the label storage area.

+ 

+ For obtaining the size of Namespace Index Block, we also cannot rely on

+ the field of 'mysize' in this index block since it might be corrupted.

+ Similar to the linux kernel, we use sizeof_namespace_index() to get the size

+ of Namespace Index Block. Then we can also correctly calculate the starting

+ offset of the following namespace labels.

+ 

+ Link: https://lore.kernel.org/r/20210708081446.14323-1-jingqi.liu@intel.com

+ Suggested-by: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>

+ Signed-off-by: Jingqi Liu <jingqi.liu@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/dimm.c           | 19 +++++++++++++++----

+  ndctl/lib/dimm.c       |  5 +++++

+  ndctl/lib/libndctl.sym |  1 +

+  ndctl/libndctl.h       |  1 +

+  4 files changed, 22 insertions(+), 4 deletions(-)

+ 

+ diff --git a/ndctl/dimm.c b/ndctl/dimm.c

+ index 09ce49e..1d2d9a2 100644

+ --- a/ndctl/dimm.c

+ +++ b/ndctl/dimm.c

+ @@ -94,13 +94,18 @@ static struct json_object *dump_label_json(struct ndctl_dimm *dimm,

+  	struct json_object *jarray = json_object_new_array();

+  	struct json_object *jlabel = NULL;

+  	struct namespace_label nslabel;

+ +	unsigned int nsindex_size;

+  	unsigned int slot = -1;

+  	ssize_t offset;

+  

+  	if (!jarray)

+  		return NULL;

+  

+ -	for (offset = NSINDEX_ALIGN * 2; offset < size;

+ +	nsindex_size = ndctl_dimm_sizeof_namespace_index(dimm);

+ +	if (nsindex_size == 0)

+ +		return NULL;

+ +

+ +	for (offset = nsindex_size * 2; offset < size;

+  			offset += ndctl_dimm_sizeof_namespace_label(dimm)) {

+  		ssize_t len = min_t(ssize_t,

+  				ndctl_dimm_sizeof_namespace_label(dimm),

+ @@ -204,17 +209,23 @@ static struct json_object *dump_label_json(struct ndctl_dimm *dimm,

+  	return jarray;

+  }

+  

+ -static struct json_object *dump_index_json(struct ndctl_cmd *cmd_read, ssize_t size)

+ +static struct json_object *dump_index_json(struct ndctl_dimm *dimm,

+ +		struct ndctl_cmd *cmd_read, ssize_t size)

+  {

+  	struct json_object *jarray = json_object_new_array();

+  	struct json_object *jindex = NULL;

+  	struct namespace_index nsindex;

+ +	unsigned int nsindex_size;

+  	ssize_t offset;

+  

+  	if (!jarray)

+  		return NULL;

+  

+ -	for (offset = 0; offset < NSINDEX_ALIGN * 2; offset += NSINDEX_ALIGN) {

+ +	nsindex_size = ndctl_dimm_sizeof_namespace_index(dimm);

+ +	if (nsindex_size == 0)

+ +		return NULL;

+ +

+ +	for (offset = 0; offset < nsindex_size * 2; offset += nsindex_size) {

+  		ssize_t len = min_t(ssize_t, sizeof(nsindex), size - offset);

+  		struct json_object *jobj;

+  

+ @@ -288,7 +299,7 @@ static struct json_object *dump_json(struct ndctl_dimm *dimm,

+  		goto err;

+  	json_object_object_add(jdimm, "dev", jobj);

+  

+ -	jindex = dump_index_json(cmd_read, size);

+ +	jindex = dump_index_json(dimm, cmd_read, size);

+  	if (!jindex)

+  		goto err;

+  	json_object_object_add(jdimm, "index", jindex);

+ diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c

+ index c045cbe..9e36e28 100644

+ --- a/ndctl/lib/dimm.c

+ +++ b/ndctl/lib/dimm.c

+ @@ -256,6 +256,11 @@ static int __label_validate(struct nvdimm_data *ndd)

+  	return -EINVAL;

+  }

+  

+ +NDCTL_EXPORT unsigned int ndctl_dimm_sizeof_namespace_index(struct ndctl_dimm *dimm)

+ +{

+ +	return sizeof_namespace_index(&dimm->ndd);

+ +}

+ +

+  /*

+   * If the dimm labels have not been previously validated this routine

+   * will make up a default size. Otherwise, it will pick the size based

+ diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym

+ index 58afb74..5ee73b7 100644

+ --- a/ndctl/lib/libndctl.sym

+ +++ b/ndctl/lib/libndctl.sym

+ @@ -454,4 +454,5 @@ LIBNDCTL_25 {

+  

+  LIBNDCTL_26 {

+  	ndctl_bus_nfit_translate_spa;

+ +	ndctl_dimm_sizeof_namespace_index;

+  } LIBNDCTL_25;

+ diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h

+ index 87d07b7..df109bb 100644

+ --- a/ndctl/libndctl.h

+ +++ b/ndctl/libndctl.h

+ @@ -337,6 +337,7 @@ int ndctl_dimm_init_labels(struct ndctl_dimm *dimm,

+  		enum ndctl_namespace_version v);

+  unsigned long ndctl_dimm_get_available_labels(struct ndctl_dimm *dimm);

+  unsigned int ndctl_dimm_sizeof_namespace_label(struct ndctl_dimm *dimm);

+ +unsigned int ndctl_dimm_sizeof_namespace_index(struct ndctl_dimm *dimm);

+  unsigned int ndctl_cmd_cfg_size_get_size(struct ndctl_cmd *cfg_size);

+  ssize_t ndctl_cmd_cfg_read_get_data(struct ndctl_cmd *cfg_read, void *buf,

+  		unsigned int len, unsigned int offset);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,58 @@ 

+ From 9bd2994f91bb77604521cbe09a76a51d092c2cfd Mon Sep 17 00:00:00 2001

+ From: Michal Suchanek <msuchanek@suse.de>

+ Date: Wed, 6 Jan 2021 14:17:40 +0100

+ Subject: [PATCH 028/217] ndctl/namespace: Skip seed namespaces when processing

+  all namespaces.

+ 

+ The seed namespaces are exposed by the kernel but most operations are

+ not valid on seed namespaces.

+ 

+ When processing all namespaces the user gets confusing errors from ndctl

+ trying to process seed namespaces. The kernel does not provide any way

+ to tell that a namspace is seed namespace but skipping namespaces with

+ zero size and UUID is a good heuristic.

+ 

+ The user can still specify the namespace by name directly in case

+ processing it is desirable.

+ 

+ Link: https://patchwork.kernel.org/patch/11473645/

+ Link: https://lore.kernel.org/r/e55ae2c17b8b9c3288491efe6214338118e8c5ae.1609938610.git.msuchanek@suse.de

+ Fixes: #41

+ Tested-by: Harish Sriram <harish@linux.ibm.com>

+ Reviewed-by: Santosh S <santosh@fossix.org>

+ Signed-off-by: Michal Suchanek <msuchanek@suse.de>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/namespace.c | 16 +++++++++++++---

+  1 file changed, 13 insertions(+), 3 deletions(-)

+ 

+ diff --git a/ndctl/namespace.c b/ndctl/namespace.c

+ index 1e8a2cd..5e65ed5 100644

+ --- a/ndctl/namespace.c

+ +++ b/ndctl/namespace.c

+ @@ -2210,9 +2210,19 @@ static int do_xaction_namespace(const char *namespace,

+  			ndctl_namespace_foreach_safe(region, ndns, _n) {

+  				ndns_name = ndctl_namespace_get_devname(ndns);

+  

+ -				if (strcmp(namespace, "all") != 0

+ -						&& strcmp(namespace, ndns_name) != 0)

+ -					continue;

+ +				if (strcmp(namespace, "all") == 0) {

+ +					static const uuid_t zero_uuid;

+ +					uuid_t uuid;

+ +

+ +					ndctl_namespace_get_uuid(ndns, uuid);

+ +					if (!ndctl_namespace_get_size(ndns) &&

+ +					    !memcmp(uuid, zero_uuid, sizeof(uuid_t)))

+ +						continue;

+ +				} else {

+ +					if (strcmp(namespace, ndns_name) != 0)

+ +						continue;

+ +				}

+ +

+  				switch (action) {

+  				case ACTION_DISABLE:

+  					rc = ndctl_namespace_disable_safe(ndns);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,82 @@ 

+ From 07011a334fd1e4b641cdbfaf5de7500f7bdc941d Mon Sep 17 00:00:00 2001

+ From: Michal Suchanek <msuchanek@suse.de>

+ Date: Wed, 6 Jan 2021 14:17:41 +0100

+ Subject: [PATCH 029/217] ndctl/namespace: Suppress -ENXIO when processing all

+  namespaces.

+ 

+ When processing all namespaces and no namespaces exist user gets the

+ default -ENXIO. Set default rc to 0 when processing all namespaces.

+ This avoids confusing error message printed in addition to the message

+ saying 0 namespaces were affected.

+ 

+ Before:

+ 

+  # ndctl check-namespace all

+ namespace0.0: namespace_check: namespace0.0: check aborted, namespace online

+ error checking namespaces: Device or resource busy

+ checked 0 namespaces

+  # ndctl disable-namespace all

+ disabled 1 namespace

+  # ndctl check-namespace all

+ namespace0.0: namespace_check: Unable to recover any BTT info blocks

+ error checking namespaces: No such device or address

+ checked 0 namespaces

+  # ndctl destroy-namespace all

+ destroyed 1 namespace

+  # ndctl check-namespace all

+ error checking namespaces: No such device or address

+ checked 0 namespaces

+  # ndctl destroy-namespace all

+ error destroying namespaces: No such device or address

+ destroyed 0 namespaces

+ 

+ After:

+ 

+  # ndctl check-namespace all

+ namespace0.0: namespace_check: namespace0.0: check aborted, namespace online

+ error checking namespaces: Device or resource busy

+ checked 0 namespaces

+  # ndctl disable-namespace namespace0.0

+ disabled 1 namespace

+  # ndctl check-namespace all

+ namespace0.0: namespace_check: Unable to recover any BTT info blocks

+ error checking namespaces: No such device or address

+ checked 0 namespaces

+  # ndctl destroy-namespace all

+ destroyed 1 namespace

+  # ndctl check-namespace all

+ checked 0 namespaces

+  # ndctl destroy-namespace all

+ destroyed 0 namespaces

+  # ndctl destroy-namespace all

+ destroyed 0 namespaces

+ 

+ Note: this does change the return value from -ENXIO to 0 in the cases

+ when no namespaces exist and processing all namespaces was requested.

+ 

+ Link: https://patchwork.kernel.org/patch/11681431/

+ Link: https://lore.kernel.org/r/32c8cd8d2716f5e52aebea4e4d303eeb4e0550f9.1609938610.git.msuchanek@suse.de

+ Reviewed-by: Santosh S <santosh@fossix.org>

+ Signed-off-by: Michal Suchanek <msuchanek@suse.de>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/namespace.c | 3 +++

+  1 file changed, 3 insertions(+)

+ 

+ diff --git a/ndctl/namespace.c b/ndctl/namespace.c

+ index 5e65ed5..cd822b3 100644

+ --- a/ndctl/namespace.c

+ +++ b/ndctl/namespace.c

+ @@ -2151,6 +2151,9 @@ static int do_xaction_namespace(const char *namespace,

+  	if (!namespace && action != ACTION_CREATE)

+  		return rc;

+  

+ +	if (namespace && (strcmp(namespace, "all") == 0))

+ +		rc = 0;

+ +

+  	if (verbose)

+  		ndctl_set_log_priority(ctx, LOG_DEBUG);

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,85 @@ 

+ From 80e0d88c3098bd419e26146a8cb3b693fdd06417 Mon Sep 17 00:00:00 2001

+ From: Santosh Sivaraj <santosh@fossix.org>

+ Date: Wed, 6 Jan 2021 14:17:42 +0100

+ Subject: [PATCH 030/217] namespace-action: Drop zero namespace checks.

+ 

+ With seed namespaces catched early on these checks for sizes in enable

+ and destroy namespace code path are not needed.

+ 

+ Reverts commit b9cb03f6d5a8 ("ndctl/namespace: Fix enable-namespace

+ error for seed namespaces")

+ 

+ Reverts commit e01045e58ad5 ("ndctl/namespace: Fix destroy-namespace

+ accounting relative to seed devices")

+ 

+ Link: https://patchwork.kernel.org/patch/11739975/

+ Link: https://lore.kernel.org/r/eb4bc7885708fa13e3d37286bc4a4219b1e4e5b6.1609938610.git.msuchanek@suse.de

+ Fixes: b9cb03f6d5a8 ("ndctl/namespace: Fix enable-namespace error for seed namespaces")

+ Fixes: e01045e58ad5 ("ndctl/namespace: Fix destroy-namespace accounting relative to seed devices")

+ Signed-off-by: Santosh Sivaraj <santosh@fossix.org>

+ [rebased on top of the previous patches]

+ Signed-off-by: Michal Suchanek <msuchanek@suse.de>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c |  5 -----

+  ndctl/namespace.c    | 10 ----------

+  2 files changed, 15 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 536e142..87f60b9 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -4531,16 +4531,11 @@ NDCTL_EXPORT int ndctl_namespace_enable(struct ndctl_namespace *ndns)

+  	const char *devname = ndctl_namespace_get_devname(ndns);

+  	struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns);

+  	struct ndctl_region *region = ndns->region;

+ -	unsigned long long size = ndctl_namespace_get_size(ndns);

+  	int rc;

+  

+  	if (ndctl_namespace_is_enabled(ndns))

+  		return 0;

+  

+ -	/* Don't try to enable idle namespace (no capacity allocated) */

+ -	if (size == 0)

+ -		return -ENXIO;

+ -

+  	rc = ndctl_bind(ctx, ndns->module, devname);

+  

+  	/*

+ diff --git a/ndctl/namespace.c b/ndctl/namespace.c

+ index cd822b3..c67c086 100644

+ --- a/ndctl/namespace.c

+ +++ b/ndctl/namespace.c

+ @@ -1164,15 +1164,12 @@ static int namespace_destroy(struct ndctl_region *region,

+  		struct ndctl_namespace *ndns)

+  {

+  	const char *devname = ndctl_namespace_get_devname(ndns);

+ -	unsigned long long size;

+  	int rc;

+  

+  	rc = namespace_prep_reconfig(region, ndns);

+  	if (rc < 0)

+  		return rc;

+  

+ -	size = ndctl_namespace_get_size(ndns);

+ -

+  	/* Labeled namespace, destroy label / allocation */

+  	if (rc == 2) {

+  		rc = ndctl_namespace_delete(ndns);

+ @@ -1180,13 +1177,6 @@ static int namespace_destroy(struct ndctl_region *region,

+  			debug("%s: failed to reclaim\n", devname);

+  	}

+  

+ -	/*

+ -	 * Don't report a destroyed namespace when no capacity was

+ -	 * allocated.

+ -	 */

+ -	if (size == 0 && rc == 0)

+ -		rc = 1;

+ -

+  	return rc;

+  }

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,187 @@ 

+ From dc712e47c39f4dbc5f089831fd50dd1a2752c8fc Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:23 -0600

+ Subject: [PATCH 031/217] ndctl: add .clang-format

+ 

+ Copy the Linux kernel's .clang-format and modify it for ndctl. Only the

+ 'ForEachMacros' section has been modified from the original kernel copy.

+ 

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reported-by: Ben Widawsky <ben.widawsky@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++

+  1 file changed, 161 insertions(+)

+  create mode 100644 .clang-format

+ 

+ diff --git a/.clang-format b/.clang-format

+ new file mode 100644

+ index 0000000..4e00fff

+ --- /dev/null

+ +++ b/.clang-format

+ @@ -0,0 +1,161 @@

+ +# SPDX-License-Identifier: GPL-2.0

+ +#

+ +# clang-format configuration file. Intended for clang-format >= 4.

+ +# Copied from Linux's .clang-format

+ +#

+ +# For more information, see:

+ +#

+ +#   https://clang.llvm.org/docs/ClangFormat.html

+ +#   https://clang.llvm.org/docs/ClangFormatStyleOptions.html

+ +#

+ +---

+ +AccessModifierOffset: -4

+ +AlignAfterOpenBracket: Align

+ +AlignConsecutiveAssignments: false

+ +AlignConsecutiveDeclarations: false

+ +#AlignEscapedNewlines: Left # Unknown to clang-format-4.0

+ +AlignOperands: true

+ +AlignTrailingComments: false

+ +AllowAllParametersOfDeclarationOnNextLine: false

+ +AllowShortBlocksOnASingleLine: false

+ +AllowShortCaseLabelsOnASingleLine: false

+ +AllowShortFunctionsOnASingleLine: None

+ +AllowShortIfStatementsOnASingleLine: false

+ +AllowShortLoopsOnASingleLine: false

+ +AlwaysBreakAfterDefinitionReturnType: None

+ +AlwaysBreakAfterReturnType: None

+ +AlwaysBreakBeforeMultilineStrings: false

+ +AlwaysBreakTemplateDeclarations: false

+ +BinPackArguments: true

+ +BinPackParameters: true

+ +BraceWrapping:

+ +  AfterClass: false

+ +  AfterControlStatement: false

+ +  AfterEnum: false

+ +  AfterFunction: true

+ +  AfterNamespace: true

+ +  AfterObjCDeclaration: false

+ +  AfterStruct: false

+ +  AfterUnion: false

+ +  #AfterExternBlock: false # Unknown to clang-format-5.0

+ +  BeforeCatch: false

+ +  BeforeElse: false

+ +  IndentBraces: false

+ +  #SplitEmptyFunction: true # Unknown to clang-format-4.0

+ +  #SplitEmptyRecord: true # Unknown to clang-format-4.0

+ +  #SplitEmptyNamespace: true # Unknown to clang-format-4.0

+ +BreakBeforeBinaryOperators: None

+ +BreakBeforeBraces: Custom

+ +#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0

+ +BreakBeforeTernaryOperators: false

+ +BreakConstructorInitializersBeforeComma: false

+ +#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0

+ +BreakAfterJavaFieldAnnotations: false

+ +BreakStringLiterals: false

+ +ColumnLimit: 80

+ +CommentPragmas: '^ IWYU pragma:'

+ +#CompactNamespaces: false # Unknown to clang-format-4.0

+ +ConstructorInitializerAllOnOneLineOrOnePerLine: false

+ +ConstructorInitializerIndentWidth: 8

+ +ContinuationIndentWidth: 8

+ +Cpp11BracedListStyle: false

+ +DerivePointerAlignment: false

+ +DisableFormat: false

+ +ExperimentalAutoDetectBinPacking: false

+ +#FixNamespaceComments: false # Unknown to clang-format-4.0

+ +

+ +# Taken from:

+ +# while read -r sym; do

+ +# 	printf "  - '%s'\n" "$sym";

+ +# done < \

+ +# 	<(cscope -dL6 "foreach|for_each" \

+ +# 	| awk '{ print $4 $5 }' | grep -E 'foreach|for_each' \

+ +# 	| sed -e 's/#define//' \

+ +# 		-e 's/*//' \

+ +# 		-e 's/://' \

+ +# 		-e 's/\(.*for_each.*\)(.*/\1/' \

+ +# 		-e 's/\(.*foreach.*\)(.*/\1/' \

+ +# 	| sort -u)

+ +ForEachMacros:

+ +  - 'daxctl_dev_foreach'

+ +  - 'daxctl_mapping_foreach'

+ +  - 'daxctl_region_foreach'

+ +  - 'kmod_list_foreach'

+ +  - 'kmod_list_foreach_reverse'

+ +  - 'list_for_each'

+ +  - 'list_for_each_off'

+ +  - 'list_for_each_rev'

+ +  - 'list_for_each_safe'

+ +  - 'list_for_each_safe_off'

+ +  - 'ndctl_btt_foreach'

+ +  - 'ndctl_btt_foreach_safe'

+ +  - 'ndctl_bus_foreach'

+ +  - 'ndctl_dax_foreach'

+ +  - 'ndctl_dax_foreach_safe'

+ +  - 'ndctl_dimm_foreach'

+ +  - 'ndctl_dimm_foreach_in_interleave_set'

+ +  - 'ndctl_dimm_foreach_in_region'

+ +  - 'ndctl_interleave_set_foreach'

+ +  - 'ndctl_mapping_foreach'

+ +  - 'ndctl_namespace_badblock_foreach'

+ +  - 'ndctl_namespace_bb_foreach'

+ +  - 'ndctl_namespace_foreach'

+ +  - 'ndctl_namespace_foreach_safe'

+ +  - 'ndctl_pfn_foreach'

+ +  - 'ndctl_pfn_foreach_safe'

+ +  - 'ndctl_region_badblock_foreach'

+ +  - 'ndctl_region_foreach'

+ +  - 'udev_list_entry_foreach'

+ +

+ +#IncludeBlocks: Preserve # Unknown to clang-format-5.0

+ +IncludeCategories:

+ +  - Regex: '.*'

+ +    Priority: 1

+ +IncludeIsMainRegex: '(Test)?$'

+ +IndentCaseLabels: false

+ +#IndentPPDirectives: None # Unknown to clang-format-5.0

+ +IndentWidth: 8

+ +IndentWrappedFunctionNames: false

+ +JavaScriptQuotes: Leave

+ +JavaScriptWrapImports: true

+ +KeepEmptyLinesAtTheStartOfBlocks: false

+ +MacroBlockBegin: ''

+ +MacroBlockEnd: ''

+ +MaxEmptyLinesToKeep: 1

+ +NamespaceIndentation: None

+ +#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0

+ +ObjCBlockIndentWidth: 8

+ +ObjCSpaceAfterProperty: true

+ +ObjCSpaceBeforeProtocolList: true

+ +

+ +# Taken from git's rules

+ +#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0

+ +PenaltyBreakBeforeFirstCallParameter: 30

+ +PenaltyBreakComment: 10

+ +PenaltyBreakFirstLessLess: 0

+ +PenaltyBreakString: 10

+ +PenaltyExcessCharacter: 100

+ +PenaltyReturnTypeOnItsOwnLine: 60

+ +

+ +PointerAlignment: Right

+ +ReflowComments: false

+ +SortIncludes: false

+ +#SortUsingDeclarations: false # Unknown to clang-format-4.0

+ +SpaceAfterCStyleCast: false

+ +SpaceAfterTemplateKeyword: true

+ +SpaceBeforeAssignmentOperators: true

+ +#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0

+ +#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0

+ +SpaceBeforeParens: ControlStatements

+ +#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0

+ +SpaceInEmptyParentheses: false

+ +SpacesBeforeTrailingComments: 1

+ +SpacesInAngles: false

+ +SpacesInContainerLiterals: false

+ +SpacesInCStyleCastParentheses: false

+ +SpacesInParentheses: false

+ +SpacesInSquareBrackets: false

+ +Standard: Cpp03

+ +TabWidth: 8

+ +UseTab: Always

+ +...

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,256 @@ 

+ From 894fb9b2b59364f7f5683ea68c8bd765223a4ca8 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:25 -0600

+ Subject: [PATCH 033/217] cxl: add a local copy of the cxl_mem UAPI header

+ 

+ While CXL functionality is under development, it is useful to have a

+ local copy of the UAPI header for cxl_mem definitions. This allows

+ building cxl and libcxl on systems where the appropriate kernel headers

+ are not installed in the usual locations.

+ 

+ Cc: Ben Widawsky <ben.widawsky@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Makefile.am         |   3 +-

+  Makefile.am.in      |   1 +

+  cxl/cxl_mem.h       | 189 ++++++++++++++++++++++++++++++++++++++++++++

+  cxl/lib/Makefile.am |   2 +-

+  4 files changed, 193 insertions(+), 2 deletions(-)

+  create mode 100644 cxl/cxl_mem.h

+ 

+ diff --git a/Makefile.am b/Makefile.am

+ index 428fd40..4904ee7 100644

+ --- a/Makefile.am

+ +++ b/Makefile.am

+ @@ -89,4 +89,5 @@ libutil_a_SOURCES = \

+  

+  nobase_include_HEADERS = \

+  	daxctl/libdaxctl.h \

+ -	cxl/libcxl.h

+ +	cxl/libcxl.h \

+ +	cxl/cxl_mem.h

+ diff --git a/Makefile.am.in b/Makefile.am.in

+ index aaeee53..a748128 100644

+ --- a/Makefile.am.in

+ +++ b/Makefile.am.in

+ @@ -11,6 +11,7 @@ AM_CPPFLAGS = \

+  	-DNDCTL_MAN_PATH=\""$(mandir)"\" \

+  	-I${top_srcdir}/ndctl/lib \

+  	-I${top_srcdir}/ndctl \

+ +	-I${top_srcdir}/cxl \

+  	-I${top_srcdir}/ \

+  	$(KMOD_CFLAGS) \

+  	$(UDEV_CFLAGS) \

+ diff --git a/cxl/cxl_mem.h b/cxl/cxl_mem.h

+ new file mode 100644

+ index 0000000..d38cc9c

+ --- /dev/null

+ +++ b/cxl/cxl_mem.h

+ @@ -0,0 +1,189 @@

+ +/* SPDX-License-Identifier: LGPL-2.1 */

+ +/* Copyright (C) 2020-2021, Intel Corporation. All rights reserved. */

+ +/*

+ + * CXL IOCTLs for Memory Devices

+ + */

+ +

+ +#ifndef _UAPI_CXL_MEM_H_

+ +#define _UAPI_CXL_MEM_H_

+ +

+ +#include <linux/types.h>

+ +#include <sys/user.h>

+ +#include <unistd.h>

+ +

+ +#define __user

+ +

+ +/**

+ + * DOC: UAPI

+ + *

+ + * Not all of all commands that the driver supports are always available for use

+ + * by userspace. Userspace must check the results from the QUERY command in

+ + * order to determine the live set of commands.

+ + */

+ +

+ +#define CXL_MEM_QUERY_COMMANDS _IOR(0xCE, 1, struct cxl_mem_query_commands)

+ +#define CXL_MEM_SEND_COMMAND _IOWR(0xCE, 2, struct cxl_send_command)

+ +

+ +#define CXL_CMDS                                                          \

+ +	___C(INVALID, "Invalid Command"),                                 \

+ +	___C(IDENTIFY, "Identify Command"),                               \

+ +	___C(RAW, "Raw device command"),                                  \

+ +	___C(GET_SUPPORTED_LOGS, "Get Supported Logs"),                   \

+ +	___C(GET_FW_INFO, "Get FW Info"),                                 \

+ +	___C(GET_PARTITION_INFO, "Get Partition Information"),            \

+ +	___C(GET_LSA, "Get Label Storage Area"),                          \

+ +	___C(GET_HEALTH_INFO, "Get Health Info"),                         \

+ +	___C(GET_LOG, "Get Log"),                                         \

+ +	___C(SET_PARTITION_INFO, "Set Partition Information"),            \

+ +	___C(SET_LSA, "Set Label Storage Area"),                          \

+ +	___C(GET_ALERT_CONFIG, "Get Alert Configuration"),                \

+ +	___C(SET_ALERT_CONFIG, "Set Alert Configuration"),                \

+ +	___C(GET_SHUTDOWN_STATE, "Get Shutdown State"),                   \

+ +	___C(SET_SHUTDOWN_STATE, "Set Shutdown State"),                   \

+ +	___C(GET_POISON, "Get Poison List"),                              \

+ +	___C(INJECT_POISON, "Inject Poison"),                             \

+ +	___C(CLEAR_POISON, "Clear Poison"),                               \

+ +	___C(GET_SCAN_MEDIA_CAPS, "Get Scan Media Capabilities"),         \

+ +	___C(SCAN_MEDIA, "Scan Media"),                                   \

+ +	___C(GET_SCAN_MEDIA, "Get Scan Media Results"),                   \

+ +	___C(MAX, "invalid / last command")

+ +

+ +#define ___C(a, b) CXL_MEM_COMMAND_ID_##a

+ +enum { CXL_CMDS };

+ +

+ +#undef ___C

+ +#define ___C(a, b) { b }

+ +static const struct {

+ +	const char *name;

+ +} cxl_command_names[] = { CXL_CMDS };

+ +

+ +/*

+ + * Here's how this actually breaks out:

+ + * cxl_command_names[] = {

+ + *	[CXL_MEM_COMMAND_ID_INVALID] = { "Invalid Command" },

+ + *	[CXL_MEM_COMMAND_ID_IDENTIFY] = { "Identify Command" },

+ + *	...

+ + *	[CXL_MEM_COMMAND_ID_MAX] = { "invalid / last command" },

+ + * };

+ + */

+ +

+ +#undef ___C

+ +

+ +/**

+ + * struct cxl_command_info - Command information returned from a query.

+ + * @id: ID number for the command.

+ + * @flags: Flags that specify command behavior.

+ + * @size_in: Expected input size, or -1 if variable length.

+ + * @size_out: Expected output size, or -1 if variable length.

+ + *

+ + * Represents a single command that is supported by both the driver and the

+ + * hardware. This is returned as part of an array from the query ioctl. The

+ + * following would be a command that takes a variable length input and returns 0

+ + * bytes of output.

+ + *

+ + *  - @id = 10

+ + *  - @flags = 0

+ + *  - @size_in = -1

+ + *  - @size_out = 0

+ + *

+ + * See struct cxl_mem_query_commands.

+ + */

+ +struct cxl_command_info {

+ +	__u32 id;

+ +

+ +	__u32 flags;

+ +#define CXL_MEM_COMMAND_FLAG_MASK GENMASK(0, 0)

+ +

+ +	__s32 size_in;

+ +	__s32 size_out;

+ +};

+ +

+ +/**

+ + * struct cxl_mem_query_commands - Query supported commands.

+ + * @n_commands: In/out parameter. When @n_commands is > 0, the driver will

+ + *		return min(num_support_commands, n_commands). When @n_commands

+ + *		is 0, driver will return the number of total supported commands.

+ + * @rsvd: Reserved for future use.

+ + * @commands: Output array of supported commands. This array must be allocated

+ + *            by userspace to be at least min(num_support_commands, @n_commands)

+ + *

+ + * Allow userspace to query the available commands supported by both the driver,

+ + * and the hardware. Commands that aren't supported by either the driver, or the

+ + * hardware are not returned in the query.

+ + *

+ + * Examples:

+ + *

+ + *  - { .n_commands = 0 } // Get number of supported commands

+ + *  - { .n_commands = 15, .commands = buf } // Return first 15 (or less)

+ + *    supported commands

+ + *

+ + *  See struct cxl_command_info.

+ + */

+ +struct cxl_mem_query_commands {

+ +	/*

+ +	 * Input: Number of commands to return (space allocated by user)

+ +	 * Output: Number of commands supported by the driver/hardware

+ +	 *

+ +	 * If n_commands is 0, kernel will only return number of commands and

+ +	 * not try to populate commands[], thus allowing userspace to know how

+ +	 * much space to allocate

+ +	 */

+ +	__u32 n_commands;

+ +	__u32 rsvd;

+ +

+ +	struct cxl_command_info __user commands[]; /* out: supported commands */

+ +};

+ +

+ +/**

+ + * struct cxl_send_command - Send a command to a memory device.

+ + * @id: The command to send to the memory device. This must be one of the

+ + *	commands returned by the query command.

+ + * @flags: Flags for the command (input).

+ + * @raw: Special fields for raw commands

+ + * @raw.opcode: Opcode passed to hardware when using the RAW command.

+ + * @raw.rsvd: Must be zero.

+ + * @rsvd: Must be zero.

+ + * @retval: Return value from the memory device (output).

+ + * @in: Parameters associated with input payload.

+ + * @in.size: Size of the payload to provide to the device (input).

+ + * @in.rsvd: Must be zero.

+ + * @in.payload: Pointer to memory for payload input, payload is little endian.

+ + * @out: Parameters associated with output payload.

+ + * @out.size: Size of the payload received from the device (input/output). This

+ + *	      field is filled in by userspace to let the driver know how much

+ + *	      space was allocated for output. It is populated by the driver to

+ + *	      let userspace know how large the output payload actually was.

+ + * @out.rsvd: Must be zero.

+ + * @out.payload: Pointer to memory for payload output, payload is little endian.

+ + *

+ + * Mechanism for userspace to send a command to the hardware for processing. The

+ + * driver will do basic validation on the command sizes. In some cases even the

+ + * payload may be introspected. Userspace is required to allocate large enough

+ + * buffers for size_out which can be variable length in certain situations.

+ + */

+ +struct cxl_send_command {

+ +	__u32 id;

+ +	__u32 flags;

+ +	union {

+ +		struct {

+ +			__u16 opcode;

+ +			__u16 rsvd;

+ +		} raw;

+ +		__u32 rsvd;

+ +	};

+ +	__u32 retval;

+ +

+ +	struct {

+ +		__s32 size;

+ +		__u32 rsvd;

+ +		__u64 payload;

+ +	} in;

+ +

+ +	struct {

+ +		__s32 size;

+ +		__u32 rsvd;

+ +		__u64 payload;

+ +	} out;

+ +};

+ +

+ +#endif

+ diff --git a/cxl/lib/Makefile.am b/cxl/lib/Makefile.am

+ index 277f0cd..72c9ccd 100644

+ --- a/cxl/lib/Makefile.am

+ +++ b/cxl/lib/Makefile.am

+ @@ -3,7 +3,7 @@ include $(top_srcdir)/Makefile.am.in

+  %.pc: %.pc.in Makefile

+  	$(SED_PROCESS)

+  

+ -pkginclude_HEADERS = ../libcxl.h

+ +pkginclude_HEADERS = ../libcxl.h ../cxl_mem.h

+  lib_LTLIBRARIES = libcxl.la

+  

+  libcxl_la_SOURCES =\

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,114 @@ 

+ From 7aa7c7be6e803de267a165237e23577ab496e792 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:26 -0600

+ Subject: [PATCH 034/217] util: add the struct_size() helper from the kernel

+ 

+ Add struct_size() from include/linux/overflow.h which calculates the

+ size of a struct with a trailing variable length array.

+ 

+ Suggested-by: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/size.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++

+  util/util.h |  6 ++++++

+  2 files changed, 68 insertions(+)

+ 

+ diff --git a/util/size.h b/util/size.h

+ index 646edae..a0f3593 100644

+ --- a/util/size.h

+ +++ b/util/size.h

+ @@ -4,6 +4,8 @@

+  #ifndef _NDCTL_SIZE_H_

+  #define _NDCTL_SIZE_H_

+  #include <stdbool.h>

+ +#include <stdint.h>

+ +#include <util/util.h>

+  

+  #define SZ_1K     0x00000400

+  #define SZ_4K     0x00001000

+ @@ -30,4 +32,64 @@ static inline bool is_power_of_2(unsigned long long v)

+  #define BITS_PER_LONG (sizeof(unsigned long) * 8)

+  #define HPAGE_SIZE (2 << 20)

+  

+ +/*

+ + * Helpers for struct_size() copied from include/linux/overflow.h (GPL-2.0)

+ + *

+ + * For simplicity and code hygiene, the fallback code below insists on

+ + * a, b and *d having the same type (similar to the min() and max()

+ + * macros), whereas gcc's type-generic overflow checkers accept

+ + * different types. Hence we don't just make check_add_overflow an

+ + * alias for __builtin_add_overflow, but add type checks similar to

+ + * below.

+ + */

+ +#define check_add_overflow(a, b, d) (({	\

+ +	typeof(a) __a = (a);			\

+ +	typeof(b) __b = (b);			\

+ +	typeof(d) __d = (d);			\

+ +	(void) (&__a == &__b);			\

+ +	(void) (&__a == __d);			\

+ +	__builtin_add_overflow(__a, __b, __d);	\

+ +}))

+ +

+ +#define check_mul_overflow(a, b, d) (({	\

+ +	typeof(a) __a = (a);			\

+ +	typeof(b) __b = (b);			\

+ +	typeof(d) __d = (d);			\

+ +	(void) (&__a == &__b);			\

+ +	(void) (&__a == __d);			\

+ +	__builtin_mul_overflow(__a, __b, __d);	\

+ +}))

+ +

+ +/*

+ + * Compute a*b+c, returning SIZE_MAX on overflow. Internal helper for

+ + * struct_size() below.

+ + */

+ +static inline size_t __ab_c_size(size_t a, size_t b, size_t c)

+ +{

+ +	size_t bytes;

+ +

+ +	if (check_mul_overflow(a, b, &bytes))

+ +		return SIZE_MAX;

+ +	if (check_add_overflow(bytes, c, &bytes))

+ +		return SIZE_MAX;

+ +

+ +	return bytes;

+ +}

+ +

+ +/**

+ + * struct_size() - Calculate size of structure with trailing array.

+ + * @p: Pointer to the structure.

+ + * @member: Name of the array member.

+ + * @count: Number of elements in the array.

+ + *

+ + * Calculates size of memory needed for structure @p followed by an

+ + * array of @count number of @member elements.

+ + *

+ + * Return: number of bytes needed or SIZE_MAX on overflow.

+ + */

+ +#define struct_size(p, member, count)					\

+ +	__ab_c_size(count,						\

+ +		    sizeof(*(p)->member) + __must_be_array((p)->member),\

+ +		    sizeof(*(p)))

+ +

+  #endif /* _NDCTL_SIZE_H_ */

+ diff --git a/util/util.h b/util/util.h

+ index ae0e4e1..b2b4ae6 100644

+ --- a/util/util.h

+ +++ b/util/util.h

+ @@ -63,6 +63,12 @@

+  #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))

+  #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

+  

+ +/* Are two types/vars the same type (ignoring qualifiers)? */

+ +#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))

+ +

+ +/* &a[0] degrades to a pointer: a different type from an array */

+ +#define __must_be_array(a)	BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))

+ +

+  enum {

+  	READ, WRITE,

+  };

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,535 @@ 

+ From 96afebd1b32ff839129f3bc0ba323ab5f04674ea Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:27 -0600

+ Subject: [PATCH 035/217] libcxl: add support for command query and submission

+ 

+ Add a set of APIs around 'cxl_cmd' for querying the kernel for supported

+ commands, allocating and validating command structures against the

+ supported set, and submitting the commands.

+ 

+ 'Query Commands' and 'Send Command' are implemented as IOCTLs in the

+ kernel. 'Query Commands' returns information about each supported

+ command, such as flags governing its use, or input and output payload

+ sizes. This information is used to validate command support, as well as

+ set up input and output buffers for command submission.

+ 

+ Cc: Ben Widawsky <ben.widawsky@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 390 +++++++++++++++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym |   9 ++

+  cxl/lib/private.h  |  33 ++++

+  cxl/libcxl.h       |  11 ++

+  4 files changed, 443 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index c15e987..727d599 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -9,14 +9,17 @@

+  #include <unistd.h>

+  #include <sys/stat.h>

+  #include <sys/types.h>

+ +#include <sys/ioctl.h>

+  #include <sys/sysmacros.h>

+  #include <uuid/uuid.h>

+  #include <ccan/list/list.h>

+  #include <ccan/array_size/array_size.h>

+  

+  #include <util/log.h>

+ +#include <util/size.h>

+  #include <util/sysfs.h>

+  #include <util/bitmap.h>

+ +#include <cxl/cxl_mem.h>

+  #include <cxl/libcxl.h>

+  #include "private.h"

+  

+ @@ -343,3 +346,390 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev

+  {

+  	return memdev->firmware_version;

+  }

+ +

+ +CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)

+ +{

+ +	if (!cmd)

+ +		return;

+ +	if (--cmd->refcount == 0) {

+ +		free(cmd->query_cmd);

+ +		free(cmd->send_cmd);

+ +		free(cmd->input_payload);

+ +		free(cmd->output_payload);

+ +		free(cmd);

+ +	}

+ +}

+ +

+ +CXL_EXPORT void cxl_cmd_ref(struct cxl_cmd *cmd)

+ +{

+ +	cmd->refcount++;

+ +}

+ +

+ +static int cxl_cmd_alloc_query(struct cxl_cmd *cmd, int num_cmds)

+ +{

+ +	size_t size;

+ +

+ +	if (!cmd)

+ +		return -EINVAL;

+ +

+ +	if (cmd->query_cmd != NULL)

+ +		free(cmd->query_cmd);

+ +

+ +	size = struct_size(cmd->query_cmd, commands, num_cmds);

+ +	if (size == SIZE_MAX)

+ +		return -EOVERFLOW;

+ +

+ +	cmd->query_cmd = calloc(1, size);

+ +	if (!cmd->query_cmd)

+ +		return -ENOMEM;

+ +

+ +	cmd->query_cmd->n_commands = num_cmds;

+ +

+ +	return 0;

+ +}

+ +

+ +static struct cxl_cmd *cxl_cmd_new(struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_cmd *cmd;

+ +	size_t size;

+ +

+ +	size = sizeof(*cmd);

+ +	cmd = calloc(1, size);

+ +	if (!cmd)

+ +		return NULL;

+ +

+ +	cxl_cmd_ref(cmd);

+ +	cmd->memdev = memdev;

+ +

+ +	return cmd;

+ +}

+ +

+ +static int __do_cmd(struct cxl_cmd *cmd, int ioctl_cmd, int fd)

+ +{

+ +	void *cmd_buf;

+ +	int rc;

+ +

+ +	switch (ioctl_cmd) {

+ +	case CXL_MEM_QUERY_COMMANDS:

+ +		cmd_buf = cmd->query_cmd;

+ +		break;

+ +	case CXL_MEM_SEND_COMMAND:

+ +		cmd_buf = cmd->send_cmd;

+ +		break;

+ +	default:

+ +		return -EINVAL;

+ +	}

+ +

+ +	rc = ioctl(fd, ioctl_cmd, cmd_buf);

+ +	if (rc < 0)

+ +		rc = -errno;

+ +

+ +	return rc;

+ +}

+ +

+ +static int do_cmd(struct cxl_cmd *cmd, int ioctl_cmd)

+ +{

+ +	char *path;

+ +	struct stat st;

+ +	unsigned int major, minor;

+ +	int rc = 0, fd;

+ +	struct cxl_memdev *memdev = cmd->memdev;

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +

+ +	major = cxl_memdev_get_major(memdev);

+ +	minor = cxl_memdev_get_minor(memdev);

+ +

+ +	if (asprintf(&path, "/dev/cxl/%s", devname) < 0)

+ +		return -ENOMEM;

+ +

+ +	fd = open(path, O_RDWR);

+ +	if (fd < 0) {

+ +		err(ctx, "failed to open %s: %s\n", path, strerror(errno));

+ +		rc = -errno;

+ +		goto out;

+ +	}

+ +

+ +	if (fstat(fd, &st) >= 0 && S_ISCHR(st.st_mode)

+ +			&& major(st.st_rdev) == major

+ +			&& minor(st.st_rdev) == minor) {

+ +		rc = __do_cmd(cmd, ioctl_cmd, fd);

+ +	} else {

+ +		err(ctx, "failed to validate %s as a CXL memdev node\n", path);

+ +		rc = -ENXIO;

+ +	}

+ +	close(fd);

+ +out:

+ +	free(path);

+ +	return rc;

+ +}

+ +

+ +static int alloc_do_query(struct cxl_cmd *cmd, int num_cmds)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(cmd->memdev);

+ +	int rc;

+ +

+ +	rc = cxl_cmd_alloc_query(cmd, num_cmds);

+ +	if (rc)

+ +		return rc;

+ +

+ +	rc = do_cmd(cmd, CXL_MEM_QUERY_COMMANDS);

+ +	if (rc < 0)

+ +		err(ctx, "%s: query commands failed: %s\n",

+ +			cxl_memdev_get_devname(cmd->memdev),

+ +			strerror(-rc));

+ +	return rc;

+ +}

+ +

+ +static int cxl_cmd_do_query(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_memdev *memdev = cmd->memdev;

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	int rc, n_commands;

+ +

+ +	switch (cmd->query_status) {

+ +	case CXL_CMD_QUERY_OK:

+ +		return 0;

+ +	case CXL_CMD_QUERY_UNSUPPORTED:

+ +		return -EOPNOTSUPP;

+ +	case CXL_CMD_QUERY_NOT_RUN:

+ +		break;

+ +	default:

+ +		err(ctx, "%s: Unknown query_status %d\n",

+ +			devname, cmd->query_status);

+ +		return -EINVAL;

+ +	}

+ +

+ +	rc = alloc_do_query(cmd, 0);

+ +	if (rc)

+ +		return rc;

+ +

+ +	n_commands = cmd->query_cmd->n_commands;

+ +	dbg(ctx, "%s: supports %d commands\n", devname, n_commands);

+ +

+ +	return alloc_do_query(cmd, n_commands);

+ +}

+ +

+ +static int cxl_cmd_validate(struct cxl_cmd *cmd, u32 cmd_id)

+ +{

+ +	struct cxl_memdev *memdev = cmd->memdev;

+ +	struct cxl_mem_query_commands *query = cmd->query_cmd;

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	u32 i;

+ +

+ +	for (i = 0; i < query->n_commands; i++) {

+ +		struct cxl_command_info *cinfo = &query->commands[i];

+ +		const char *cmd_name = cxl_command_names[cinfo->id].name;

+ +

+ +		if (cinfo->id != cmd_id)

+ +			continue;

+ +

+ +		dbg(ctx, "%s: %s: in: %d, out %d, flags: %#08x\n",

+ +			devname, cmd_name, cinfo->size_in,

+ +			cinfo->size_out, cinfo->flags);

+ +

+ +		cmd->query_idx = i;

+ +		cmd->query_status = CXL_CMD_QUERY_OK;

+ +		return 0;

+ +	}

+ +	cmd->query_status = CXL_CMD_QUERY_UNSUPPORTED;

+ +	return -EOPNOTSUPP;

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *buf,

+ +		int size)

+ +{

+ +	struct cxl_memdev *memdev = cmd->memdev;

+ +

+ +	if (size > memdev->payload_max || size < 0)

+ +		return -EINVAL;

+ +

+ +	if (!buf) {

+ +

+ +		/* If the user didn't supply a buffer, allocate it */

+ +		cmd->input_payload = calloc(1, size);

+ +		if (!cmd->input_payload)

+ +			return -ENOMEM;

+ +		cmd->send_cmd->in.payload = (u64)cmd->input_payload;

+ +	} else {

+ +		/*

+ +		 * Use user-buffer as is. If an automatic allocation was

+ +		 * previously made (based on a fixed size from query),

+ +		 * it will get freed during unref.

+ +		 */

+ +		cmd->send_cmd->in.payload = (u64)buf;

+ +	}

+ +	cmd->send_cmd->in.size = size;

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *buf,

+ +		int size)

+ +{

+ +	struct cxl_memdev *memdev = cmd->memdev;

+ +

+ +	if (size > memdev->payload_max || size < 0)

+ +		return -EINVAL;

+ +

+ +	if (!buf) {

+ +

+ +		/* If the user didn't supply a buffer, allocate it */

+ +		cmd->output_payload = calloc(1, size);

+ +		if (!cmd->output_payload)

+ +			return -ENOMEM;

+ +		cmd->send_cmd->out.payload = (u64)cmd->output_payload;

+ +	} else {

+ +		/*

+ +		 * Use user-buffer as is. If an automatic allocation was

+ +		 * previously made (based on a fixed size from query),

+ +		 * it will get freed during unref.

+ +		 */

+ +		cmd->send_cmd->out.payload = (u64)buf;

+ +	}

+ +	cmd->send_cmd->out.size = size;

+ +

+ +	return 0;

+ +}

+ +

+ +static int cxl_cmd_alloc_send(struct cxl_cmd *cmd, u32 cmd_id)

+ +{

+ +	struct cxl_mem_query_commands *query = cmd->query_cmd;

+ +	struct cxl_command_info *cinfo = &query->commands[cmd->query_idx];

+ +	size_t size;

+ +

+ +	if (!query)

+ +		return -EINVAL;

+ +

+ +	size = sizeof(struct cxl_send_command);

+ +	cmd->send_cmd = calloc(1, size);

+ +	if (!cmd->send_cmd)

+ +		return -ENOMEM;

+ +

+ +	if (cinfo->id != cmd_id)

+ +		return -EINVAL;

+ +

+ +	cmd->send_cmd->id = cmd_id;

+ +

+ +	if (cinfo->size_in > 0) {

+ +		cmd->input_payload = calloc(1, cinfo->size_in);

+ +		if (!cmd->input_payload)

+ +			return -ENOMEM;

+ +		cmd->send_cmd->in.payload = (u64)cmd->input_payload;

+ +		cmd->send_cmd->in.size = cinfo->size_in;

+ +	}

+ +	if (cinfo->size_out > 0) {

+ +		cmd->output_payload = calloc(1, cinfo->size_out);

+ +		if (!cmd->output_payload)

+ +			return -ENOMEM;

+ +		cmd->send_cmd->out.payload = (u64)cmd->output_payload;

+ +		cmd->send_cmd->out.size = cinfo->size_out;

+ +	}

+ +

+ +	return 0;

+ +}

+ +

+ +static struct cxl_cmd *cxl_cmd_new_generic(struct cxl_memdev *memdev,

+ +		u32 cmd_id)

+ +{

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	struct cxl_cmd *cmd;

+ +	int rc;

+ +

+ +	cmd = cxl_cmd_new(memdev);

+ +	if (!cmd)

+ +		return NULL;

+ +

+ +	rc = cxl_cmd_do_query(cmd);

+ +	if (rc) {

+ +		err(ctx, "%s: query returned: %s\n", devname, strerror(-rc));

+ +		goto fail;

+ +	}

+ +

+ +	rc = cxl_cmd_validate(cmd, cmd_id);

+ +	if (rc) {

+ +		errno = -rc;

+ +		goto fail;

+ +	}

+ +

+ +	rc = cxl_cmd_alloc_send(cmd, cmd_id);

+ +	if (rc) {

+ +		errno = -rc;

+ +		goto fail;

+ +	}

+ +

+ +	cmd->status = 1;

+ +	return cmd;

+ +

+ +fail:

+ +	cxl_cmd_unref(cmd);

+ +	return NULL;

+ +}

+ +

+ +CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)

+ +{

+ +	return cxl_memdev_get_devname(cmd->memdev);

+ +}

+ +

+ +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,

+ +		int opcode)

+ +{

+ +	struct cxl_cmd *cmd;

+ +

+ +	/* opcode '0' is reserved */

+ +	if (opcode <= 0) {

+ +		errno = EINVAL;

+ +		return NULL;

+ +	}

+ +

+ +	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_RAW);

+ +	if (!cmd)

+ +		return NULL;

+ +

+ +	cmd->send_cmd->raw.opcode = opcode;

+ +	return cmd;

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_memdev *memdev = cmd->memdev;

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	int rc;

+ +

+ +	switch (cmd->query_status) {

+ +	case CXL_CMD_QUERY_OK:

+ +		break;

+ +	case CXL_CMD_QUERY_UNSUPPORTED:

+ +		return -EOPNOTSUPP;

+ +	case CXL_CMD_QUERY_NOT_RUN:

+ +		return -EINVAL;

+ +	default:

+ +		err(ctx, "%s: Unknown query_status %d\n",

+ +			devname, cmd->query_status);

+ +		return -EINVAL;

+ +	}

+ +

+ +	dbg(ctx, "%s: submitting SEND cmd: in: %d, out: %d\n", devname,

+ +		cmd->send_cmd->in.size, cmd->send_cmd->out.size);

+ +	rc = do_cmd(cmd, CXL_MEM_SEND_COMMAND);

+ +	cmd->status = cmd->send_cmd->retval;

+ +	dbg(ctx, "%s: got SEND cmd: in: %d, out: %d, retval: %d, status: %d\n",

+ +		devname, cmd->send_cmd->in.size, cmd->send_cmd->out.size,

+ +		rc, cmd->status);

+ +

+ +	return rc;

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd)

+ +{

+ +	return cmd->status;

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_get_out_size(struct cxl_cmd *cmd)

+ +{

+ +	return cmd->send_cmd->out.size;

+ +}

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 2616e5c..3900f90 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -20,6 +20,15 @@ global:

+  	cxl_memdev_get_pmem_size;

+  	cxl_memdev_get_ram_size;

+  	cxl_memdev_get_firmware_verison;

+ +	cxl_cmd_get_devname;

+ +	cxl_cmd_new_raw;

+ +	cxl_cmd_set_input_payload;

+ +	cxl_cmd_set_output_payload;

+ +	cxl_cmd_ref;

+ +	cxl_cmd_unref;

+ +	cxl_cmd_submit;

+ +	cxl_cmd_get_mbox_status;

+ +	cxl_cmd_get_out_size;

+  local:

+          *;

+  };

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index fc88fa1..87ca17e 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -4,6 +4,9 @@

+  #define _LIBCXL_PRIVATE_H_

+  

+  #include <libkmod.h>

+ +#include <cxl/cxl_mem.h>

+ +#include <ccan/endian/endian.h>

+ +#include <ccan/short_types/short_types.h>

+  

+  #define CXL_EXPORT __attribute__ ((visibility("default")))

+  

+ @@ -21,6 +24,36 @@ struct cxl_memdev {

+  	struct kmod_module *module;

+  };

+  

+ +enum cxl_cmd_query_status {

+ +	CXL_CMD_QUERY_NOT_RUN = 0,

+ +	CXL_CMD_QUERY_OK,

+ +	CXL_CMD_QUERY_UNSUPPORTED,

+ +};

+ +

+ +/**

+ + * struct cxl_cmd - CXL memdev command

+ + * @memdev: the memory device to which the command is being sent

+ + * @query_cmd: structure for the Linux 'Query commands' ioctl

+ + * @send_cmd: structure for the Linux 'Send command' ioctl

+ + * @input_payload: buffer for input payload managed by libcxl

+ + * @output_payload: buffer for output payload managed by libcxl

+ + * @refcount: reference for passing command buffer around

+ + * @query_status: status from query_commands

+ + * @query_idx: index of 'this' command in the query_commands array

+ + * @status: command return status from the device

+ + */

+ +struct cxl_cmd {

+ +	struct cxl_memdev *memdev;

+ +	struct cxl_mem_query_commands *query_cmd;

+ +	struct cxl_send_command *send_cmd;

+ +	void *input_payload;

+ +	void *output_payload;

+ +	int refcount;

+ +	int query_status;

+ +	int query_idx;

+ +	int status;

+ +};

+ +

+  static inline int check_kmod(struct kmod_ctx *kmod_ctx)

+  {

+  	return kmod_ctx ? 0 : -ENXIO;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index fd06790..6e87b80 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -48,6 +48,17 @@ const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+               memdev != NULL; \

+               memdev = cxl_memdev_get_next(memdev))

+  

+ +struct cxl_cmd;

+ +const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);

+ +struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ +int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *in, int size);

+ +int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *out, int size);

+ +void cxl_cmd_ref(struct cxl_cmd *cmd);

+ +void cxl_cmd_unref(struct cxl_cmd *cmd);

+ +int cxl_cmd_submit(struct cxl_cmd *cmd);

+ +int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);

+ +int cxl_cmd_get_out_size(struct cxl_cmd *cmd);

+ +

+  #ifdef __cplusplus

+  } /* extern "C" */

+  #endif

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,157 @@ 

+ From 244862cbbfecda9b6b638eccaca526f4daba2795 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:28 -0600

+ Subject: [PATCH 036/217] libcxl: add support for the 'Identify Device' command

+ 

+ Add APIs to allocate and send an 'Identify Device' command, and

+ accessors to retrieve some of the fields from the resulting data.

+ 

+ Only add a handful accessor functions; more can be added as the need

+ arises. The fields added are fw_revision, partition_align, and

+ lsa_size.

+ 

+ Cc: Ben Widawsky <ben.widawsky@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 52 ++++++++++++++++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym |  4 ++++

+  cxl/lib/private.h  | 19 +++++++++++++++++

+  cxl/libcxl.h       |  4 ++++

+  4 files changed, 79 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 727d599..ed21670 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -13,7 +13,10 @@

+  #include <sys/sysmacros.h>

+  #include <uuid/uuid.h>

+  #include <ccan/list/list.h>

+ +#include <ccan/endian/endian.h>

+ +#include <ccan/minmax/minmax.h>

+  #include <ccan/array_size/array_size.h>

+ +#include <ccan/short_types/short_types.h>

+  

+  #include <util/log.h>

+  #include <util/size.h>

+ @@ -674,6 +677,55 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)

+  	return cxl_memdev_get_devname(cmd->memdev);

+  }

+  

+ +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)

+ +{

+ +	return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev,

+ +		int fw_len)

+ +{

+ +	struct cxl_cmd_identify *id =

+ +			(struct cxl_cmd_identify *)cmd->send_cmd->out.payload;

+ +

+ +	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)

+ +		return -EINVAL;

+ +	if (cmd->status < 0)

+ +		return cmd->status;

+ +

+ +	if (fw_len > 0)

+ +		memcpy(fw_rev, id->fw_revision,

+ +			min(fw_len, CXL_CMD_IDENTIFY_FW_REV_LENGTH));

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT unsigned long long cxl_cmd_identify_get_partition_align(

+ +		struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_identify *id =

+ +			(struct cxl_cmd_identify *)cmd->send_cmd->out.payload;

+ +

+ +	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)

+ +		return -EINVAL;

+ +	if (cmd->status < 0)

+ +		return cmd->status;

+ +

+ +	return le64_to_cpu(id->partition_align);

+ +}

+ +

+ +CXL_EXPORT unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_identify *id =

+ +			(struct cxl_cmd_identify *)cmd->send_cmd->out.payload;

+ +

+ +	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)

+ +		return -EINVAL;

+ +	if (cmd->status < 0)

+ +		return cmd->status;

+ +

+ +	return le32_to_cpu(id->lsa_size);

+ +}

+ +

+  CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,

+  		int opcode)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 3900f90..1dc45f4 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -29,6 +29,10 @@ global:

+  	cxl_cmd_submit;

+  	cxl_cmd_get_mbox_status;

+  	cxl_cmd_get_out_size;

+ +	cxl_cmd_new_identify;

+ +	cxl_cmd_identify_get_fw_rev;

+ +	cxl_cmd_identify_get_partition_align;

+ +	cxl_cmd_identify_get_label_size;

+  local:

+          *;

+  };

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 87ca17e..3273f21 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -54,6 +54,25 @@ struct cxl_cmd {

+  	int status;

+  };

+  

+ +#define CXL_CMD_IDENTIFY_FW_REV_LENGTH 0x10

+ +

+ +struct cxl_cmd_identify {

+ +	char fw_revision[CXL_CMD_IDENTIFY_FW_REV_LENGTH];

+ +	le64 total_capacity;

+ +	le64 volatile_capacity;

+ +	le64 persistent_capacity;

+ +	le64 partition_align;

+ +	le16 info_event_log_size;

+ +	le16 warning_event_log_size;

+ +	le16 failure_event_log_size;

+ +	le16 fatal_event_log_size;

+ +	le32 lsa_size;

+ +	u8 poison_list_max_mer[3];

+ +	le16 inject_poison_limit;

+ +	u8 poison_caps;

+ +	u8 qos_telemetry_caps;

+ +} __attribute__((packed));

+ +

+  static inline int check_kmod(struct kmod_ctx *kmod_ctx)

+  {

+  	return kmod_ctx ? 0 : -ENXIO;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 6e87b80..0f2d5e9 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -58,6 +58,10 @@ void cxl_cmd_unref(struct cxl_cmd *cmd);

+  int cxl_cmd_submit(struct cxl_cmd *cmd);

+  int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);

+  int cxl_cmd_get_out_size(struct cxl_cmd *cmd);

+ +struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);

+ +int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);

+ +unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);

+ +unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd);

+  

+  #ifdef __cplusplus

+  } /* extern "C" */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,575 @@ 

+ From 55ada0eab92d52826c9be0186db664ba9eeba749 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:29 -0600

+ Subject: [PATCH 037/217] libcxl: add GET_HEALTH_INFO mailbox command and

+  accessors

+ 

+ Add libcxl APIs to create a new GET_HEALTH_INFO mailbox command, the

+ command output data structure (privately), and accessor APIs to return

+ the different fields in the health info output.

+ 

+ Cc: Ben Widawsky <ben.widawsky@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 291 +++++++++++++++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym |  29 +++++

+  cxl/lib/private.h  |  47 ++++++++

+  cxl/libcxl.h       |  33 +++++

+  util/bitmap.h      |  85 +++++++++++++

+  5 files changed, 485 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index ed21670..065824d 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -677,6 +677,297 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)

+  	return cxl_memdev_get_devname(cmd->memdev);

+  }

+  

+ +static int cxl_cmd_validate_status(struct cxl_cmd *cmd, u32 id)

+ +{

+ +	if (cmd->send_cmd->id != id)

+ +		return -EINVAL;

+ +	if (cmd->status < 0)

+ +		return cmd->status;

+ +	return 0;

+ +}

+ +

+ +/* Helpers for health_info fields (no endian conversion) */

+ +#define cmd_get_field_u8(cmd, n, N, field)				\

+ +do {									\

+ +	struct cxl_cmd_##n *c =						\

+ +		(struct cxl_cmd_##n *)cmd->send_cmd->out.payload;	\

+ +	int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N);	\

+ +	if (rc)								\

+ +		return rc;						\

+ +	return c->field;						\

+ +} while(0)

+ +

+ +#define cmd_get_field_u16(cmd, n, N, field)				\

+ +do {									\

+ +	struct cxl_cmd_##n *c =						\

+ +		(struct cxl_cmd_##n *)cmd->send_cmd->out.payload;	\

+ +	int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N);	\

+ +	if (rc)								\

+ +		return rc;						\

+ +	return le16_to_cpu(c->field);					\

+ +} while(0)

+ +

+ +

+ +#define cmd_get_field_u32(cmd, n, N, field)				\

+ +do {									\

+ +	struct cxl_cmd_##n *c =						\

+ +		(struct cxl_cmd_##n *)cmd->send_cmd->out.payload;	\

+ +	int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N);	\

+ +	if (rc)								\

+ +		return rc;						\

+ +	return le32_to_cpu(c->field);					\

+ +} while(0)

+ +

+ +

+ +#define cmd_get_field_u8_mask(cmd, n, N, field, mask)			\

+ +do {									\

+ +	struct cxl_cmd_##n *c =						\

+ +		(struct cxl_cmd_##n *)cmd->send_cmd->out.payload;	\

+ +	int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N);	\

+ +	if (rc)								\

+ +		return rc;						\

+ +	return !!(c->field & mask);					\

+ +} while(0)

+ +

+ +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_health_info(

+ +		struct cxl_memdev *memdev)

+ +{

+ +	return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_HEALTH_INFO);

+ +}

+ +

+ +#define cmd_health_get_status_field(c, m)					\

+ +	cmd_get_field_u8_mask(c, get_health_info, GET_HEALTH_INFO, health_status, m)

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_maintenance_needed(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_get_status_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_STATUS_MAINTENANCE_NEEDED_MASK);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_performance_degraded(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_get_status_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_STATUS_PERFORMANCE_DEGRADED_MASK);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_hw_replacement_needed(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_get_status_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_STATUS_HW_REPLACEMENT_NEEDED_MASK);

+ +}

+ +

+ +#define cmd_health_check_media_field(cmd, f)					\

+ +do {										\

+ +	struct cxl_cmd_get_health_info *c =					\

+ +		(struct cxl_cmd_get_health_info *)cmd->send_cmd->out.payload;	\

+ +	int rc = cxl_cmd_validate_status(cmd,					\

+ +			CXL_MEM_COMMAND_ID_GET_HEALTH_INFO);			\

+ +	if (rc)									\

+ +		return rc;							\

+ +	return (c->media_status == f);						\

+ +} while(0)

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_media_normal(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NORMAL);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_media_not_ready(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NOT_READY);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_media_persistence_lost(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOST);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_media_data_lost(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOST);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_media_powerloss_persistence_loss(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_PERSISTENCE_LOSS);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_media_shutdown_persistence_loss(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_PERSISTENCE_LOSS);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_media_persistence_loss_imminent(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOSS_IMMINENT);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_media_powerloss_data_loss(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_DATA_LOSS);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_media_shutdown_data_loss(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_DATA_LOSS);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_media_data_loss_imminent(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_media_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOSS_IMMINENT);

+ +}

+ +

+ +#define cmd_health_check_ext_field(cmd, fname, type)				\

+ +do {										\

+ +	struct cxl_cmd_get_health_info *c =					\

+ +		(struct cxl_cmd_get_health_info *)cmd->send_cmd->out.payload;	\

+ +	int rc = cxl_cmd_validate_status(cmd,					\

+ +			CXL_MEM_COMMAND_ID_GET_HEALTH_INFO);			\

+ +	if (rc)									\

+ +		return rc;							\

+ +	return (FIELD_GET(fname##_MASK, c->ext_status) ==			\

+ +		fname##_##type);						\

+ +} while(0)

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_life_used_normal(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_LIFE_USED, NORMAL);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_life_used_warning(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_LIFE_USED, WARNING);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_life_used_critical(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_LIFE_USED, CRITICAL);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_temperature_normal(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE, NORMAL);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_temperature_warning(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE, WARNING);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_temperature_critical(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE, CRITICAL);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_corrected_volatile_normal(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE, NORMAL);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_corrected_volatile_warning(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE, WARNING);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_corrected_persistent_normal(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT, NORMAL);

+ +}

+ +

+ +CXL_EXPORT int

+ +cxl_cmd_health_info_get_ext_corrected_persistent_warning(struct cxl_cmd *cmd)

+ +{

+ +	cmd_health_check_ext_field(cmd,

+ +		CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT, WARNING);

+ +}

+ +

+ +static int health_info_get_life_used_raw(struct cxl_cmd *cmd)

+ +{

+ +	cmd_get_field_u8(cmd, get_health_info, GET_HEALTH_INFO,

+ +				life_used);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_life_used(struct cxl_cmd *cmd)

+ +{

+ +	int rc = health_info_get_life_used_raw(cmd);

+ +

+ +	if (rc < 0)

+ +		return rc;

+ +	if (rc == CXL_CMD_HEALTH_INFO_LIFE_USED_NOT_IMPL)

+ +		return -EOPNOTSUPP;

+ +	return rc;

+ +}

+ +

+ +static int health_info_get_temperature_raw(struct cxl_cmd *cmd)

+ +{

+ +	cmd_get_field_u16(cmd, get_health_info, GET_HEALTH_INFO,

+ +				 temperature);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_temperature(struct cxl_cmd *cmd)

+ +{

+ +	int rc = health_info_get_temperature_raw(cmd);

+ +

+ +	if (rc < 0)

+ +		return rc;

+ +	if (rc == CXL_CMD_HEALTH_INFO_TEMPERATURE_NOT_IMPL)

+ +		return -EOPNOTSUPP;

+ +	return rc;

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd)

+ +{

+ +	cmd_get_field_u32(cmd, get_health_info, GET_HEALTH_INFO,

+ +				 dirty_shutdowns);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_volatile_errors(struct cxl_cmd *cmd)

+ +{

+ +	cmd_get_field_u32(cmd, get_health_info, GET_HEALTH_INFO,

+ +				 volatile_errors);

+ +}

+ +

+ +CXL_EXPORT int cxl_cmd_health_info_get_pmem_errors(struct cxl_cmd *cmd)

+ +{

+ +	cmd_get_field_u32(cmd, get_health_info, GET_HEALTH_INFO,

+ +				 pmem_errors);

+ +}

+ +

+  CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)

+  {

+  	return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 1dc45f4..c83bc28 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -33,6 +33,35 @@ global:

+  	cxl_cmd_identify_get_fw_rev;

+  	cxl_cmd_identify_get_partition_align;

+  	cxl_cmd_identify_get_label_size;

+ +	cxl_cmd_new_get_health_info;

+ +	cxl_cmd_health_info_get_maintenance_needed;

+ +	cxl_cmd_health_info_get_performance_degraded;

+ +	cxl_cmd_health_info_get_hw_replacement_needed;

+ +	cxl_cmd_health_info_get_media_normal;

+ +	cxl_cmd_health_info_get_media_not_ready;

+ +	cxl_cmd_health_info_get_media_persistence_lost;

+ +	cxl_cmd_health_info_get_media_data_lost;

+ +	cxl_cmd_health_info_get_media_powerloss_persistence_loss;

+ +	cxl_cmd_health_info_get_media_shutdown_persistence_loss;

+ +	cxl_cmd_health_info_get_media_persistence_loss_imminent;

+ +	cxl_cmd_health_info_get_media_powerloss_data_loss;

+ +	cxl_cmd_health_info_get_media_shutdown_data_loss;

+ +	cxl_cmd_health_info_get_media_data_loss_imminent;

+ +	cxl_cmd_health_info_get_ext_life_used_normal;

+ +	cxl_cmd_health_info_get_ext_life_used_warning;

+ +	cxl_cmd_health_info_get_ext_life_used_critical;

+ +	cxl_cmd_health_info_get_ext_temperature_normal;

+ +	cxl_cmd_health_info_get_ext_temperature_warning;

+ +	cxl_cmd_health_info_get_ext_temperature_critical;

+ +	cxl_cmd_health_info_get_ext_corrected_volatile_normal;

+ +	cxl_cmd_health_info_get_ext_corrected_volatile_warning;

+ +	cxl_cmd_health_info_get_ext_corrected_persistent_normal;

+ +	cxl_cmd_health_info_get_ext_corrected_persistent_warning;

+ +	cxl_cmd_health_info_get_life_used;

+ +	cxl_cmd_health_info_get_temperature;

+ +	cxl_cmd_health_info_get_dirty_shutdowns;

+ +	cxl_cmd_health_info_get_volatile_errors;

+ +	cxl_cmd_health_info_get_pmem_errors;

+  local:

+          *;

+  };

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 3273f21..885553a 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -73,6 +73,53 @@ struct cxl_cmd_identify {

+  	u8 qos_telemetry_caps;

+  } __attribute__((packed));

+  

+ +struct cxl_cmd_get_health_info {

+ +	u8 health_status;

+ +	u8 media_status;

+ +	u8 ext_status;

+ +	u8 life_used;

+ +	le16 temperature;

+ +	le32 dirty_shutdowns;

+ +	le32 volatile_errors;

+ +	le32 pmem_errors;

+ +} __attribute__((packed));

+ +

+ +/* CXL 2.0 8.2.9.5.3 Byte 0 Health Status */

+ +#define CXL_CMD_HEALTH_INFO_STATUS_MAINTENANCE_NEEDED_MASK		BIT(0)

+ +#define CXL_CMD_HEALTH_INFO_STATUS_PERFORMANCE_DEGRADED_MASK		BIT(1)

+ +#define CXL_CMD_HEALTH_INFO_STATUS_HW_REPLACEMENT_NEEDED_MASK		BIT(2)

+ +

+ +/* CXL 2.0 8.2.9.5.3 Byte 1 Media Status */

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NORMAL				0x0

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NOT_READY			0x1

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOST		0x2

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOST			0x3

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_PERSISTENCE_LOSS	0x4

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_PERSISTENCE_LOSS	0x5

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOSS_IMMINENT	0x6

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_DATA_LOSS		0x7

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_DATA_LOSS		0x8

+ +#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOSS_IMMINENT		0x9

+ +

+ +/* CXL 2.0 8.2.9.5.3 Byte 2 Additional Status */

+ +#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_MASK				GENMASK(1, 0)

+ +#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_NORMAL			(0)

+ +#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_WARNING			(1)

+ +#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_CRITICAL			(2)

+ +#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_MASK			GENMASK(3, 2)

+ +#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_NORMAL			(0)

+ +#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_WARNING			(1)

+ +#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_CRITICAL			(2)

+ +#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE_MASK			BIT(4)

+ +#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE_NORMAL		(0)

+ +#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE_WARNING		(1)

+ +#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT_MASK		BIT(5)

+ +#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT_NORMAL		(0)

+ +#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT_WARNING		(1)

+ +

+ +#define CXL_CMD_HEALTH_INFO_LIFE_USED_NOT_IMPL				0xff

+ +#define CXL_CMD_HEALTH_INFO_TEMPERATURE_NOT_IMPL			0xffff

+ +

+  static inline int check_kmod(struct kmod_ctx *kmod_ctx)

+  {

+  	return kmod_ctx ? 0 : -ENXIO;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 0f2d5e9..eae2db8 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -62,6 +62,39 @@ struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);

+  int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);

+  unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);

+  unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd);

+ +struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev);

+ +int cxl_cmd_health_info_get_maintenance_needed(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_performance_degraded(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_hw_replacement_needed(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_normal(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_not_ready(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_persistence_lost(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_data_lost(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_normal(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_not_ready(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_persistence_lost(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_data_lost(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_powerloss_persistence_loss(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_shutdown_persistence_loss(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_persistence_loss_imminent(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_powerloss_data_loss(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_shutdown_data_loss(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_media_data_loss_imminent(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_life_used_normal(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_life_used_warning(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_life_used_critical(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_temperature_normal(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_temperature_warning(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_temperature_critical(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_corrected_volatile_normal(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_corrected_volatile_warning(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_corrected_persistent_normal(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_ext_corrected_persistent_warning(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_life_used(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_temperature(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_volatile_errors(struct cxl_cmd *cmd);

+ +int cxl_cmd_health_info_get_pmem_errors(struct cxl_cmd *cmd);

+  

+  #ifdef __cplusplus

+  } /* extern "C" */

+ diff --git a/util/bitmap.h b/util/bitmap.h

+ index 490f3f0..04b3429 100644

+ --- a/util/bitmap.h

+ +++ b/util/bitmap.h

+ @@ -3,10 +3,33 @@

+  #ifndef _NDCTL_BITMAP_H_

+  #define _NDCTL_BITMAP_H_

+  

+ +#include <linux/const.h>

+  #include <util/size.h>

+ +#include <util/util.h>

+  #include <ccan/short_types/short_types.h>

+  

+ +#ifndef _UL

+ +#define _UL(x)		(_AC(x, UL))

+ +#endif

+ +#ifndef _ULL

+ +#define _ULL(x)		(_AC(x, ULL))

+ +#endif

+ +

+  #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))

+ +#define UL(x)		(_UL(x))

+ +#define ULL(x)		(_ULL(x))

+ +

+ +/* GENMASK() and its dependencies copied from include/linux/{bits.h, const.h} */

+ +#define __is_constexpr(x) \

+ +	(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))

+ +#define GENMASK_INPUT_CHECK(h, l) \

+ +	(BUILD_BUG_ON_ZERO(__builtin_choose_expr( \

+ +		__is_constexpr((l) > (h)), (l) > (h), 0)))

+ +#define __GENMASK(h, l) \

+ +	(((~UL(0)) - (UL(1) << (l)) + 1) & \

+ +	 (~UL(0) >> (BITS_PER_LONG - 1 - (h))))

+ +#define GENMASK(h, l) \

+ +	(GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l))

+  

+  #define BIT(nr)			(1UL << (nr))

+  #define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))

+ @@ -30,5 +53,67 @@ unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,

+  				 unsigned long offset);

+  int bitmap_full(const unsigned long *src, unsigned int nbits);

+  

+ +/*

+ + * Bitfield access macros

+ + * (Copied from Linux's include/linux/bitfield.h)

+ + *

+ + * FIELD_{GET,PREP} macros take as first parameter shifted mask

+ + * from which they extract the base mask and shift amount.

+ + * Mask must be a compilation time constant.

+ + *

+ + * Example:

+ + *

+ + *  #define REG_FIELD_A  GENMASK(6, 0)

+ + *  #define REG_FIELD_B  BIT(7)

+ + *  #define REG_FIELD_C  GENMASK(15, 8)

+ + *  #define REG_FIELD_D  GENMASK(31, 16)

+ + *

+ + * Get:

+ + *  a = FIELD_GET(REG_FIELD_A, reg);

+ + *  b = FIELD_GET(REG_FIELD_B, reg);

+ + *

+ + * Set:

+ + *  reg = FIELD_PREP(REG_FIELD_A, 1) |

+ + *	  FIELD_PREP(REG_FIELD_B, 0) |

+ + *	  FIELD_PREP(REG_FIELD_C, c) |

+ + *	  FIELD_PREP(REG_FIELD_D, 0x40);

+ + *

+ + * Modify:

+ + *  reg &= ~REG_FIELD_C;

+ + *  reg |= FIELD_PREP(REG_FIELD_C, c);

+ + */

+ +

+ +/* Force a compilation error if a constant expression is not a power of 2 */

+ +#define __BUILD_BUG_ON_NOT_POWER_OF_2(n)	\

+ +	BUILD_BUG_ON(((n) & ((n) - 1)) != 0)

+ +#define BUILD_BUG_ON_NOT_POWER_OF_2(n)			\

+ +	BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))

+ +

+ +#define __bf_shf(x) (__builtin_ffsll(x) - 1)

+ +

+ +#define __BF_FIELD_CHECK(_mask, _reg, _val)					\

+ +	({									\

+ +		BUILD_BUG_ON(!__builtin_constant_p(_mask));			\

+ +		BUILD_BUG_ON((_mask) == 0);					\

+ +		BUILD_BUG_ON(__builtin_constant_p(_val) ?			\

+ +				 ~((_mask) >> __bf_shf(_mask)) & (_val) : 0);	\

+ +		BUILD_BUG_ON((_mask) > (typeof(_reg))~0ull);			\

+ +		__BUILD_BUG_ON_NOT_POWER_OF_2((_mask) +				\

+ +					      (1ULL << __bf_shf(_mask))); 	\

+ +	})

+ +

+ +/**

+ + * FIELD_GET() - extract a bitfield element

+ + * @_mask: shifted mask defining the field's length and position

+ + * @_reg:  value of entire bitfield

+ + *

+ + * FIELD_GET() extracts the field specified by @_mask from the

+ + * bitfield passed in as @_reg by masking and shifting it down.

+ + */

+ +#define FIELD_GET(_mask, _reg)						\

+ +	({								\

+ +		__BF_FIELD_CHECK(_mask, _reg, 0U);			\

+ +		(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask));	\

+ +	})

+  

+  #endif /* _NDCTL_BITMAP_H_ */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,113 @@ 

+ From c7ae078f1050ed54e254377404af2ae0879f2a39 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:30 -0600

+ Subject: [PATCH 038/217] libcxl: add support for the 'GET_LSA' command

+ 

+ Add a command allocator and accessor APIs for the 'GET_LSA' mailbox

+ command.

+ 

+ Cc: Ben Widawsky <ben.widawsky@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 36 ++++++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym |  2 ++

+  cxl/lib/private.h  |  5 +++++

+  cxl/libcxl.h       |  4 ++++

+  4 files changed, 47 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 065824d..76913a2 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1036,6 +1036,42 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,

+  	return cmd;

+  }

+  

+ +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,

+ +		unsigned int offset, unsigned int length)

+ +{

+ +	struct cxl_cmd_get_lsa_in *get_lsa;

+ +	struct cxl_cmd *cmd;

+ +

+ +	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_LSA);

+ +	if (!cmd)

+ +		return NULL;

+ +

+ +	get_lsa = (struct cxl_cmd_get_lsa_in *)cmd->send_cmd->in.payload;

+ +	get_lsa->offset = cpu_to_le32(offset);

+ +	get_lsa->length = cpu_to_le32(length);

+ +	return cmd;

+ +}

+ +

+ +CXL_EXPORT ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd,

+ +		void *buf, unsigned int length)

+ +{

+ +	struct cxl_cmd_get_lsa_in *get_lsa;

+ +	void *payload;

+ +	int rc;

+ +

+ +	rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_GET_LSA);

+ +	if (rc)

+ +		return rc;

+ +

+ +	get_lsa = (struct cxl_cmd_get_lsa_in *)cmd->send_cmd->in.payload;

+ +	if (length > le32_to_cpu(get_lsa->length))

+ +		return -EINVAL;

+ +

+ +	payload = (void *)cmd->send_cmd->out.payload;

+ +	memcpy(buf, payload, length);

+ +	return length;

+ +}

+ +

+  CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)

+  {

+  	struct cxl_memdev *memdev = cmd->memdev;

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index c83bc28..629322c 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -62,6 +62,8 @@ global:

+  	cxl_cmd_health_info_get_dirty_shutdowns;

+  	cxl_cmd_health_info_get_volatile_errors;

+  	cxl_cmd_health_info_get_pmem_errors;

+ +	cxl_cmd_new_read_label;

+ +	cxl_cmd_read_label_get_payload;

+  local:

+          *;

+  };

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 885553a..bf3a897 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -73,6 +73,11 @@ struct cxl_cmd_identify {

+  	u8 qos_telemetry_caps;

+  } __attribute__((packed));

+  

+ +struct cxl_cmd_get_lsa_in {

+ +	le32 offset;

+ +	le32 length;

+ +} __attribute__((packed));

+ +

+  struct cxl_cmd_get_health_info {

+  	u8 health_status;

+  	u8 media_status;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index eae2db8..7408745 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -95,6 +95,10 @@ int cxl_cmd_health_info_get_temperature(struct cxl_cmd *cmd);

+  int cxl_cmd_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);

+  int cxl_cmd_health_info_get_volatile_errors(struct cxl_cmd *cmd);

+  int cxl_cmd_health_info_get_pmem_errors(struct cxl_cmd *cmd);

+ +struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,

+ +		unsigned int offset, unsigned int length);

+ +ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd, void *buf,

+ +		unsigned int length);

+  

+  #ifdef __cplusplus

+  } /* extern "C" */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,89 @@ 

+ From 101966ed3e4a73a6e0e1c269306e976040e068a9 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:32 -0600

+ Subject: [PATCH 039/217] libcxl: add label_size to cxl_memdev, and an API to

+  retrieve it

+ 

+ Size of the Label Storage Area (LSA) is available as a sysfs attribute

+ called 'label_storage_size'. Add that to libcxl's memdev so that it is available

+ for label related commands.

+ 

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 12 ++++++++++++

+  cxl/lib/libcxl.sym |  1 +

+  cxl/lib/private.h  |  1 +

+  cxl/libcxl.h       |  1 +

+  4 files changed, 15 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 76913a2..def3a97 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -247,6 +247,13 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  	if (memdev->payload_max < 0)

+  		goto err_read;

+  

+ +	sprintf(path, "%s/label_storage_size", cxlmem_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		goto err_read;

+ +	memdev->lsa_size = strtoull(buf, NULL, 0);

+ +	if (memdev->lsa_size == ULLONG_MAX)

+ +		goto err_read;

+ +

+  	memdev->dev_path = strdup(cxlmem_base);

+  	if (!memdev->dev_path)

+  		goto err_read;

+ @@ -350,6 +357,11 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev

+  	return memdev->firmware_version;

+  }

+  

+ +CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)

+ +{

+ +	return memdev->lsa_size;

+ +}

+ +

+  CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)

+  {

+  	if (!cmd)

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 629322c..858e953 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -64,6 +64,7 @@ global:

+  	cxl_cmd_health_info_get_pmem_errors;

+  	cxl_cmd_new_read_label;

+  	cxl_cmd_read_label_get_payload;

+ +	cxl_memdev_get_label_size;

+  local:

+          *;

+  };

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index bf3a897..c4ed741 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -21,6 +21,7 @@ struct cxl_memdev {

+  	unsigned long long pmem_size;

+  	unsigned long long ram_size;

+  	int payload_max;

+ +	size_t lsa_size;

+  	struct kmod_module *module;

+  };

+  

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 7408745..d3b97a1 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -42,6 +42,7 @@ struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+ +size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);

+  

+  #define cxl_memdev_foreach(ctx, memdev) \

+          for (memdev = cxl_memdev_get_first(ctx); \

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,184 @@ 

+ From cd1aed6cefe8f4f2043349e1a614876f67743439 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:33 -0600

+ Subject: [PATCH 040/217] libcxl: add representation for an nvdimm bridge

+  object

+ 

+ Add an nvdimm bridge object representation internal to libcxl. A bridge

+ object is tied to its parent memdev object, and this patch adds its

+ first interface, which checks whether a bridge is 'active' - i.e.

+ implying the label space on the memdev is owned by the kernel.

+ 

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 73 ++++++++++++++++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym |  1 +

+  cxl/lib/private.h  |  8 +++++

+  cxl/libcxl.h       |  1 +

+  4 files changed, 83 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index def3a97..60ed646 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -45,11 +45,19 @@ struct cxl_ctx {

+  	void *private_data;

+  };

+  

+ +static void free_bridge(struct cxl_nvdimm_bridge *bridge)

+ +{

+ +	free(bridge->dev_buf);

+ +	free(bridge->dev_path);

+ +	free(bridge);

+ +}

+ +

+  static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+  {

+  	if (head)

+  		list_del_from(head, &memdev->list);

+  	kmod_module_unref(memdev->module);

+ +	free_bridge(memdev->bridge);

+  	free(memdev->firmware_version);

+  	free(memdev->dev_buf);

+  	free(memdev->dev_path);

+ @@ -205,6 +213,40 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)

+  	ctx->ctx.log_priority = priority;

+  }

+  

+ +static void *add_cxl_bridge(void *parent, int id, const char *br_base)

+ +{

+ +	const char *devname = devpath_to_devname(br_base);

+ +	struct cxl_memdev *memdev = parent;

+ +	struct cxl_ctx *ctx = memdev->ctx;

+ +	struct cxl_nvdimm_bridge *bridge;

+ +

+ +	dbg(ctx, "%s: bridge_base: \'%s\'\n", devname, br_base);

+ +

+ +	bridge = calloc(1, sizeof(*bridge));

+ +	if (!bridge)

+ +		goto err_dev;

+ +	bridge->id = id;

+ +

+ +	bridge->dev_path = strdup(br_base);

+ +	if (!bridge->dev_path)

+ +		goto err_read;

+ +

+ +	bridge->dev_buf = calloc(1, strlen(br_base) + 50);

+ +	if (!bridge->dev_buf)

+ +		goto err_read;

+ +	bridge->buf_len = strlen(br_base) + 50;

+ +

+ +	memdev->bridge = bridge;

+ +	return bridge;

+ +

+ + err_read:

+ +	free(bridge->dev_buf);

+ +	free(bridge->dev_path);

+ +	free(bridge);

+ + err_dev:

+ +	return NULL;

+ +}

+ +

+  static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  {

+  	const char *devname = devpath_to_devname(cxlmem_base);

+ @@ -271,6 +313,8 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  		goto err_read;

+  	memdev->buf_len = strlen(cxlmem_base) + 50;

+  

+ +	sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_bridge);

+ +

+  	cxl_memdev_foreach(ctx, memdev_dup)

+  		if (memdev_dup->id == memdev->id) {

+  			free_memdev(memdev, NULL);

+ @@ -362,6 +406,35 @@ CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)

+  	return memdev->lsa_size;

+  }

+  

+ +static int is_enabled(const char *drvpath)

+ +{

+ +	struct stat st;

+ +

+ +	if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode))

+ +		return 0;

+ +	else

+ +		return 1;

+ +}

+ +

+ +CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	struct cxl_nvdimm_bridge *bridge = memdev->bridge;

+ +	char *path = bridge->dev_buf;

+ +	int len = bridge->buf_len;

+ +

+ +	if (!bridge)

+ +		return 0;

+ +

+ +	if (snprintf(path, len, "%s/driver", bridge->dev_path) >= len) {

+ +		err(ctx, "%s: nvdimm bridge buffer too small!\n",

+ +				cxl_memdev_get_devname(memdev));

+ +		return 0;

+ +	}

+ +

+ +	return is_enabled(path);

+ +}

+ +

+  CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)

+  {

+  	if (!cmd)

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 858e953..f3b0c63 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -65,6 +65,7 @@ global:

+  	cxl_cmd_new_read_label;

+  	cxl_cmd_read_label_get_payload;

+  	cxl_memdev_get_label_size;

+ +	cxl_memdev_nvdimm_bridge_active;

+  local:

+          *;

+  };

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index c4ed741..525c41e 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -10,6 +10,13 @@

+  

+  #define CXL_EXPORT __attribute__ ((visibility("default")))

+  

+ +struct cxl_nvdimm_bridge {

+ +	int id;

+ +	void *dev_buf;

+ +	size_t buf_len;

+ +	char *dev_path;

+ +};

+ +

+  struct cxl_memdev {

+  	int id, major, minor;

+  	void *dev_buf;

+ @@ -23,6 +30,7 @@ struct cxl_memdev {

+  	int payload_max;

+  	size_t lsa_size;

+  	struct kmod_module *module;

+ +	struct cxl_nvdimm_bridge *bridge;

+  };

+  

+  enum cxl_cmd_query_status {

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index d3b97a1..535e349 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -43,6 +43,7 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+  size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);

+ +int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);

+  

+  #define cxl_memdev_foreach(ctx, memdev) \

+          for (memdev = cxl_memdev_get_first(ctx); \

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,247 @@ 

+ From 6255d23452809ddc6d48083c35fc935e4fa420d8 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:34 -0600

+ Subject: [PATCH 041/217] libcxl: add interfaces for label operations

+ 

+ Add libcxl interfaces to allow performinfg label (LSA) manipulations.

+ Add a 'cxl_cmd_new_set_lsa' interface to create a 'Set LSA' mailbox

+ command payload, and interfaces to read, write, and zero the LSA area on

+ a memdev.

+ 

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 158 +++++++++++++++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym |   4 ++

+  cxl/lib/private.h  |   6 ++

+  cxl/libcxl.h       |   8 +++

+  4 files changed, 176 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 60ed646..f0664be 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1197,3 +1197,161 @@ CXL_EXPORT int cxl_cmd_get_out_size(struct cxl_cmd *cmd)

+  {

+  	return cmd->send_cmd->out.size;

+  }

+ +

+ +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev,

+ +		void *lsa_buf, unsigned int offset, unsigned int length)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	struct cxl_cmd_set_lsa *set_lsa;

+ +	struct cxl_cmd *cmd;

+ +	int rc;

+ +

+ +	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_SET_LSA);

+ +	if (!cmd)

+ +		return NULL;

+ +

+ +	/* this will allocate 'in.payload' */

+ +	rc = cxl_cmd_set_input_payload(cmd, NULL, sizeof(*set_lsa) + length);

+ +	if (rc) {

+ +		err(ctx, "%s: cmd setup failed: %s\n",

+ +			cxl_memdev_get_devname(memdev), strerror(-rc));

+ +		goto out_fail;

+ +	}

+ +	set_lsa = (struct cxl_cmd_set_lsa *)cmd->send_cmd->in.payload;

+ +	set_lsa->offset = cpu_to_le32(offset);

+ +	memcpy(set_lsa->lsa_data, lsa_buf, length);

+ +

+ +	return cmd;

+ +

+ +out_fail:

+ +	cxl_cmd_unref(cmd);

+ +	return NULL;

+ +}

+ +

+ +enum lsa_op {

+ +	LSA_OP_GET,

+ +	LSA_OP_SET,

+ +	LSA_OP_ZERO,

+ +};

+ +

+ +static int __lsa_op(struct cxl_memdev *memdev, int op, void *buf,

+ +		size_t length, size_t offset)

+ +{

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	void *zero_buf = NULL;

+ +	struct cxl_cmd *cmd;

+ +	ssize_t ret_len;

+ +	int rc = 0;

+ +

+ +	switch (op) {

+ +	case LSA_OP_GET:

+ +		cmd = cxl_cmd_new_read_label(memdev, offset, length);

+ +		if (!cmd)

+ +			return -ENOMEM;

+ +		rc = cxl_cmd_set_output_payload(cmd, buf, length);

+ +		if (rc) {

+ +			err(ctx, "%s: cmd setup failed: %s\n",

+ +			    cxl_memdev_get_devname(memdev), strerror(-rc));

+ +			goto out;

+ +		}

+ +		break;

+ +	case LSA_OP_ZERO:

+ +		zero_buf = calloc(1, length);

+ +		if (!zero_buf)

+ +			return -ENOMEM;

+ +		buf = zero_buf;

+ +		/* fall through */

+ +	case LSA_OP_SET:

+ +		cmd = cxl_cmd_new_write_label(memdev, buf, offset, length);

+ +		if (!cmd) {

+ +			rc = -ENOMEM;

+ +			goto out_free;

+ +		}

+ +		break;

+ +	default:

+ +		return -EOPNOTSUPP;

+ +	}

+ +

+ +	rc = cxl_cmd_submit(cmd);

+ +	if (rc < 0) {

+ +		err(ctx, "%s: cmd submission failed: %s\n",

+ +			devname, strerror(-rc));

+ +		goto out;

+ +	}

+ +

+ +	rc = cxl_cmd_get_mbox_status(cmd);

+ +	if (rc != 0) {

+ +		err(ctx, "%s: firmware status: %d\n",

+ +			devname, rc);

+ +		rc = -ENXIO;

+ +		goto out;

+ +	}

+ +

+ +	if (op == LSA_OP_GET) {

+ +		ret_len = cxl_cmd_read_label_get_payload(cmd, buf, length);

+ +		if (ret_len < 0) {

+ +			rc = ret_len;

+ +			goto out;

+ +		}

+ +	}

+ +

+ +out:

+ +	cxl_cmd_unref(cmd);

+ +out_free:

+ +	free(zero_buf);

+ +	return rc;

+ +

+ +}

+ +

+ +static int lsa_op(struct cxl_memdev *memdev, int op, void *buf,

+ +		size_t length, size_t offset)

+ +{

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	size_t remaining = length, cur_len, cur_off = 0;

+ +	int label_iter_max, rc = 0;

+ +

+ +	if (op != LSA_OP_ZERO && buf == NULL) {

+ +		err(ctx, "%s: LSA buffer cannot be NULL\n", devname);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (length == 0)

+ +		return 0;

+ +

+ +	label_iter_max = memdev->payload_max - sizeof(struct cxl_cmd_set_lsa);

+ +	while (remaining) {

+ +		cur_len = min((size_t)label_iter_max, remaining);

+ +		rc = __lsa_op(memdev, op, buf + cur_off,

+ +				cur_len, offset + cur_off);

+ +		if (rc)

+ +			break;

+ +

+ +		remaining -= cur_len;

+ +		cur_off += cur_len;

+ +	}

+ +

+ +	if (rc && (op == LSA_OP_SET))

+ +		err(ctx, "%s: labels may be in an inconsistent state\n",

+ +			devname);

+ +	return rc;

+ +}

+ +

+ +CXL_EXPORT int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,

+ +		size_t offset)

+ +{

+ +	return lsa_op(memdev, LSA_OP_ZERO, NULL, length, offset);

+ +}

+ +

+ +CXL_EXPORT int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf,

+ +		size_t length, size_t offset)

+ +{

+ +	return lsa_op(memdev, LSA_OP_SET, buf, length, offset);

+ +}

+ +

+ +CXL_EXPORT int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf,

+ +		size_t length, size_t offset)

+ +{

+ +	return lsa_op(memdev, LSA_OP_GET, buf, length, offset);

+ +}

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index f3b0c63..077d104 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -66,6 +66,10 @@ global:

+  	cxl_cmd_read_label_get_payload;

+  	cxl_memdev_get_label_size;

+  	cxl_memdev_nvdimm_bridge_active;

+ +	cxl_cmd_new_write_label;

+ +	cxl_memdev_zero_label;

+ +	cxl_memdev_write_label;

+ +	cxl_memdev_read_label;

+  local:

+          *;

+  };

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 525c41e..a1b8b50 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -87,6 +87,12 @@ struct cxl_cmd_get_lsa_in {

+  	le32 length;

+  } __attribute__((packed));

+  

+ +struct cxl_cmd_set_lsa {

+ +	le32 offset;

+ +	le32 rsvd;

+ +	unsigned char lsa_data[0];

+ +} __attribute__ ((packed));

+ +

+  struct cxl_cmd_get_health_info {

+  	u8 health_status;

+  	u8 media_status;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 535e349..89d35ba 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -44,6 +44,12 @@ unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+  size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);

+  int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);

+ +int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,

+ +		size_t offset);

+ +int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length,

+ +		size_t offset);

+ +int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,

+ +		size_t offset);

+  

+  #define cxl_memdev_foreach(ctx, memdev) \

+          for (memdev = cxl_memdev_get_first(ctx); \

+ @@ -101,6 +107,8 @@ struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,

+  		unsigned int offset, unsigned int length);

+  ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd, void *buf,

+  		unsigned int length);

+ +struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev,

+ +		void *buf, unsigned int offset, unsigned int length);

+  

+  #ifdef __cplusplus

+  } /* extern "C" */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,583 @@ 

+ From c415cebe4b5ca50e06db78a4719f312e33106936 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:35 -0600

+ Subject: [PATCH 042/217] cxl: add commands to read, write, and zero labels

+ 

+ Add the following cxl-cli commands: read-labels, write-labels,

+ zero-labels. They operate on a CXL memdev, or a set of memdevs, and

+ allow interacting with the label storage area (LSA) on the device.

+ 

+ Add man pages for the above cxl-cli commands.

+ 

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/Makefile.am            |   5 +-

+  Documentation/cxl/cxl-read-labels.txt    |  33 +++

+  Documentation/cxl/cxl-write-labels.txt   |  32 +++

+  Documentation/cxl/cxl-zero-labels.txt    |  29 ++

+  Documentation/cxl/labels-description.txt |   8 +

+  Documentation/cxl/labels-options.txt     |  17 ++

+  Documentation/cxl/memdev-option.txt      |   4 +

+  cxl/Makefile.am                          |   1 +

+  cxl/builtin.h                            |   5 +

+  cxl/cxl.c                                |   3 +

+  cxl/memdev.c                             | 324 +++++++++++++++++++++++

+  11 files changed, 460 insertions(+), 1 deletion(-)

+  create mode 100644 Documentation/cxl/cxl-read-labels.txt

+  create mode 100644 Documentation/cxl/cxl-write-labels.txt

+  create mode 100644 Documentation/cxl/cxl-zero-labels.txt

+  create mode 100644 Documentation/cxl/labels-description.txt

+  create mode 100644 Documentation/cxl/labels-options.txt

+  create mode 100644 Documentation/cxl/memdev-option.txt

+  create mode 100644 cxl/memdev.c

+ 

+ diff --git a/Documentation/cxl/Makefile.am b/Documentation/cxl/Makefile.am

+ index db98dd7..efabaa3 100644

+ --- a/Documentation/cxl/Makefile.am

+ +++ b/Documentation/cxl/Makefile.am

+ @@ -19,7 +19,10 @@ endif

+  

+  man1_MANS = \

+  	cxl.1 \

+ -	cxl-list.1

+ +	cxl-list.1 \

+ +	cxl-read-labels.1 \

+ +	cxl-write-labels.1 \

+ +	cxl-zero-labels.1

+  

+  EXTRA_DIST = $(man1_MANS)

+  

+ diff --git a/Documentation/cxl/cxl-read-labels.txt b/Documentation/cxl/cxl-read-labels.txt

+ new file mode 100644

+ index 0000000..143f296

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-read-labels.txt

+ @@ -0,0 +1,33 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-read-labels(1)

+ +==================

+ +

+ +NAME

+ +----

+ +cxl-read-labels - read out the label area on a CXL memdev

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl read-labels' <mem0> [<mem1>..<memN>] [<options>]

+ +

+ +include::labels-description.txt[]

+ +This command dumps the raw binary data in a memdev's label area to stdout or a

+ +file.  In the multi-memdev case the data is concatenated.

+ +

+ +OPTIONS

+ +-------

+ +include::labels-options.txt[]

+ +

+ +-o::

+ +--output::

+ +	output file

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-write-labels[1],

+ +linkcxl:cxl-zero-labels[1],

+ +CXL-2.0 9.13.2

+ diff --git a/Documentation/cxl/cxl-write-labels.txt b/Documentation/cxl/cxl-write-labels.txt

+ new file mode 100644

+ index 0000000..75f42a5

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-write-labels.txt

+ @@ -0,0 +1,32 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-write-labels(1)

+ +===================

+ +

+ +NAME

+ +----

+ +cxl-write-labels - write data to the label area on a memdev

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl write-labels <mem> [-i <filename>]'

+ +

+ +include::labels-description.txt[]

+ +Read data from the input filename, or stdin, and write it to the given

+ +<mem> device. Note that the device must not be active in any region, or

+ +actively registered with the nvdimm subsystem. If it is, the kernel will

+ +not allow write access to the device's label data area.

+ +

+ +OPTIONS

+ +-------

+ +include::labels-options.txt[]

+ +-i::

+ +--input::

+ +	input file

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-read-labels[1],

+ +linkcxl:cxl-zero-labels[1],

+ +CXL-2.0 9.13.2

+ diff --git a/Documentation/cxl/cxl-zero-labels.txt b/Documentation/cxl/cxl-zero-labels.txt

+ new file mode 100644

+ index 0000000..bf95b24

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-zero-labels.txt

+ @@ -0,0 +1,29 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-zero-labels(1)

+ +==================

+ +

+ +NAME

+ +----

+ +cxl-zero-labels - zero out the label area on a set of memdevs

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl zero-labels' <mem0> [<mem1>..<memN>] [<options>]

+ +

+ +include::labels-description.txt[]

+ +This command resets the device to its default state by

+ +deleting all labels.

+ +

+ +OPTIONS

+ +-------

+ +include::labels-options.txt[]

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-read-labels[1],

+ +linkcxl:cxl-write-labels[1],

+ +CXL-2.0 9.13.2

+ diff --git a/Documentation/cxl/labels-description.txt b/Documentation/cxl/labels-description.txt

+ new file mode 100644

+ index 0000000..f60bd5d

+ --- /dev/null

+ +++ b/Documentation/cxl/labels-description.txt

+ @@ -0,0 +1,8 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +DESCRIPTION

+ +-----------

+ +The region label area is a small persistent partition of capacity

+ +available on some CXL memory devices. The label area is used to

+ +and configure or determine the set of memory devices participating

+ +in different interleave sets.

+ diff --git a/Documentation/cxl/labels-options.txt b/Documentation/cxl/labels-options.txt

+ new file mode 100644

+ index 0000000..06fbac3

+ --- /dev/null

+ +++ b/Documentation/cxl/labels-options.txt

+ @@ -0,0 +1,17 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +<memory device(s)>::

+ +include::memdev-option.txt[]

+ +

+ +-s::

+ +--size=::

+ +	Limit the operation to the given number of bytes. A size of 0

+ +	indicates to operate over the entire label capacity.

+ +

+ +-O::

+ +--offset=::

+ +	Begin the operation at the given offset into the label area.

+ +

+ +-v::

+ +	Turn on verbose debug messages in the library (if libcxl was built with

+ +	logging and debug enabled).

+ diff --git a/Documentation/cxl/memdev-option.txt b/Documentation/cxl/memdev-option.txt

+ new file mode 100644

+ index 0000000..e778582

+ --- /dev/null

+ +++ b/Documentation/cxl/memdev-option.txt

+ @@ -0,0 +1,4 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +A 'memX' device name, or a memdev id number. Restrict the operation to

+ +the specified memdev(s). The keyword 'all' can be specified to indicate

+ +the lack of any restriction.

+ diff --git a/cxl/Makefile.am b/cxl/Makefile.am

+ index 98606b9..da9f91d 100644

+ --- a/cxl/Makefile.am

+ +++ b/cxl/Makefile.am

+ @@ -10,6 +10,7 @@ config.h: $(srcdir)/Makefile.am

+  cxl_SOURCES =\

+  		cxl.c \

+  		list.c \

+ +		memdev.c \

+  		../util/json.c \

+  		builtin.h

+  

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index 3797f98..78eca6e 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -5,4 +5,9 @@

+  

+  struct cxl_ctx;

+  int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  #endif /* _CXL_BUILTIN_H_ */

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index a7725f8..4b1661d 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -61,6 +61,9 @@ static struct cmd_struct commands[] = {

+  	{ "version", .c_fn = cmd_version },

+  	{ "list", .c_fn = cmd_list },

+  	{ "help", .c_fn = cmd_help },

+ +	{ "zero-labels", .c_fn = cmd_zero_labels },

+ +	{ "read-labels", .c_fn = cmd_read_labels },

+ +	{ "write-labels", .c_fn = cmd_write_labels },

+  };

+  

+  int main(int argc, const char **argv)

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ new file mode 100644

+ index 0000000..5ee38e5

+ --- /dev/null

+ +++ b/cxl/memdev.c

+ @@ -0,0 +1,324 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */

+ +#include <stdio.h>

+ +#include <errno.h>

+ +#include <stdlib.h>

+ +#include <unistd.h>

+ +#include <limits.h>

+ +#include <util/log.h>

+ +#include <util/filter.h>

+ +#include <cxl/libcxl.h>

+ +#include <util/parse-options.h>

+ +#include <ccan/minmax/minmax.h>

+ +#include <ccan/array_size/array_size.h>

+ +

+ +struct action_context {

+ +	FILE *f_out;

+ +	FILE *f_in;

+ +};

+ +

+ +static struct parameters {

+ +	const char *outfile;

+ +	const char *infile;

+ +	unsigned len;

+ +	unsigned offset;

+ +	bool verbose;

+ +} param;

+ +

+ +#define fail(fmt, ...) \

+ +do { \

+ +	fprintf(stderr, "cxl-%s:%s:%d: " fmt, \

+ +			VERSION, __func__, __LINE__, ##__VA_ARGS__); \

+ +} while (0)

+ +

+ +#define BASE_OPTIONS() \

+ +OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug")

+ +

+ +#define READ_OPTIONS() \

+ +OPT_STRING('o', "output", &param.outfile, "output-file", \

+ +	"filename to write label area contents")

+ +

+ +#define WRITE_OPTIONS() \

+ +OPT_STRING('i', "input", &param.infile, "input-file", \

+ +	"filename to read label area data")

+ +

+ +#define LABEL_OPTIONS() \

+ +OPT_UINTEGER('s', "size", &param.len, "number of label bytes to operate"), \

+ +OPT_UINTEGER('O', "offset", &param.offset, \

+ +	"offset into the label area to start operation")

+ +

+ +static const struct option read_options[] = {

+ +	BASE_OPTIONS(),

+ +	LABEL_OPTIONS(),

+ +	READ_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static const struct option write_options[] = {

+ +	BASE_OPTIONS(),

+ +	LABEL_OPTIONS(),

+ +	WRITE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static const struct option zero_options[] = {

+ +	BASE_OPTIONS(),

+ +	LABEL_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)

+ +{

+ +	size_t size;

+ +	int rc;

+ +

+ +	if (param.len)

+ +		size = param.len;

+ +	else

+ +		size = cxl_memdev_get_label_size(memdev);

+ +

+ +	if (cxl_memdev_nvdimm_bridge_active(memdev)) {

+ +		fprintf(stderr,

+ +			"%s: has active nvdimm bridge, abort label write\n",

+ +			cxl_memdev_get_devname(memdev));

+ +		return -EBUSY;

+ +	}

+ +

+ +	rc = cxl_memdev_zero_label(memdev, size, param.offset);

+ +	if (rc < 0)

+ +		fprintf(stderr, "%s: label zeroing failed: %s\n",

+ +			cxl_memdev_get_devname(memdev), strerror(-rc));

+ +

+ +	return rc;

+ +}

+ +

+ +static int action_write(struct cxl_memdev *memdev, struct action_context *actx)

+ +{

+ +	size_t size = param.len, read_len;

+ +	unsigned char *buf;

+ +	int rc;

+ +

+ +	if (cxl_memdev_nvdimm_bridge_active(memdev)) {

+ +		fprintf(stderr,

+ +			"%s: has active nvdimm bridge, abort label write\n",

+ +			cxl_memdev_get_devname(memdev));

+ +		return -EBUSY;

+ +	}

+ +

+ +	if (!size) {

+ +		size_t label_size = cxl_memdev_get_label_size(memdev);

+ +

+ +		fseek(actx->f_in, 0L, SEEK_END);

+ +		size = ftell(actx->f_in);

+ +		fseek(actx->f_in, 0L, SEEK_SET);

+ +

+ +		if (size > label_size) {

+ +			fprintf(stderr,

+ +				"File size (%zu) greater than label area size (%zu), aborting\n",

+ +				size, label_size);

+ +			return -EINVAL;

+ +		}

+ +	}

+ +

+ +	buf = calloc(1, size);

+ +	if (!buf)

+ +		return -ENOMEM;

+ +

+ +	read_len = fread(buf, 1, size, actx->f_in);

+ +	if (read_len != size) {

+ +		rc = -ENXIO;

+ +		goto out;

+ +	}

+ +

+ +	rc = cxl_memdev_write_label(memdev, buf, size, param.offset);

+ +	if (rc < 0)

+ +		fprintf(stderr, "%s: label write failed: %s\n",

+ +			cxl_memdev_get_devname(memdev), strerror(-rc));

+ +

+ +out:

+ +	free(buf);

+ +	return rc;

+ +}

+ +

+ +static int action_read(struct cxl_memdev *memdev, struct action_context *actx)

+ +{

+ +	size_t size, write_len;

+ +	char *buf;

+ +	int rc;

+ +

+ +	if (param.len)

+ +		size = param.len;

+ +	else

+ +		size = cxl_memdev_get_label_size(memdev);

+ +

+ +	buf = calloc(1, size);

+ +	if (!buf)

+ +		return -ENOMEM;

+ +

+ +	rc = cxl_memdev_read_label(memdev, buf, size, param.offset);

+ +	if (rc < 0) {

+ +		fprintf(stderr, "%s: label read failed: %s\n",

+ +			cxl_memdev_get_devname(memdev), strerror(-rc));

+ +		goto out;

+ +	}

+ +

+ +	write_len = fwrite(buf, 1, size, actx->f_out);

+ +	if (write_len != size) {

+ +		rc = -ENXIO;

+ +		goto out;

+ +	}

+ +	fflush(actx->f_out);

+ +

+ +out:

+ +	free(buf);

+ +	return rc;

+ +}

+ +

+ +static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+ +		int (*action)(struct cxl_memdev *memdev, struct action_context *actx),

+ +		const struct option *options, const char *usage)

+ +{

+ +	struct cxl_memdev *memdev, *single = NULL;

+ +	struct action_context actx = { 0 };

+ +	int i, rc = 0, count = 0, err = 0;

+ +	const char * const u[] = {

+ +		usage,

+ +		NULL

+ +	};

+ +	unsigned long id;

+ +

+ +	argc = parse_options(argc, argv, options, u, 0);

+ +

+ +	if (argc == 0)

+ +		usage_with_options(u, options);

+ +	for (i = 0; i < argc; i++) {

+ +		if (strcmp(argv[i], "all") == 0) {

+ +			argv[0] = "all";

+ +			argc = 1;

+ +			break;

+ +		}

+ +

+ +		if (sscanf(argv[i], "mem%lu", &id) != 1) {

+ +			fprintf(stderr, "'%s' is not a valid memdev name\n",

+ +					argv[i]);

+ +			err++;

+ +		}

+ +	}

+ +

+ +	if (err == argc) {

+ +		usage_with_options(u, options);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (!param.outfile)

+ +		actx.f_out = stdout;

+ +	else {

+ +		actx.f_out = fopen(param.outfile, "w+");

+ +		if (!actx.f_out) {

+ +			fprintf(stderr, "failed to open: %s: (%s)\n",

+ +					param.outfile, strerror(errno));

+ +			rc = -errno;

+ +			goto out;

+ +		}

+ +	}

+ +

+ +	if (!param.infile) {

+ +		actx.f_in = stdin;

+ +	} else {

+ +		actx.f_in = fopen(param.infile, "r");

+ +		if (!actx.f_in) {

+ +			fprintf(stderr, "failed to open: %s: (%s)\n",

+ +					param.infile, strerror(errno));

+ +			rc = -errno;

+ +			goto out_close_fout;

+ +		}

+ +	}

+ +

+ +	if (param.verbose)

+ +		cxl_set_log_priority(ctx, LOG_DEBUG);

+ +

+ +	rc = 0;

+ +	err = 0;

+ +	count = 0;

+ +

+ +	for (i = 0; i < argc; i++) {

+ +		if (sscanf(argv[i], "mem%lu", &id) != 1

+ +				&& strcmp(argv[i], "all") != 0)

+ +			continue;

+ +

+ +		cxl_memdev_foreach (ctx, memdev) {

+ +			if (!util_cxl_memdev_filter(memdev, argv[i]))

+ +				continue;

+ +

+ +			if (action == action_write) {

+ +				single = memdev;

+ +				rc = 0;

+ +			} else

+ +				rc = action(memdev, &actx);

+ +

+ +			if (rc == 0)

+ +				count++;

+ +			else if (rc && !err)

+ +				err = rc;

+ +		}

+ +	}

+ +	rc = err;

+ +

+ +	if (action == action_write) {

+ +		if (count > 1) {

+ +			error("write-labels only supports writing a single memdev\n");

+ +			usage_with_options(u, options);

+ +			return -EINVAL;

+ +		} else if (single) {

+ +			rc = action(single, &actx);

+ +			if (rc)

+ +				count = 0;

+ +		}

+ +	}

+ +

+ +	if (actx.f_in != stdin)

+ +		fclose(actx.f_in);

+ +

+ + out_close_fout:

+ +	if (actx.f_out != stdout)

+ +		fclose(actx.f_out);

+ +

+ + out:

+ +	/*

+ +	 * count if some actions succeeded, 0 if none were attempted,

+ +	 * negative error code otherwise.

+ +	 */

+ +	if (count > 0)

+ +		return count;

+ +	return rc;

+ +}

+ +

+ +int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(argc, argv, ctx, action_write, write_options,

+ +			"cxl write-labels <memdev> [-i <filename>]");

+ +

+ +	fprintf(stderr, "wrote %d mem%s\n", count >= 0 ? count : 0,

+ +			count > 1 ? "s" : "");

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ +

+ +int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(argc, argv, ctx, action_read, read_options,

+ +			"cxl read-labels <mem0> [<mem1>..<memN>] [-o <filename>]");

+ +

+ +	fprintf(stderr, "read %d mem%s\n", count >= 0 ? count : 0,

+ +			count > 1 ? "s" : "");

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ +

+ +int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(argc, argv, ctx, action_zero, zero_options,

+ +			"cxl zero-labels <mem0> [<mem1>..<memN>] [<options>]");

+ +

+ +	fprintf(stderr, "zeroed %d mem%s\n", count >= 0 ? count : 0,

+ +			count > 1 ? "s" : "");

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,248 @@ 

+ From 62fe17528d362110e258d56d8a2f44f2798f3f45 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:36 -0600

+ Subject: [PATCH 043/217] Documentation/cxl: add library API documentation

+ 

+ Add library API documentation for libcxl(3) using the existing

+ asciidoc(tor) build system. Add a section 3 man page for 'libcxl' that

+ provides an overview of the library and its usage, and a man page for

+ the 'cxl_new()' API.

+ 

+ Cc: Ben Widawsky <ben.widawsky@intel.com>

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .gitignore                        |  3 ++

+  Documentation/cxl/lib/Makefile.am | 58 +++++++++++++++++++++++++++++++

+  Documentation/cxl/lib/cxl_new.txt | 43 +++++++++++++++++++++++

+  Documentation/cxl/lib/libcxl.txt  | 56 +++++++++++++++++++++++++++++

+  Makefile.am                       |  1 +

+  configure.ac                      |  1 +

+  6 files changed, 162 insertions(+)

+  create mode 100644 Documentation/cxl/lib/Makefile.am

+  create mode 100644 Documentation/cxl/lib/cxl_new.txt

+  create mode 100644 Documentation/cxl/lib/libcxl.txt

+ 

+ diff --git a/.gitignore b/.gitignore

+ index 6a97b92..6468c7a 100644

+ --- a/.gitignore

+ +++ b/.gitignore

+ @@ -14,12 +14,15 @@ Makefile.in

+  /libtool

+  /stamp-h1

+  *.1

+ +*.3

+  Documentation/daxctl/asciidoc.conf

+  Documentation/ndctl/asciidoc.conf

+  Documentation/cxl/asciidoc.conf

+ +Documentation/cxl/lib/asciidoc.conf

+  Documentation/daxctl/asciidoctor-extensions.rb

+  Documentation/ndctl/asciidoctor-extensions.rb

+  Documentation/cxl/asciidoctor-extensions.rb

+ +Documentation/cxl/lib/asciidoctor-extensions.rb

+  Documentation/ndctl/attrs.adoc

+  .dirstamp

+  daxctl/config.h

+ diff --git a/Documentation/cxl/lib/Makefile.am b/Documentation/cxl/lib/Makefile.am

+ new file mode 100644

+ index 0000000..41e3a5f

+ --- /dev/null

+ +++ b/Documentation/cxl/lib/Makefile.am

+ @@ -0,0 +1,58 @@

+ +# SPDX-License-Identifier: GPL-2.0

+ +# Copyright (C) 2020-2021 Intel Corporation. All rights reserved.

+ +

+ +if USE_ASCIIDOCTOR

+ +

+ +do_subst = sed -e 's,@Utility@,Libcxl,g' -e's,@utility@,libcxl,g'

+ +CONFFILE = asciidoctor-extensions.rb

+ +asciidoctor-extensions.rb: ../../asciidoctor-extensions.rb.in

+ +	$(AM_V_GEN) $(do_subst) < $< > $@

+ +

+ +else

+ +

+ +do_subst = sed -e 's,UTILITY,libcxl,g'

+ +CONFFILE = asciidoc.conf

+ +asciidoc.conf: ../../asciidoc.conf.in

+ +	$(AM_V_GEN) $(do_subst) < $< > $@

+ +

+ +endif

+ +

+ +man3_MANS = \

+ +	libcxl.3 \

+ +	cxl_new.3

+ +

+ +EXTRA_DIST = $(man3_MANS)

+ +

+ +CLEANFILES = $(man3_MANS)

+ +

+ +XML_DEPS = \

+ +	../../../version.m4 \

+ +	../../copyright.txt \

+ +	Makefile \

+ +	$(CONFFILE)

+ +

+ +RM ?= rm -f

+ +

+ +if USE_ASCIIDOCTOR

+ +

+ +%.3: %.txt $(XML_DEPS)

+ +	$(AM_V_GEN)$(RM) $@+ $@ && \

+ +		$(ASCIIDOC) -b manpage -d manpage -acompat-mode \

+ +		-I. -rasciidoctor-extensions \

+ +		-amansource=libcxl -amanmanual="libcxl Manual" \

+ +		-andctl_version=$(VERSION) -o $@+ $< && \

+ +		mv $@+ $@

+ +

+ +else

+ +

+ +%.xml: %.txt $(XML_DEPS)

+ +	$(AM_V_GEN)$(RM) $@+ $@ && \

+ +		$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \

+ +		--unsafe -alibcxl_version=$(VERSION) -o $@+ $< && \

+ +		mv $@+ $@

+ +

+ +%.3: %.xml $(XML_DEPS)

+ +	$(AM_V_GEN)$(RM) $@ && \

+ +		$(XMLTO) -o . -m ../../manpage-normal.xsl man $<

+ +

+ +endif

+ diff --git a/Documentation/cxl/lib/cxl_new.txt b/Documentation/cxl/lib/cxl_new.txt

+ new file mode 100644

+ index 0000000..147d4e0

+ --- /dev/null

+ +++ b/Documentation/cxl/lib/cxl_new.txt

+ @@ -0,0 +1,43 @@

+ +// SPDX-License-Identifier: LGPL-2.0

+ +

+ +cxl_new(3)

+ +==========

+ +

+ +NAME

+ +----

+ +cxl_new - Create a new library context object that acts as a handle for all

+ +library operations

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +----

+ +#include <cxl/libcxl.h>

+ +

+ +int cxl_new(struct cxl_ctx **ctx);

+ +----

+ +

+ +DESCRIPTION

+ +-----------

+ +Instantiates a new library context, and stores an opaque pointer in ctx. The

+ +context is freed by linklibcxl:cxl_unref[3], i.e. cxl_new(3) implies an

+ +internal linklibcxl:cxl_ref[3].

+ +

+ +

+ +RETURN VALUE

+ +------------

+ +Returns 0 on success, and a negative errno on failure.

+ +Possible error codes are:

+ +

+ + * -ENOMEM

+ + * -ENXIO

+ +

+ +EXAMPLE

+ +-------

+ +See example usage in test/libcxl.c

+ +

+ +include::../../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linklibcxl:cxl_ref[3], linklibcxl:cxl_unref[3]

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ new file mode 100644

+ index 0000000..2539369

+ --- /dev/null

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -0,0 +1,56 @@

+ +// SPDX-License-Identifier: LGPL-2.0

+ +

+ +libcxl(3)

+ +=========

+ +

+ +NAME

+ +----

+ +libcxl - A library to interact with CXL devices through sysfs(5)

+ +and ioctl(2) interfaces

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +#include <cxl/libcxl.h>

+ +cc ... -lcxl

+ +

+ +DESCRIPTION

+ +-----------

+ +libcxl provides interfaces to interact with CXL devices in Linux, using sysfs

+ +interfaces for most kernel interactions, and the ioctl() interface for command

+ +submission.

+ +

+ +The starting point for all library interfaces is a 'cxl_ctx' object, returned

+ +by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices are children of the

+ +cxl_ctx object, and can be iterated through using an iterator API.

+ +

+ +Library level interfaces that are agnostic to any device, or a specific

+ +subclass of operations have the prefix 'cxl_'

+ +

+ +The object representing a CXL Type 3 device is 'cxl_memdev'. Library interfaces

+ +related to these devices have the prefix 'cxl_memdev_'. These interfaces are

+ +mostly associated with sysfs interactions (unless otherwise noted in their

+ +respective documentation pages). They are typically used to retrieve data

+ +published by the kernel, or to send data or trigger kernel operations for a

+ +given device.

+ +

+ +A 'cxl_cmd' is a reference counted object which is used to perform 'Mailbox'

+ +commands as described in the CXL Specification. A 'cxl_cmd' object is tied to a

+ +'cxl_memdev'. Associated library interfaces have the prefix 'cxl_cmd_'. Within

+ +this sub-class of interfaces, there are:

+ +

+ + * 'cxl_cmd_new_*' interfaces that allocate a new cxl_cmd object for a given

+ +   command type.

+ +

+ + * 'cxl_cmd_submit' which submits the command via ioctl()

+ +

+ + * 'cxl_cmd_<name>_get_<field>' interfaces that get specific fields out of the

+ +   command response

+ +

+ + * 'cxl_cmd_get_*' interfaces to get general command related information.

+ +

+ +include::../../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linklibcxl:cxl[1]

+ diff --git a/Makefile.am b/Makefile.am

+ index 4904ee7..e2f6bef 100644

+ --- a/Makefile.am

+ +++ b/Makefile.am

+ @@ -4,6 +4,7 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}

+  SUBDIRS = . cxl/lib daxctl/lib ndctl/lib cxl ndctl daxctl

+  if ENABLE_DOCS

+  SUBDIRS += Documentation/ndctl Documentation/daxctl Documentation/cxl

+ +SUBDIRS += Documentation/cxl/lib

+  endif

+  SUBDIRS += test

+  

+ diff --git a/configure.ac b/configure.ac

+ index dadae0a..00497ae 100644

+ --- a/configure.ac

+ +++ b/configure.ac

+ @@ -231,6 +231,7 @@ AC_CONFIG_FILES([

+          Documentation/ndctl/Makefile

+          Documentation/daxctl/Makefile

+          Documentation/cxl/Makefile

+ +        Documentation/cxl/lib/Makefile

+  ])

+  

+  AC_OUTPUT

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,147 @@ 

+ From 57b1484fa427228afd52cdfa4fa3916a7a5878bf Mon Sep 17 00:00:00 2001

+ From: Ira Weiny <ira.weiny@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:37 -0600

+ Subject: [PATCH 044/217] ndctl: Add CXL packages to the RPM spec

+ 

+ Add CXL related packages - the cxl-cli utility, the libcxl library, and

+ development headers to respective RPM packages in the main spec file.

+ 

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Ira Weiny <ira.weiny@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Makefile.am   |  4 ++++

+  ndctl.spec.in | 49 +++++++++++++++++++++++++++++++++++++++++++++++++

+  2 files changed, 53 insertions(+)

+ 

+ diff --git a/Makefile.am b/Makefile.am

+ index e2f6bef..fa2010a 100644

+ --- a/Makefile.am

+ +++ b/Makefile.am

+ @@ -23,17 +23,21 @@ CLEANFILES += $(noinst_SCRIPTS)

+  

+  do_rhel_subst = sed -e 's,VERSION,$(VERSION),g' \

+              -e 's,DAX_DNAME,daxctl-devel,g' \

+ +            -e 's,CXL_DNAME,cxl-devel,g' \

+              -e 's,DNAME,ndctl-devel,g' \

+              -e '/^%defattr.*/d' \

+  	    -e 's,DAX_LNAME,daxctl-libs,g' \

+ +	    -e 's,CXL_LNAME,cxl-libs,g' \

+  	    -e 's,LNAME,ndctl-libs,g'

+  

+  do_sles_subst = sed -e 's,VERSION,$(VERSION),g' \

+              -e 's,DAX_DNAME,libdaxctl-devel,g' \

+ +            -e 's,CXL_DNAME,libcxl-devel,g' \

+              -e 's,DNAME,libndctl-devel,g' \

+              -e 's,%license,%doc,g' \

+              -e 's,\(^License:.*GPL\)v2,\1-2.0,g' \

+              -e "s,DAX_LNAME,libdaxctl$$(($(LIBDAXCTL_CURRENT) - $(LIBDAXCTL_AGE))),g" \

+ +            -e "s,CXL_LNAME,libcxl$$(($(LIBCXL_CURRENT) - $(LIBCXL_AGE))),g" \

+              -e "s,LNAME,libndctl$$(($(LIBNDCTL_CURRENT) - $(LIBNDCTL_AGE))),g"

+  

+  rhel/ndctl.spec: ndctl.spec.in Makefile.am version.m4

+ diff --git a/ndctl.spec.in b/ndctl.spec.in

+ index 0563b2d..4b08c05 100644

+ --- a/ndctl.spec.in

+ +++ b/ndctl.spec.in

+ @@ -8,6 +8,7 @@ Source0:	https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{v

+  

+  Requires:	LNAME%{?_isa} = %{version}-%{release}

+  Requires:	DAX_LNAME%{?_isa} = %{version}-%{release}

+ +Requires:	CXL_LNAME%{?_isa} = %{version}-%{release}

+  BuildRequires:	autoconf

+  %if 0%{?rhel} < 9

+  BuildRequires:	asciidoc

+ @@ -54,6 +55,24 @@ the Linux kernel Device-DAX facility. This facility enables DAX mappings

+  of performance / feature differentiated memory without need of a

+  filesystem.

+  

+ +%package -n cxl-cli

+ +Summary:	Manage CXL devices

+ +License:	GPLv2

+ +Requires:	CXL_LNAME%{?_isa} = %{version}-%{release}

+ +

+ +%description -n cxl-cli

+ +The cxl utility provides enumeration and provisioning commands for

+ +the Linux kernel CXL devices.

+ +

+ +%package -n CXL_DNAME

+ +Summary:	Development files for libcxl

+ +License:	LGPLv2

+ +Requires:	CXL_LNAME%{?_isa} = %{version}-%{release}

+ +

+ +%description -n CXL_DNAME

+ +This package contains libraries and header files for developing applications

+ +that use libcxl, a library for enumerating and communicating with CXL devices.

+ +

+  %package -n DAX_DNAME

+  Summary:	Development files for libdaxctl

+  License:	LGPLv2

+ @@ -84,6 +103,13 @@ Device DAX is a facility for establishing DAX mappings of performance /

+  feature-differentiated memory. DAX_LNAME provides an enumeration /

+  control API for these devices.

+  

+ +%package -n CXL_LNAME

+ +Summary:	Management library for CXL devices

+ +License:	LGPLv2

+ +

+ +%description -n CXL_LNAME

+ +libcxl is a library for enumerating and communicating with CXL devices.

+ +

+  

+  %prep

+  %setup -q ndctl-%{version}

+ @@ -105,6 +131,8 @@ make check

+  

+  %ldconfig_scriptlets -n DAX_LNAME

+  

+ +%ldconfig_scriptlets -n CXL_LNAME

+ +

+  %define bashcompdir %(pkg-config --variable=completionsdir bash-completion)

+  

+  %files

+ @@ -126,6 +154,12 @@ make check

+  %{_mandir}/man1/daxctl*

+  %{_datadir}/daxctl/daxctl.conf

+  

+ +%files -n cxl-cli

+ +%defattr(-,root,root)

+ +%license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0

+ +%{_bindir}/cxl

+ +%{_mandir}/man1/cxl*

+ +

+  %files -n LNAME

+  %defattr(-,root,root)

+  %doc README.md

+ @@ -138,6 +172,12 @@ make check

+  %license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0

+  %{_libdir}/libdaxctl.so.*

+  

+ +%files -n CXL_LNAME

+ +%defattr(-,root,root)

+ +%doc README.md

+ +%license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0

+ +%{_libdir}/libcxl.so.*

+ +

+  %files -n DNAME

+  %defattr(-,root,root)

+  %license LICENSES/preferred/LGPL-2.1

+ @@ -152,6 +192,15 @@ make check

+  %{_libdir}/libdaxctl.so

+  %{_libdir}/pkgconfig/libdaxctl.pc

+  

+ +%files -n CXL_DNAME

+ +%defattr(-,root,root)

+ +%license LICENSES/preferred/LGPL-2.1

+ +%{_includedir}/cxl/

+ +%{_libdir}/libcxl.so

+ +%{_libdir}/pkgconfig/libcxl.pc

+ +%{_mandir}/man3/cxl*

+ +%{_mandir}/man3/libcxl.3.gz

+ +

+  

+  %changelog

+  * Fri May 27 2016 Dan Williams <dan.j.williams@intel.com> - 53-1

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,139 @@ 

+ From 02c40b971bd4d092b3612fcb5e9ddd57548e6dbb Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:38 -0600

+ Subject: [PATCH 045/217] cxl-cli: add bash completion

+ 

+ Add bash completion for the cxl-cli commands implemented so far:

+   cxl-list

+   cxl-read-labels

+   cxl-write-labels

+   cxl-zero-labels

+ 

+ Acked-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  contrib/ndctl | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++

+  1 file changed, 109 insertions(+)

+ 

+ diff --git a/contrib/ndctl b/contrib/ndctl

+ index 680fe6a..cae4b1b 100755

+ --- a/contrib/ndctl

+ +++ b/contrib/ndctl

+ @@ -647,5 +647,114 @@ _daxctl()

+  	__daxctl_main

+  }

+  

+ +### cxl-cli ###

+ +

+ +__cxl_get_devs()

+ +{

+ +	local opts=("--memdevs" "$*")

+ +	cxl list "${opts[@]}" | grep -E "^\s*\"memdev\":" | cut -d'"' -f4

+ +}

+ +

+ +__cxlcomp()

+ +{

+ +	local i=0

+ +

+ +	COMPREPLY=( $( compgen -W "$1" -- "$2" ) )

+ +	for cword in "${COMPREPLY[@]}"; do

+ +		if [[ "$cword" == @(--memdev|--offset|--size|--input|--output) ]]; then

+ +			COMPREPLY[$i]="${cword}="

+ +		else

+ +			COMPREPLY[$i]="${cword} "

+ +		fi

+ +		((i++))

+ +	done

+ +}

+ +

+ +__cxl_comp_options()

+ +{

+ +

+ +	local cur=$1

+ +	local opts

+ +

+ +	if [[ "$cur" == *=* ]]; then

+ +		local cur_subopt=${cur%%=*}

+ +		local cur_arg=${cur##*=}

+ +		case $cur_subopt in

+ +		--memdev)

+ +			opts="$(__cxl_get_devs -i)"

+ +			;;

+ +		*)

+ +			return

+ +			;;

+ +		esac

+ +		__cxlcomp "$opts" "$cur_arg"

+ +	fi

+ +}

+ +

+ +__cxl_comp_non_option_args()

+ +{

+ +	local subcmd=$1

+ +	local cur=$2

+ +	local opts

+ +

+ +	case $subcmd in

+ +	read-labels)

+ +		;&

+ +	write-labels)

+ +		;&

+ +	zero-labels)

+ +		opts="$(__cxl_get_devs -i) all"

+ +		;;

+ +	*)

+ +		return

+ +		;;

+ +	esac

+ +	__cxlcomp "$opts" "$cur"

+ +}

+ +

+ +__cxl_main()

+ +{

+ +	local cmd subcmd

+ +

+ +	cmd=${words[0]}

+ +	COMPREPLY=()

+ +

+ +	# Skip options backward and find the last cxl command

+ +	__nd_common_prev_skip_opts

+ +	subcmd=$prev_skip_opts

+ +	# List cxl subcommands or long options

+ +	if [ -z $subcmd ]; then

+ +		if [[ $cur == --* ]]; then

+ +			cmds="--version --help --list-cmds"

+ +		else

+ +			cmds=$($cmd --list-cmds)

+ +		fi

+ +		__cxlcomp "$cmds" "$cur"

+ +	else

+ +		# List long option names

+ +		if [[ $cur == --* ]];  then

+ +			opts=$($cmd $subcmd --list-opts)

+ +			__cxlcomp "$opts" "$cur"

+ +			__cxl_comp_options "$cur"

+ +		else

+ +			[ -z "$subcmd" ] && return

+ +			__cxl_comp_non_option_args "$subcmd" "$cur"

+ +		fi

+ +	fi

+ +}

+ +

+ +type cxl &>/dev/null &&

+ +_cxl()

+ +{

+ +	local cur words cword prev

+ +	if [ $preload_get_comp_words_by_ref = "true" ]; then

+ +		_get_comp_words_by_ref -n =: cur words cword prev

+ +	else

+ +		__nd_common_get_comp_words_by_ref -n =: cur words cword prev

+ +	fi

+ +	__cxl_main

+ +}

+ +

+  complete -o nospace -F _ndctl ndctl

+  complete -o nospace -F _daxctl daxctl

+ +complete -o nospace -F _cxl cxl

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,308 @@ 

+ From f5d1e2133c54c1f420a0c3cf45fa633f097823be Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 7 Oct 2021 02:21:39 -0600

+ Subject: [PATCH 046/217] cxl: add health information to cxl-list

+ 

+ Add JSON output for fields from the 'GET_HEALTH_INFO' mailbox command

+ to memory device listings.

+ 

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt |  38 +++++++

+  cxl/list.c                     |   5 +

+  util/json.c                    | 179 +++++++++++++++++++++++++++++++++

+  util/json.h                    |   1 +

+  4 files changed, 223 insertions(+)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 370d5b8..c8d10fb 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -48,6 +48,44 @@ OPTIONS

+  --idle::

+  	Include idle (not enabled / zero-sized) devices in the listing

+  

+ +-H::

+ +--health::

+ +	Include health information in the memdev listing. Example listing:

+ +----

+ +# cxl list -m mem0 -H

+ +[

+ +  {

+ +    "memdev":"mem0",

+ +    "pmem_size":268435456,

+ +    "ram_size":268435456,

+ +    "health":{

+ +      "maintenance_needed":true,

+ +      "performance_degraded":true,

+ +      "hw_replacement_needed":true,

+ +      "media_normal":false,

+ +      "media_not_ready":false,

+ +      "media_persistence_lost":false,

+ +      "media_data_lost":true,

+ +      "media_powerloss_persistence_loss":false,

+ +      "media_shutdown_persistence_loss":false,

+ +      "media_persistence_loss_imminent":false,

+ +      "media_powerloss_data_loss":false,

+ +      "media_shutdown_data_loss":false,

+ +      "media_data_loss_imminent":false,

+ +      "ext_life_used":"normal",

+ +      "ext_temperature":"critical",

+ +      "ext_corrected_volatile":"warning",

+ +      "ext_corrected_persistent":"normal",

+ +      "life_used_percent":15,

+ +      "temperature":25,

+ +      "dirty_shutdowns":10,

+ +      "volatile_errors":20,

+ +      "pmem_errors":30

+ +    }

+ +  }

+ +]

+ +----

+ +

+  include::human-option.txt[]

+  

+  include::verbose-option.txt[]

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 043d20c..b1468b7 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -16,6 +16,7 @@ static struct {

+  	bool memdevs;

+  	bool idle;

+  	bool human;

+ +	bool health;

+  } list;

+  

+  static unsigned long listopts_to_flags(void)

+ @@ -26,6 +27,8 @@ static unsigned long listopts_to_flags(void)

+  		flags |= UTIL_JSON_IDLE;

+  	if (list.human)

+  		flags |= UTIL_JSON_HUMAN;

+ +	if (list.health)

+ +		flags |= UTIL_JSON_HEALTH;

+  	return flags;

+  }

+  

+ @@ -57,6 +60,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  		OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),

+  		OPT_BOOLEAN('u', "human", &list.human,

+  				"use human friendly number formats "),

+ +		OPT_BOOLEAN('H', "health", &list.health,

+ +				"include memory device health information "),

+  		OPT_END(),

+  	};

+  	const char * const u[] = {

+ diff --git a/util/json.c b/util/json.c

+ index 3be3a92..f97cf07 100644

+ --- a/util/json.c

+ +++ b/util/json.c

+ @@ -1442,6 +1442,180 @@ struct json_object *util_badblock_rec_to_json(u64 block, u64 count,

+  	return NULL;

+  }

+  

+ +static struct json_object *util_cxl_memdev_health_to_json(

+ +		struct cxl_memdev *memdev, unsigned long flags)

+ +{

+ +	struct json_object *jhealth;

+ +	struct json_object *jobj;

+ +	struct cxl_cmd *cmd;

+ +	u32 field;

+ +	int rc;

+ +

+ +	jhealth = json_object_new_object();

+ +	if (!jhealth)

+ +		return NULL;

+ +	if (!memdev)

+ +		goto err_jobj;

+ +

+ +	cmd = cxl_cmd_new_get_health_info(memdev);

+ +	if (!cmd)

+ +		goto err_jobj;

+ +

+ +	rc = cxl_cmd_submit(cmd);

+ +	if (rc < 0)

+ +		goto err_cmd;

+ +	rc = cxl_cmd_get_mbox_status(cmd);

+ +	if (rc != 0)

+ +		goto err_cmd;

+ +

+ +	/* health_status fields */

+ +	rc = cxl_cmd_health_info_get_maintenance_needed(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "maintenance_needed", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_performance_degraded(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "performance_degraded", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_hw_replacement_needed(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "hw_replacement_needed", jobj);

+ +

+ +	/* media_status fields */

+ +	rc = cxl_cmd_health_info_get_media_normal(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_normal", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_not_ready(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_not_ready", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_persistence_lost(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_persistence_lost", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_data_lost(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_data_lost", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_powerloss_persistence_loss(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_powerloss_persistence_loss", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_shutdown_persistence_loss(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_shutdown_persistence_loss", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_persistence_loss_imminent(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_persistence_loss_imminent", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_powerloss_data_loss(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_powerloss_data_loss", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_shutdown_data_loss(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_shutdown_data_loss", jobj);

+ +

+ +	rc = cxl_cmd_health_info_get_media_data_loss_imminent(cmd);

+ +	jobj = json_object_new_boolean(rc);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "media_data_loss_imminent", jobj);

+ +

+ +	/* ext_status fields */

+ +	if (cxl_cmd_health_info_get_ext_life_used_normal(cmd))

+ +		jobj = json_object_new_string("normal");

+ +	else if (cxl_cmd_health_info_get_ext_life_used_warning(cmd))

+ +		jobj = json_object_new_string("warning");

+ +	else if (cxl_cmd_health_info_get_ext_life_used_critical(cmd))

+ +		jobj = json_object_new_string("critical");

+ +	else

+ +		jobj = json_object_new_string("unknown");

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "ext_life_used", jobj);

+ +

+ +	if (cxl_cmd_health_info_get_ext_temperature_normal(cmd))

+ +		jobj = json_object_new_string("normal");

+ +	else if (cxl_cmd_health_info_get_ext_temperature_warning(cmd))

+ +		jobj = json_object_new_string("warning");

+ +	else if (cxl_cmd_health_info_get_ext_temperature_critical(cmd))

+ +		jobj = json_object_new_string("critical");

+ +	else

+ +		jobj = json_object_new_string("unknown");

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "ext_temperature", jobj);

+ +

+ +	if (cxl_cmd_health_info_get_ext_corrected_volatile_normal(cmd))

+ +		jobj = json_object_new_string("normal");

+ +	else if (cxl_cmd_health_info_get_ext_corrected_volatile_warning(cmd))

+ +		jobj = json_object_new_string("warning");

+ +	else

+ +		jobj = json_object_new_string("unknown");

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "ext_corrected_volatile", jobj);

+ +

+ +	if (cxl_cmd_health_info_get_ext_corrected_persistent_normal(cmd))

+ +		jobj = json_object_new_string("normal");

+ +	else if (cxl_cmd_health_info_get_ext_corrected_persistent_warning(cmd))

+ +		jobj = json_object_new_string("warning");

+ +	else

+ +		jobj = json_object_new_string("unknown");

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "ext_corrected_persistent", jobj);

+ +

+ +	/* other fields */

+ +	field = cxl_cmd_health_info_get_life_used(cmd);

+ +	if (field != 0xff) {

+ +		jobj = json_object_new_int(field);

+ +		if (jobj)

+ +			json_object_object_add(jhealth, "life_used_percent", jobj);

+ +	}

+ +

+ +	field = cxl_cmd_health_info_get_temperature(cmd);

+ +	if (field != 0xffff) {

+ +		jobj = json_object_new_int(field);

+ +		if (jobj)

+ +			json_object_object_add(jhealth, "temperature", jobj);

+ +	}

+ +

+ +	field = cxl_cmd_health_info_get_dirty_shutdowns(cmd);

+ +	jobj = json_object_new_int64(field);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "dirty_shutdowns", jobj);

+ +

+ +	field = cxl_cmd_health_info_get_volatile_errors(cmd);

+ +	jobj = json_object_new_int64(field);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "volatile_errors", jobj);

+ +

+ +	field = cxl_cmd_health_info_get_pmem_errors(cmd);

+ +	jobj = json_object_new_int64(field);

+ +	if (jobj)

+ +		json_object_object_add(jhealth, "pmem_errors", jobj);

+ +

+ +	cxl_cmd_unref(cmd);

+ +	return jhealth;

+ +

+ +err_cmd:

+ +	cxl_cmd_unref(cmd);

+ +err_jobj:

+ +	json_object_put(jhealth);

+ +	return NULL;

+ +}

+ +

+  struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  		unsigned long flags)

+  {

+ @@ -1464,5 +1638,10 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  	if (jobj)

+  		json_object_object_add(jdev, "ram_size", jobj);

+  

+ +	if (flags & UTIL_JSON_HEALTH) {

+ +		jobj = util_cxl_memdev_health_to_json(memdev, flags);

+ +		if (jobj)

+ +			json_object_object_add(jdev, "health", jobj);

+ +	}

+  	return jdev;

+  }

+ diff --git a/util/json.h b/util/json.h

+ index 91918c8..ce575e6 100644

+ --- a/util/json.h

+ +++ b/util/json.h

+ @@ -19,6 +19,7 @@ enum util_json_flags {

+  	UTIL_JSON_CONFIGURED	= (1 << 7),

+  	UTIL_JSON_FIRMWARE	= (1 << 8),

+  	UTIL_JSON_DAX_MAPPINGS	= (1 << 9),

+ +	UTIL_JSON_HEALTH	= (1 << 10),

+  };

+  

+  struct json_object;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,75 @@ 

+ From ac46d00d7d4d555a238bb898e2ff4af0c444bebe Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 16 Nov 2021 17:51:31 -0700

+ Subject: [PATCH 047/217] ndctl: install bash-completion symlinks

+ 

+ Install symlinks for other utilities (daxctl, cxl-cli) in the

+ completions directory so that the dynamic completion loader can pick up

+ their respective names. Without this, completions for daxctl and cxl

+ would only work after a prior invocation of ndctl's completion.

+ 

+ Reported-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Makefile.am   | 3 +++

+  configure.ac  | 1 +

+  ndctl.spec.in | 4 +++-

+  3 files changed, 7 insertions(+), 1 deletion(-)

+ 

+ diff --git a/Makefile.am b/Makefile.am

+ index fa2010a..bd0037e 100644

+ --- a/Makefile.am

+ +++ b/Makefile.am

+ @@ -49,6 +49,9 @@ sles/ndctl.spec: sles/header ndctl.spec.in Makefile.am version.m4

+  if ENABLE_BASH_COMPLETION

+  bashcompletiondir = $(BASH_COMPLETION_DIR)

+  dist_bashcompletion_DATA = contrib/ndctl

+ +install-data-hook:

+ +	$(LN_S) -f $(BASH_COMPLETION_DIR)/ndctl $(DESTDIR)/$(BASH_COMPLETION_DIR)/daxctl

+ +	$(LN_S) -f $(BASH_COMPLETION_DIR)/ndctl $(DESTDIR)/$(BASH_COMPLETION_DIR)/cxl

+  endif

+  

+  modprobe_file = contrib/nvdimm-security.conf

+ diff --git a/configure.ac b/configure.ac

+ index 00497ae..9ac785f 100644

+ --- a/configure.ac

+ +++ b/configure.ac

+ @@ -31,6 +31,7 @@ AC_PREFIX_DEFAULT([/usr])

+  

+  AC_PROG_SED

+  AC_PROG_MKDIR_P

+ +AC_PROG_LN_S

+  

+  AC_ARG_ENABLE([docs],

+          AS_HELP_STRING([--disable-docs],

+ diff --git a/ndctl.spec.in b/ndctl.spec.in

+ index 4b08c05..27ca097 100644

+ --- a/ndctl.spec.in

+ +++ b/ndctl.spec.in

+ @@ -140,7 +140,7 @@ make check

+  %license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0

+  %{_bindir}/ndctl

+  %{_mandir}/man1/ndctl*

+ -%{bashcompdir}/

+ +%{bashcompdir}/ndctl

+  %{_unitdir}/ndctl-monitor.service

+  %{_sysconfdir}/ndctl/keys/keys.readme

+  %{_sysconfdir}/modprobe.d/nvdimm-security.conf

+ @@ -153,12 +153,14 @@ make check

+  %{_bindir}/daxctl

+  %{_mandir}/man1/daxctl*

+  %{_datadir}/daxctl/daxctl.conf

+ +%{bashcompdir}/daxctl

+  

+  %files -n cxl-cli

+  %defattr(-,root,root)

+  %license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0

+  %{_bindir}/cxl

+  %{_mandir}/man1/cxl*

+ +%{bashcompdir}/cxl

+  

+  %files -n LNAME

+  %defattr(-,root,root)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,400 @@ 

+ From 706a418798633ccb550b114eca7cc11038ab2695 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 14 Dec 2021 19:01:02 -0700

+ Subject: [PATCH 048/217] scripts: Add a man page template generator

+ 

+ Add a script to generate man page templates for the utils and libraries

+ under ndctl - including cxl, libcxl, ndctl, and daxctl.

+ 

+ The script can control certain include options depending on the options

+ supplied, and either dump the templates to stdout, or write the actual

+ files in their eventual directories, and open up an editor to further

+ edit them (unless --no-edit is used).

+ 

+ Link: https://lore.kernel.org/r/20211215020102.97880-1-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  scripts/docsurgeon                     | 339 +++++++++++++++++++++++++

+  scripts/docsurgeon_parser_generator.m4 |  23 ++

+  2 files changed, 362 insertions(+)

+  create mode 100755 scripts/docsurgeon

+  create mode 100644 scripts/docsurgeon_parser_generator.m4

+ 

+ diff --git a/scripts/docsurgeon b/scripts/docsurgeon

+ new file mode 100755

+ index 0000000..ca0ad78

+ --- /dev/null

+ +++ b/scripts/docsurgeon

+ @@ -0,0 +1,339 @@

+ +#!/bin/bash -eE

+ +

+ +this_script="docsurgeon"

+ +script_dir="$(cd "$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")" && pwd)"

+ +env_file="${script_dir}/.env"

+ +if [ -e "$env_file" ]; then

+ +	# shellcheck source=.env

+ +	. "$env_file"

+ +fi

+ +

+ +sources_file="${script_dir}/.sources"

+ +

+ +parser_generator="${script_dir}/${this_script}_parser_generator.m4"

+ +parser_lib="${script_dir}/${this_script}_parser.sh"

+ +if [ ! -e "$parser_lib" ] || [ "$parser_generator" -nt "$parser_lib" ]; then

+ +	if command -V argbash > /dev/null; then

+ +		argbash --strip user-content "$parser_generator" -o "$parser_lib"

+ +	else

+ +		echo "error: please install argbash" >&2

+ +		exit 1

+ +	fi

+ +fi

+ +

+ +if [[ $1 != "bin" ]]; then

+ +	# shellcheck source=docsurgeon_parser.sh

+ +	. "${script_dir}/${this_script}_parser.sh" || { echo "Couldn't find $parser_lib" >&2; exit 1; }

+ +fi

+ +

+ +# some script defaults - override using '.env'

+ +docbase="Documentation"

+ +copyright_cli="// SPDX-License-Identifier: GPL-2.0"

+ +copyright_footer_cli="include::../copyright.txt[]"

+ +copyright_lib="// SPDX-License-Identifier: LGPL-2.0"

+ +copyright_footer_lib="include::../../copyright.txt[]"

+ +

+ +# List of files we're creating, to be edited/renamed later

+ +# This starts out blank, and is filled in as we go by gen_*() functions

+ +declare -a outfiles

+ +

+ +cleanup()

+ +{

+ +	if [ ${#outfiles[@]} -gt 0 ]; then

+ +		rm -f "${outfiles[@]}"

+ +	fi

+ +	set +x

+ +}

+ +

+ +trap cleanup EXIT

+ +

+ +auto_detect_params()

+ +{

+ +	fs=""

+ +	module=""

+ +	section=""

+ +

+ +	# if module and section were explicitly specified, respect them

+ +	if [[ $_arg_module ]] && [[ $_arg_section ]]; then

+ +		return

+ +	fi

+ +

+ +	# check if names are self-consistent, and determine 'fs'

+ +	for name in ${_arg_name[@]}; do

+ +		if [[ ! $fs ]]; then

+ +			if [[ $name == *-* ]]; then

+ +				fs="-"

+ +			elif [[ $name == *_* ]]; then

+ +				fs="_"

+ +			else

+ +				# can't autodetect section

+ +				return

+ +			fi

+ +		fi

+ +		if [[ $fs == "-" ]] && [[ $name == *_* ]]; then

+ +			die "can't auto-detect params with mixed-style names"

+ +		fi

+ +		if [[ $fs == "_" ]] && [[ $name == *-* ]]; then

+ +			die "can't auto-detect params with mixed-style names"

+ +		fi

+ +	done

+ +

+ +	# try to detect module name

+ +	for name in ${_arg_name[@]}; do

+ +		str=${name%%$fs*}

+ +		if [[ $module ]]; then

+ +			if [[ $str != $module ]]; then

+ +				die "Can't autodetect module because of mixed names ($str and $module)"

+ +			fi

+ +		else

+ +			module="$str"

+ +		fi

+ +	done

+ +

+ +	# try to detect section number

+ +	case "$fs" in

+ +	-)

+ +		section=1

+ +		;;

+ +	_)

+ +		section=3

+ +		;;

+ +	*)

+ +		die "Unknown fs, can't autodetect section number"

+ +		;;

+ +	esac

+ +

+ +	if [[ $module ]]; then

+ +		_arg_module="$module"

+ +	fi

+ +	if [[ $section ]]; then

+ +		_arg_section="$section"

+ +	fi

+ +}

+ +

+ +process_options_logic()

+ +{

+ +	if [[ $_arg_debug == "on" ]]; then

+ +		set -x

+ +	fi

+ +

+ +	auto_detect_params

+ +}

+ +

+ +gen_underline()

+ +{

+ +	name="$1"

+ +	char="$2"

+ +	num="${#name}"

+ +

+ +	printf -v tmpstring "%-${num}s" " "

+ +	echo "${tmpstring// /$char}"

+ +}

+ +

+ +gen_header()

+ +{

+ +	printf "\n%s\n%s\n" "$1" "$(gen_underline "$1" "=")"

+ +}

+ +

+ +gen_section()

+ +{

+ +	printf "\n%s\n%s\n" "$1" "$(gen_underline "$1" "-")"

+ +}

+ +

+ +gen_section_name()

+ +{

+ +	name="$1"

+ +

+ +	gen_section "NAME"

+ +	cat <<- EOF

+ +		$name - 

+ +	EOF

+ +}

+ +

+ +gen_section_synopsis_1()

+ +{

+ +	name="$1"

+ +

+ +	gen_section "SYNOPSIS"

+ +	cat <<- EOF

+ +		[verse]

+ +		'$_arg_module ${name#*-} [<options>]'

+ +	EOF

+ +}

+ +

+ +gen_section_synopsis_3()

+ +{

+ +	name="$1"

+ +

+ +	gen_section "SYNOPSIS"

+ +	cat <<- EOF

+ +		[verse]

+ +		----

+ +		#include <$_arg_module/lib$_arg_module.h>

+ +

+ +		<type> $name();

+ +		----

+ +	EOF

+ +}

+ +

+ +gen_section_example_1()

+ +{

+ +	name="$1"

+ +

+ +	gen_section "EXAMPLE"

+ +	cat <<- EOF

+ +		----

+ +		# $_arg_module ${name#*-}

+ +		----

+ +	EOF

+ +}

+ +

+ +gen_section_example_3()

+ +{

+ +	name="$1"

+ +

+ +	gen_section "EXAMPLE"

+ +	cat <<- EOF

+ +		See example usage in test/lib$_arg_module.c

+ +	EOF

+ +}

+ +

+ +gen_section_options_1()

+ +{

+ +	gen_section "OPTIONS"

+ +cat << EOF

+ +-o::

+ +--option::

+ +	Description

+ +EOF

+ +

+ +	if [[ $_arg_human_option == "on" ]]; then

+ +		printf "\n%s\n" "include::human-option.txt[]"

+ +	fi

+ +	if [[ $_arg_verbose_option == "on" ]]; then

+ +		printf "\n%s\n" "include::verbose-option.txt[]"

+ +	fi

+ +}

+ +

+ +gen_section_seealso_1()

+ +{

+ +	gen_section "SEE ALSO"

+ +	cat <<- EOF

+ +	link$_arg_module:$_arg_module-list[$_arg_section],

+ +	EOF

+ +}

+ +

+ +gen_section_seealso_3()

+ +{

+ +	gen_section "SEE ALSO"

+ +	cat <<- EOF

+ +	linklib$_arg_module:${_arg_module}_other_API[$_arg_section],

+ +	EOF

+ +}

+ +

+ +gen_cli()

+ +{

+ +	name="$1"

+ +	path="$docbase/$_arg_module"

+ +	if [ ! -d "$path" ]; then

+ +		die "Not found: $path"

+ +	fi

+ +

+ +	tmp="$(mktemp -p "$path" "$name.txt.XXXX")"

+ +	outfiles+=("$tmp")

+ +

+ +	# Start template generation

+ +	printf "%s\n" "$copyright_cli" > "$tmp"

+ +	gen_header "$name" >> "$tmp"

+ +	gen_section_name "$name" >> "$tmp"

+ +	gen_section_synopsis_1 "$name" >> "$tmp"

+ +	gen_section "DESCRIPTION" >> "$tmp"

+ +	gen_section_example_1 "$name" >> "$tmp"

+ +	gen_section_options_1 >> "$tmp"

+ +	printf "\n%s\n" "$copyright_footer_cli" >> "$tmp"

+ +	gen_section_seealso_1 >> "$tmp"

+ +}

+ +

+ +gen_lib()

+ +{

+ +	name="$1"

+ +	path="$docbase/$_arg_module/lib"

+ +	if [ ! -d "$path" ]; then

+ +		die "Not found: $path"

+ +	fi

+ +

+ +	tmp="$(mktemp -p "$path" "$name.txt.XXXX")"

+ +	outfiles+=("$tmp")

+ +

+ +	# Start template generation

+ +	printf "%s\n" "$copyright_lib" > "$tmp"

+ +	gen_header "$name($_arg_section)" >> "$tmp"

+ +	gen_section_name "$name" >> "$tmp"

+ +	gen_section_synopsis_3 "$name" >> "$tmp"

+ +	gen_section "DESCRIPTION" >> "$tmp"

+ +	gen_section "RETURN VALUE" >> "$tmp"

+ +	gen_section_example_3 "$name" >> "$tmp"

+ +	printf "\n%s\n" "$copyright_footer_lib" >> "$tmp"

+ +	gen_section_seealso_3 >> "$tmp"

+ +}

+ +

+ +gen_man()

+ +{

+ +	name="$1"

+ +	case "$_arg_section" in

+ +	1)

+ +		gen_cli "$name"

+ +		;;

+ +	3)

+ +		gen_lib "$name"

+ +		;;

+ +	*)

+ +		die "Unknown section: $_arg_section"

+ +		;;

+ +	esac

+ +}

+ +

+ +gen_include()

+ +{

+ +	echo "in gen_include"

+ +}

+ +

+ +main()

+ +{

+ +	process_options_logic

+ +

+ +	cmd="$_arg_command"

+ +	case "$cmd" in

+ +	gen-man)

+ +		for name in ${_arg_name[@]}; do

+ +			gen_man "$name"

+ +		done

+ +		;;

+ +	gen-include)

+ +		for name in ${_arg_name[@]}; do

+ +			gen_include

+ +		done

+ +		;;

+ +	*)

+ +		die "Unknown command: $cmd"

+ +		;;

+ +	esac

+ +

+ +	if [[ $_arg_dump == "on" ]]; then

+ +		for file in ${outfiles[@]}; do

+ +			echo "${file##*/}"

+ +			cat "$file"

+ +			rm "$file"

+ +		done

+ +	elif [ ${#outfiles[@]} -gt 0 ]; then

+ +		if [[ $_arg_edit = "on" ]]; then

+ +			vim -p "${outfiles[@]}"

+ +		fi

+ +

+ +		for file in ${outfiles[@]}; do

+ +			mv "$file" "${file%.*}"

+ +		done

+ +	fi

+ +}

+ +

+ +main "$@"

+ diff --git a/scripts/docsurgeon_parser_generator.m4 b/scripts/docsurgeon_parser_generator.m4

+ new file mode 100644

+ index 0000000..9283c7c

+ --- /dev/null

+ +++ b/scripts/docsurgeon_parser_generator.m4

+ @@ -0,0 +1,23 @@

+ +#!/bin/bash

+ +

+ +# m4_ignore(

+ +echo "This is just a parsing library template, not the library - pass this file to 'argbash' to fix this." >&2

+ +exit 11  #)Created by argbash-init v2.9.0

+ +# Rearrange the order of options below according to what you would like to see in the help message.

+ +# ARG_OPTIONAL_REPEATED([name], [n], [Command or function name to generate a template for.\n Can be repeated for multiple names. ], [])

+ +# ARG_OPTIONAL_BOOLEAN([edit], [e], [Edit template files after creation], [on])

+ +# ARG_OPTIONAL_BOOLEAN([debug], [], [Debug script problems (enables set -x)], )

+ +# ARG_OPTIONAL_BOOLEAN([dump], [], [Write generated file to stdout instead of a file], )

+ +# ARG_OPTIONAL_SINGLE([module], [m], [Module (Docs subdir) in which to create the template], [])

+ +# ARG_OPTIONAL_SINGLE([section], [s], [man section for which to create the template], [])

+ +# ARG_OPTIONAL_BOOLEAN([human-option], [u], [Include the human option in 'OPTIONS'], )

+ +# ARG_OPTIONAL_BOOLEAN([verbose-option], [V], [Include the verbose option in 'OPTIONS'], )

+ +# ARG_POSITIONAL_DOUBLEDASH()

+ +# ARG_POSITIONAL_SINGLE([command], [Operation to perform:\n  gen-man\n  gen-include], [])

+ +# ARGBASH_SET_DELIM([ =])

+ +# ARG_OPTION_STACKING([getopt])

+ +# ARG_RESTRICT_VALUES([no-local-options])

+ +# ARG_DEFAULTS_POS

+ +# ARG_HELP([Tool to aid in creating and managing man page templates])

+ +# ARG_VERSION([echo "docsurgeon 0.1"])

+ +# ARGBASH_GO

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,167 @@ 

+ From 8f4e42c0c526e85b045fd0329df7cb904f511c98 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 7 Oct 2021 14:59:53 -0700

+ Subject: [PATCH 049/217] daxctl: Add "Soft Reservation" theory of operation

+ 

+ As systems are starting to ship memory with the EFI "Special Purpose"

+ attribute that Linux optionally turns into "Soft Reserved" ranges one of

+ the immediate first questions is "where is my special memory, and how do

+ access it". Add some documentation to explain the default behaviour of

+ "Soft Reserved".

+ 

+ Link: https://lore.kernel.org/r/163364399303.201290.6835215953983673447.stgit@dwillia2-desk3.amr.corp.intel.com

+ Reported-by: John Groves <john@jagalactic.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .../daxctl/daxctl-reconfigure-device.txt      | 127 ++++++++++++------

+  1 file changed, 88 insertions(+), 39 deletions(-)

+ 

+ diff --git a/Documentation/daxctl/daxctl-reconfigure-device.txt b/Documentation/daxctl/daxctl-reconfigure-device.txt

+ index f112b3c..132684c 100644

+ --- a/Documentation/daxctl/daxctl-reconfigure-device.txt

+ +++ b/Documentation/daxctl/daxctl-reconfigure-device.txt

+ @@ -12,6 +12,94 @@ SYNOPSIS

+  [verse]

+  'daxctl reconfigure-device' <dax0.0> [<dax1.0>...<daxY.Z>] [<options>]

+  

+ +DESCRIPTION

+ +-----------

+ +

+ +Reconfigure the operational mode of a dax device. This can be used to convert

+ +a regular 'devdax' mode device to the 'system-ram' mode which arranges for the

+ +dax range to be hot-plugged into the system as regular memory.

+ +

+ +NOTE: This is a destructive operation. Any data on the dax device *will* be

+ +lost.

+ +

+ +NOTE: Device reconfiguration depends on the dax-bus device model. See

+ +linkdaxctl:daxctl-migrate-device-model[1] for more information. If dax-class is

+ +in use (via the dax_pmem_compat driver), the reconfiguration will fail with an

+ +error such as the following:

+ +----

+ +# daxctl reconfigure-device --mode=system-ram --region=0 all

+ +libdaxctl: daxctl_dev_disable: dax3.0: error: device model is dax-class

+ +dax3.0: disable failed: Operation not supported

+ +error reconfiguring devices: Operation not supported

+ +reconfigured 0 devices

+ +----

+ +

+ +'daxctl-reconfigure-device' nominally expects that it will online new memory

+ +blocks as 'movable', so that kernel data doesn't make it into this memory.

+ +However, there are other potential agents that may be configured to

+ +automatically online new hot-plugged memory as it appears. Most notably,

+ +these are the '/sys/devices/system/memory/auto_online_blocks' configuration,

+ +or system udev rules. If such an agent races to online memory sections, daxctl

+ +checks if the blocks were onlined as 'movable' memory. If this was not the

+ +case, and the memory blocks are found to be in a different zone, then a

+ +warning is displayed. If it is desired that a different agent control the

+ +onlining of memory blocks, and the associated memory zone, then it is

+ +recommended to use the --no-online option described below. This will abridge

+ +the device reconfiguration operation to just hotplugging the memory, and

+ +refrain from then onlining it.

+ +

+ +In case daxctl detects that there is a kernel policy to auto-online blocks

+ +(via /sys/devices/system/memory/auto_online_blocks), then reconfiguring to

+ +system-ram will result in a failure. This can be overridden with '--force'.

+ +

+ +

+ +THEORY OF OPERATION

+ +-------------------

+ +The kernel device-dax subsystem surfaces character devices

+ +that provide DAX-access (direct mappings sans page-cache buffering) to a

+ +given memory region. The devices are named /dev/daxX.Y where X is a

+ +region-id and Y is an instance-id within that region. There are 2

+ +mechanisms that trigger device-dax instances to appear:

+ +

+ +1. Persistent Memory (PMEM) namespace configured in "devdax" mode. See

+ +"ndctl create-namspace --help" and

+ +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dax/Kconfig[CONFIG_DEV_DAX_PMEM].

+ +In this case the device-dax instance is statically sized to its host

+ +memory region which is bounded to the physical address range of the host

+ +namespace.

+ +

+ +2. Soft Reserved memory enumerated by platform firmware. On EFI systems

+ +this is communicated via the so called EFI_MEMORY_SP "Special Purpose"

+ +attribute. See

+ +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dax/Kconfig[CONFIG_DEV_DAX_HMEM].

+ +In this case the device-dax instance(s) associated with the given memory

+ +region can be resized and divided into multiple devices.

+ +

+ +In the Soft Reservation case the expectation for EFI + ACPI based

+ +platforms is that in addition to the EFI_MEMORY_SP attribute the

+ +firmware also creates distinct ACPI proximity domains for any address

+ +range that has different performance characteristics than default

+ +"System RAM". So, the SRAT will define the proximity domain, the SLIT

+ +communicates relative distance to other proximity domains, and the HMAT

+ +is populated with nominal read/write latency and read/write bandwidth

+ +data. That HMAT data is emitted to the kernel log on bootup, and also

+ +exported to sysfs. See

+ +https://www.kernel.org/doc/html/latest/admin-guide/mm/numaperf.html[NUMAPERF],

+ +for the runtime representation of CPU to Memory node performance

+ +details.

+ +

+ +Outside of the NUMA performance details linked above the other method to

+ +detect the presence of "Soft Reserved" memory is to dump /proc/iomem and

+ +look for "Soft Reserved" ranges. If the kernel was not built with

+ +CONFIG_EFI_SOFTRESERVE, predates the introduction of

+ +CONFIG_EFI_SOFTRESERVE (v5.5), or was booted with the efi=nosoftreserve

+ +command line then device-dax will not attach and the expectation is that

+ +the memory shows up as a memory-only NUMA node. Otherwise the memory

+ +shows up as a device-dax instance and DAXCTL(1) can be used to

+ +optionally partition it and assign the memory back to the kernel as

+ +"System RAM", or the device can be mapped directly as the back end of a

+ +userspace memory allocator like https://pmem.io/vmem/libvmem/[LIBVMEM].

+ +

+  EXAMPLES

+  --------

+  

+ @@ -83,45 +171,6 @@ reconfigured 1 device

+  reconfigured 1 device

+  ----

+  

+ -DESCRIPTION

+ ------------

+ -

+ -Reconfigure the operational mode of a dax device. This can be used to convert

+ -a regular 'devdax' mode device to the 'system-ram' mode which arranges for the

+ -dax range to be hot-plugged into the system as regular memory.

+ -

+ -NOTE: This is a destructive operation. Any data on the dax device *will* be

+ -lost.

+ -

+ -NOTE: Device reconfiguration depends on the dax-bus device model. See

+ -linkdaxctl:daxctl-migrate-device-model[1] for more information. If dax-class is

+ -in use (via the dax_pmem_compat driver), the reconfiguration will fail with an

+ -error such as the following:

+ -----

+ -# daxctl reconfigure-device --mode=system-ram --region=0 all

+ -libdaxctl: daxctl_dev_disable: dax3.0: error: device model is dax-class

+ -dax3.0: disable failed: Operation not supported

+ -error reconfiguring devices: Operation not supported

+ -reconfigured 0 devices

+ -----

+ -

+ -'daxctl-reconfigure-device' nominally expects that it will online new memory

+ -blocks as 'movable', so that kernel data doesn't make it into this memory.

+ -However, there are other potential agents that may be configured to

+ -automatically online new hot-plugged memory as it appears. Most notably,

+ -these are the '/sys/devices/system/memory/auto_online_blocks' configuration,

+ -or system udev rules. If such an agent races to online memory sections, daxctl

+ -checks if the blocks were onlined as 'movable' memory. If this was not the

+ -case, and the memory blocks are found to be in a different zone, then a

+ -warning is displayed. If it is desired that a different agent control the

+ -onlining of memory blocks, and the associated memory zone, then it is

+ -recommended to use the --no-online option described below. This will abridge

+ -the device reconfiguration operation to just hotplugging the memory, and

+ -refrain from then onlining it.

+ -

+ -In case daxctl detects that there is a kernel policy to auto-online blocks

+ -(via /sys/devices/system/memory/auto_online_blocks), then reconfiguring to

+ -system-ram will result in a failure. This can be overridden with '--force'.

+  

+  OPTIONS

+  -------

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,46 @@ 

+ From c55b18181281b2fffadb9e0e8955d74b8b719349 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Fri, 17 Dec 2021 19:25:11 -0700

+ Subject: [PATCH 061/217] libcxl: fix potential NULL dereference in

+  cxl_memdev_nvdimm_bridge_active()

+ 

+ Static analysis points out that the function above has a check for

+ 'if (!bridge)', implying that bridge maybe NULL, but it is dereferenced

+ before the check, which could result in a NULL dereference.

+ 

+ Fix this by moving any accesses to the bridge structure after the NULL

+ check.

+ 

+ Link: https://lore.kernel.org/r/20211218022511.314928-1-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 7 +++++--

+  1 file changed, 5 insertions(+), 2 deletions(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index f0664be..3390eb9 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -420,12 +420,15 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)

+  {

+  	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+  	struct cxl_nvdimm_bridge *bridge = memdev->bridge;

+ -	char *path = bridge->dev_buf;

+ -	int len = bridge->buf_len;

+ +	char *path;

+ +	int len;

+  

+  	if (!bridge)

+  		return 0;

+  

+ +	path = bridge->dev_buf;

+ +	len = bridge->buf_len;

+ +

+  	if (snprintf(path, len, "%s/driver", bridge->dev_path) >= len) {

+  		err(ctx, "%s: nvdimm bridge buffer too small!\n",

+  				cxl_memdev_get_devname(memdev));

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,142 @@ 

+ From 25062cf34c70012f5d42ce1fef7e2dc129807c10 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Fri, 17 Dec 2021 21:14:37 -0700

+ Subject: [PATCH 064/217] ndctl: release v72

+ 

+ This release incorporates functionality up to the 5.16 kernel.

+ 

+ Highlights include a new utility and library for interfacing with the

+ 'CXL' drivers and devices, a policy based configuration mechanism for

+ ndctl and daxctl, fixes, test updates, and general additions for the

+ PAPR family of NVDIMMs, more seed device accounting fixes, misc unit

+ test and documentation updates, and fixes to NVDIMM bus scrubbing.

+ 

+ Commands:

+   cxl-cli: new utility providing list, {read,write,zero}-label commands

+   daxctl-reconfigure-device: new --check-config option

+   ndctl-monitor: add support for a new unified config file format

+   ndctl-*-namespace: seed namespace accounting fixes

+ 

+ Tests:

+   Fix device-dax mremap() test

+   Exercise soft_offline_page() corner cases

+   Fix btt expect table compile warning

+   monitor.sh: add checking the presence of jq command ahead of time

+ 

+ APIs:

+   ndctl_bus_nfit_translate_spa

+   ndctl_dimm_sizeof_namespace_index

+   ndctl_get_config_path

+   ndctl_set_config_path

+   daxctl_dev_has_online_memory

+   daxctl_dev_will_auto_online_memory

+   daxctl_get_config_path

+   daxctl_set_config_path

+   cxl_cmd_get_devname

+   cxl_cmd_get_mbox_status

+   cxl_cmd_get_out_size

+   cxl_cmd_health_info_get_dirty_shutdowns

+   cxl_cmd_health_info_get_ext_corrected_persistent_normal

+   cxl_cmd_health_info_get_ext_corrected_persistent_warning

+   cxl_cmd_health_info_get_ext_corrected_volatile_normal

+   cxl_cmd_health_info_get_ext_corrected_volatile_warning

+   cxl_cmd_health_info_get_ext_life_used_critical

+   cxl_cmd_health_info_get_ext_life_used_normal

+   cxl_cmd_health_info_get_ext_life_used_warning

+   cxl_cmd_health_info_get_ext_temperature_critical

+   cxl_cmd_health_info_get_ext_temperature_normal

+   cxl_cmd_health_info_get_ext_temperature_warning

+   cxl_cmd_health_info_get_hw_replacement_needed

+   cxl_cmd_health_info_get_life_used

+   cxl_cmd_health_info_get_maintenance_needed

+   cxl_cmd_health_info_get_media_data_loss_imminent

+   cxl_cmd_health_info_get_media_data_lost

+   cxl_cmd_health_info_get_media_normal

+   cxl_cmd_health_info_get_media_not_ready

+   cxl_cmd_health_info_get_media_persistence_loss_imminent

+   cxl_cmd_health_info_get_media_persistence_lost

+   cxl_cmd_health_info_get_media_powerloss_data_loss

+   cxl_cmd_health_info_get_media_powerloss_persistence_loss

+   cxl_cmd_health_info_get_media_shutdown_data_loss

+   cxl_cmd_health_info_get_media_shutdown_persistence_loss

+   cxl_cmd_health_info_get_performance_degraded

+   cxl_cmd_health_info_get_pmem_errors

+   cxl_cmd_health_info_get_temperature

+   cxl_cmd_health_info_get_volatile_errors

+   cxl_cmd_identify_get_fw_rev

+   cxl_cmd_identify_get_label_size

+   cxl_cmd_identify_get_partition_align

+   cxl_cmd_new_get_health_info

+   cxl_cmd_new_identify

+   cxl_cmd_new_raw

+   cxl_cmd_new_read_label

+   cxl_cmd_new_write_label

+   cxl_cmd_read_label_get_payload

+   cxl_cmd_ref

+   cxl_cmd_set_input_payload

+   cxl_cmd_set_output_payload

+   cxl_cmd_submit

+   cxl_cmd_unref

+   cxl_get_log_priority

+   cxl_get_private_data

+   cxl_get_userdata

+   cxl_memdev_get_ctx

+   cxl_memdev_get_devname

+   cxl_memdev_get_firmware_verison

+   cxl_memdev_get_first

+   cxl_memdev_get_id

+   cxl_memdev_get_label_size

+   cxl_memdev_get_major

+   cxl_memdev_get_minor

+   cxl_memdev_get_next

+   cxl_memdev_get_pmem_size

+   cxl_memdev_get_ram_size

+   cxl_memdev_nvdimm_bridge_active

+   cxl_memdev_read_label

+   cxl_memdev_write_label

+   cxl_memdev_zero_label

+   cxl_new

+   cxl_ref

+   cxl_set_log_fn

+   cxl_set_log_priority

+   cxl_set_private_data

+   cxl_set_userdata

+   cxl_unref

+ ---

+  Makefile.am.in | 8 ++++----

+  git-version    | 2 +-

+  2 files changed, 5 insertions(+), 5 deletions(-)

+ 

+ diff -up ndctl-71.1/Makefile.am.in.orig ndctl-71.1/Makefile.am.in

+ --- ndctl-71.1/Makefile.am.in.orig	2022-10-07 15:20:47.982353042 -0400

+ +++ ndctl-71.1/Makefile.am.in	2022-10-07 15:21:02.174401362 -0400

+ @@ -36,13 +36,13 @@ SED_PROCESS = \

+  	-e 's,@includedir\@,$(includedir),g' \

+  	< $< > $@ || rm $@

+  

+ -LIBNDCTL_CURRENT=25

+ +LIBNDCTL_CURRENT=26

+  LIBNDCTL_REVISION=1

+ -LIBNDCTL_AGE=19

+ +LIBNDCTL_AGE=20

+  

+ -LIBDAXCTL_CURRENT=6

+ +LIBDAXCTL_CURRENT=7

+  LIBDAXCTL_REVISION=0

+ -LIBDAXCTL_AGE=5

+ +LIBDAXCTL_AGE=6

+  

+  LIBCXL_CURRENT=1

+  LIBCXL_REVISION=0

+ diff -up ndctl-71.1/git-version.orig ndctl-71.1/git-version

+ --- ndctl-71.1/git-version.orig	2022-10-07 15:21:02.175401365 -0400

+ +++ ndctl-71.1/git-version	2022-10-07 15:21:27.267486796 -0400

+ @@ -19,7 +19,7 @@ dirty() {

+  	fi

+  }

+  

+ -DEF_VER=71.1

+ +DEF_VER=72

+  

+  LF='

+  '

@@ -0,0 +1,32 @@ 

+ From 20a714fe89a7941ef99898821719a46f04f7488b Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 4 Jan 2022 17:18:23 -0700

+ Subject: [PATCH 067/217] ndctl: add repology graphic to README.md

+ 

+ Add a graphic/badge from repology showing the packaging status of ndctl

+ with various distros.

+ 

+ Link: https://lore.kernel.org/r/20220105001823.299797-1-vishal.l.verma@intel.com

+ Reviewed-by: Ira Weiny <ira.weiny@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  README.md | 3 +++

+  1 file changed, 3 insertions(+)

+ 

+ diff --git a/README.md b/README.md

+ index 89dfc87..4ab4523 100644

+ --- a/README.md

+ +++ b/README.md

+ @@ -4,6 +4,9 @@

+  Utility library for managing the libnvdimm (non-volatile memory device)

+  sub-system in the Linux kernel

+    

+ +<a href="https://repology.org/project/ndctl/versions">

+ +    <img src="https://repology.org/badge/vertical-allrepos/ndctl.svg" alt="Packaging status" align="right">

+ +</a>

+  

+  Build

+  =====

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,29 @@ 

+ From 3f2a2973b23fa86c810aab49eeb8ff5f97a02720 Mon Sep 17 00:00:00 2001

+ From: Yasunori Goto <y-goto@fujitsu.com>

+ Date: Wed, 3 Feb 2021 19:17:07 +0900

+ Subject: [PATCH 068/217] Documentation/ndctl: fix self-reference of ndctl

+  disable-namespace

+ 

+ The man manual of ndctl disable-namespace link to itself at See

+ Also section. It should be enable-namespace instead of it.

+ 

+ Signed-off-by: Yasunori Goto <y-goto@fujitsu.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ Link: https://github.com/pmem/ndctl/pull/160

+ ---

+  Documentation/ndctl/ndctl-disable-namespace.txt | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/Documentation/ndctl/ndctl-disable-namespace.txt b/Documentation/ndctl/ndctl-disable-namespace.txt

+ index 5d3a8be..187348f 100644

+ --- a/Documentation/ndctl/ndctl-disable-namespace.txt

+ +++ b/Documentation/ndctl/ndctl-disable-namespace.txt

+ @@ -22,4 +22,4 @@ include::../copyright.txt[]

+  

+  SEE ALSO

+  --------

+ -linkndctl:ndctl-disable-namespace[1]

+ +linkndctl:ndctl-enable-namespace[1]

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,97 @@ 

+ From 475cb041a97d3c7140efd1b0cda820fb22b69d11 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:31:44 -0800

+ Subject: [PATCH 069/217] ndctl/docs: Clarify update-firwmware activation

+  'overflow' conditions

+ 

+ Give examples and remediation for "overflow" events, i.e. where the

+ estimated time to complete activation exceeds the platform advertised

+ maximum. When that happens forced activation can lead to undefined results.

+ 

+ Link: https://lore.kernel.org/r/164141830490.3990253.6263569501446070716.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/ndctl/ndctl-update-firmware.txt | 64 ++++++++++++++++++-

+  1 file changed, 63 insertions(+), 1 deletion(-)

+ 

+ diff --git a/Documentation/ndctl/ndctl-update-firmware.txt b/Documentation/ndctl/ndctl-update-firmware.txt

+ index 1080d62..6166457 100644

+ --- a/Documentation/ndctl/ndctl-update-firmware.txt

+ +++ b/Documentation/ndctl/ndctl-update-firmware.txt

+ @@ -58,7 +58,69 @@ include::xable-bus-options.txt[]

+  	Arm a device for firmware activation. This is enabled by default

+  	when a firmware image is specified. Specify --no-arm to disable

+  	this default. Otherwise, without a firmware image, this option can be

+ -	used to manually arm a device for firmware activate.

+ +	used to manually arm a device for firmware activate. When a

+ +	device transitions from unarmed to armed the platform recalculates the

+ +	firmware activation time and compares it against the maximum platform

+ +	supported time. If the activation time would exceed the platform maximum the

+ +	arm attempt is aborted:

+ +

+ +[verse]

+ +ndctl update-firmware --arm --bus=nfit_test.0 all

+ +  Error: update firmware: nmem4: arm aborted, tripped overflow

+ +[

+ +  {

+ +    "dev":"nmem1",

+ +    "id":"cdab-0a-07e0-ffffffff",

+ +    "handle":"0",

+ +    "phys_id":"0",

+ +    "security":"disabled",

+ +    "firmware":{

+ +      "current_version":"0",

+ +      "can_update":true

+ +    }

+ +  },

+ +  {

+ +    "dev":"nmem3",

+ +    "id":"cdab-0a-07e0-fffeffff",

+ +    "handle":"0x100",

+ +    "phys_id":"0x2",

+ +    "security":"disabled",

+ +    "firmware":{

+ +      "current_version":"0",

+ +      "can_update":true

+ +    }

+ +  },

+ +  {

+ +    "dev":"nmem2",

+ +    "id":"cdab-0a-07e0-feffffff",

+ +    "handle":"0x1",

+ +    "phys_id":"0x1",

+ +    "security":"disabled",

+ +    "firmware":{

+ +      "current_version":"0",

+ +      "can_update":true

+ +    }

+ +  }

+ +]

+ +updated 3 nmems.

+ +

+ +	It is possible, but not recommended, to ignore timeout overflows

+ +	with the --force option. At any point to view the 'armed' state of the

+ +	bus do:

+ +

+ +[verse]

+ +ndctl list -BF -b nfit_test.0

+ +[

+ +  {

+ +    "provider":"nfit_test.0",

+ +    "dev":"ndbus2",

+ +    "scrub_state":"idle",

+ +    "firmware":{

+ +      "activate_method":"suspend",

+ +      "activate_state":"overflow"

+ +    }

+ +  }

+ +]

+  

+  -D::

+  --disarm::

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,171 @@ 

+ From e423b467e10e3405e6e09260b7669e7022b5f5f7 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:31:50 -0800

+ Subject: [PATCH 070/217] ndctl/test: Prepare for BLK-aperture support removal

+ 

+ The kernel is dropping its support for the BLK-aperture access method. The

+ primary side effect of this for nfit_test is that NVDIMM namespace labeling

+ will not be enabled by default. Update the unit tests to initialize the

+ label index area in this scenario.

+ 

+ Link: https://lore.kernel.org/r/164141830999.3990253.5021445352398348657.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/core.c     | 31 ++++++++++++++++++++++++++++---

+  test/libndctl.c | 49 +++++++++++++++++++++++++++++++++++--------------

+  2 files changed, 63 insertions(+), 17 deletions(-)

+ 

+ diff --git a/test/core.c b/test/core.c

+ index 2b03aa9..93e1dae 100644

+ --- a/test/core.c

+ +++ b/test/core.c

+ @@ -261,8 +261,8 @@ retry:

+  		ndctl_bus_foreach(nd_ctx, bus) {

+  			struct ndctl_region *region;

+  

+ -			if (strncmp(ndctl_bus_get_provider(bus),

+ -						"nfit_test", 9) != 0)

+ +			if (strcmp(ndctl_bus_get_provider(bus),

+ +				   "nfit_test.0") != 0)

+  				continue;

+  			ndctl_region_foreach(bus, region)

+  				ndctl_region_disable_invalidate(region);

+ @@ -280,5 +280,30 @@ retry:

+  			NULL, NULL, NULL, NULL);

+  	if (rc)

+  		kmod_unref(*ctx);

+ -	return rc;

+ +

+ +	if (!nd_ctx)

+ +		return rc;

+ +

+ +	ndctl_bus_foreach (nd_ctx, bus) {

+ +		struct ndctl_region *region;

+ +		struct ndctl_dimm *dimm;

+ +

+ +		if (strcmp(ndctl_bus_get_provider(bus), "nfit_test.0") != 0)

+ +			continue;

+ +

+ +		ndctl_region_foreach (bus, region)

+ +			ndctl_region_disable_invalidate(region);

+ +

+ +		ndctl_dimm_foreach (bus, dimm) {

+ +			ndctl_dimm_read_label_index(dimm);

+ +			ndctl_dimm_init_labels(dimm, NDCTL_NS_VERSION_1_2);

+ +			ndctl_dimm_disable(dimm);

+ +			ndctl_dimm_enable(dimm);

+ +		}

+ +

+ +		ndctl_region_foreach (bus, region)

+ +			ndctl_region_enable(region);

+ +	}

+ +

+ +	return 0;

+  }

+ diff --git a/test/libndctl.c b/test/libndctl.c

+ index d9b50f4..c0e4b4c 100644

+ --- a/test/libndctl.c

+ +++ b/test/libndctl.c

+ @@ -2587,17 +2587,41 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,

+  	return 0;

+  }

+  

+ -static void reset_bus(struct ndctl_bus *bus)

+ +enum dimm_reset {

+ +	DIMM_INIT,

+ +	DIMM_ZERO,

+ +};

+ +

+ +static int reset_dimms(struct ndctl_bus *bus, enum dimm_reset reset)

+  {

+ -	struct ndctl_region *region;

+  	struct ndctl_dimm *dimm;

+ +	int rc = 0;

+ +

+ +	ndctl_dimm_foreach(bus, dimm) {

+ +		if (reset == DIMM_ZERO)

+ +			ndctl_dimm_zero_labels(dimm);

+ +		else {

+ +			ndctl_dimm_read_label_index(dimm);

+ +			ndctl_dimm_init_labels(dimm, NDCTL_NS_VERSION_1_2);

+ +		}

+ +		ndctl_dimm_disable(dimm);

+ +		rc = ndctl_dimm_enable(dimm);

+ +		if (rc)

+ +			break;

+ +	}

+ +

+ +	return rc;

+ +}

+ +

+ +static void reset_bus(struct ndctl_bus *bus, enum dimm_reset reset)

+ +{

+ +	struct ndctl_region *region;

+  

+  	/* disable all regions so that set_config_data commands are permitted */

+  	ndctl_region_foreach(bus, region)

+  		ndctl_region_disable_invalidate(region);

+  

+ -	ndctl_dimm_foreach(bus, dimm)

+ -		ndctl_dimm_zero_labels(dimm);

+ +	reset_dimms(bus, reset);

+  

+  	/* set regions back to their default state */

+  	ndctl_region_foreach(bus, region)

+ @@ -2608,7 +2632,6 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  {

+  	struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER0);

+  	struct ndctl_region *region;

+ -	struct ndctl_dimm *dimm;

+  	int rc;

+  

+  	if (!bus)

+ @@ -2625,13 +2648,10 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  	if (rc)

+  		return rc;

+  

+ -	ndctl_dimm_foreach(bus, dimm) {

+ -		rc = ndctl_dimm_zero_labels(dimm);

+ -		if (rc < 0) {

+ -			fprintf(stderr, "failed to zero %s\n",

+ -					ndctl_dimm_get_devname(dimm));

+ -			return rc;

+ -		}

+ +	rc = reset_dimms(bus, DIMM_INIT);

+ +	if (rc < 0) {

+ +		fprintf(stderr, "failed to reset dimms\n");

+ +		return rc;

+  	}

+  

+  	/*

+ @@ -2649,14 +2669,14 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  		rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), DAX);

+  		if (rc)

+  			return rc;

+ -		reset_bus(bus);

+ +		reset_bus(bus, DIMM_INIT);

+  	}

+  

+  	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {

+  		rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), PFN);

+  		if (rc)

+  			return rc;

+ -		reset_bus(bus);

+ +		reset_bus(bus, DIMM_INIT);

+  	}

+  

+  	return check_regions(bus, regions0, ARRAY_SIZE(regions0), BTT);

+ @@ -2671,6 +2691,7 @@ static int do_test1(struct ndctl_ctx *ctx, struct ndctl_test *test)

+  		return -ENXIO;

+  

+  	ndctl_bus_wait_probe(bus);

+ +	reset_bus(bus, DIMM_ZERO);

+  

+  	/*

+  	 * Starting with v4.10 the dimm on nfit_test.1 gets a unique

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,428 @@ 

+ From 6538529be5738f06543a0d7178f97e0b0e6b63c2 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:31:55 -0800

+ Subject: [PATCH 071/217] ndctl/test: Move 'reset()' to function in 'common'

+ 

+ When BLK mode is removed, tests that expect the nfit_test region to allow

+ pmem namespace creation will need to 'init' rather than 'zero' labels. In

+ preparation, take the time opportunity to move reset() to a common

+ function. So that 'ndctl zero-labels' can be replaced with 'ndctl

+ init-labels' in one central location.

+ 

+ Link: https://lore.kernel.org/r/164141831509.3990253.14783946910211635678.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/blk-exhaust.sh             |  4 +---

+  test/btt-check.sh               |  7 -------

+  test/btt-errors.sh              | 12 +++---------

+  test/btt-pad-compat.sh          |  7 -------

+  test/clear.sh                   |  4 +---

+  test/common                     | 15 +++++++++++++++

+  test/create.sh                  |  4 +---

+  test/daxctl-create.sh           |  4 ++--

+  test/daxdev-errors.sh           |  4 +---

+  test/firmware-update.sh         |  8 +++-----

+  test/inject-error.sh            |  7 -------

+  test/max_available_extent_ns.sh |  9 +--------

+  test/monitor.sh                 | 11 ++---------

+  test/multi-dax.sh               |  4 +---

+  test/pfn-meta-errors.sh         |  4 +---

+  test/pmem-errors.sh             |  4 +---

+  test/rescan-partitions.sh       |  7 -------

+  test/sector-mode.sh             |  9 ++-------

+  test/track-uuid.sh              |  4 +---

+  19 files changed, 36 insertions(+), 92 deletions(-)

+ 

+ diff --git a/test/blk-exhaust.sh b/test/blk-exhaust.sh

+ index 09c4aae..b6d3808 100755

+ --- a/test/blk-exhaust.sh

+ +++ b/test/blk-exhaust.sh

+ @@ -14,9 +14,7 @@ trap 'err $LINENO' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  # if the kernel accounting is correct we should be able to create two

+  # pmem and two blk namespaces on nfit_test.0

+ diff --git a/test/btt-check.sh b/test/btt-check.sh

+ index 8e0b489..65b5c58 100755

+ --- a/test/btt-check.sh

+ +++ b/test/btt-check.sh

+ @@ -39,13 +39,6 @@ create()

+  	[ $size -gt 0 ] || err "$LINENO"

+  }

+  

+ -reset()

+ -{

+ -	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ -}

+ -

+  # re-enable the BTT namespace, and do IO to it in an attempt to

+  # verify it still comes up ok, and functions as expected

+  post_repair_test()

+ diff --git a/test/btt-errors.sh b/test/btt-errors.sh

+ index 4e59f57..5a20d26 100755

+ --- a/test/btt-errors.sh

+ +++ b/test/btt-errors.sh

+ @@ -45,9 +45,7 @@ trap 'err $LINENO cleanup' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  rc=1

+  

+ @@ -126,9 +124,7 @@ dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1

+  

+  # reset everything to get a clean log

+  if grep -q "$MNT" /proc/mounts; then umount $MNT; fi

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  dev="x"

+  json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector)

+  eval "$(echo "$json" | json2var)"

+ @@ -148,9 +144,7 @@ force_raw 0

+  dd if=/dev/$blockdev of=/dev/null iflag=direct bs=4096 count=1 && err $LINENO || true

+  

+  # done, exit

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  cleanup

+  _cleanup

+  exit 0

+ diff --git a/test/btt-pad-compat.sh b/test/btt-pad-compat.sh

+ index bf1ea54..be538b7 100755

+ --- a/test/btt-pad-compat.sh

+ +++ b/test/btt-pad-compat.sh

+ @@ -37,13 +37,6 @@ create()

+  	fi

+  }

+  

+ -reset()

+ -{

+ -	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ -}

+ -

+  verify_idx()

+  {

+  	idx0="$1"

+ diff --git a/test/clear.sh b/test/clear.sh

+ index fb9d52c..c4d02d5 100755

+ --- a/test/clear.sh

+ +++ b/test/clear.sh

+ @@ -14,9 +14,7 @@ trap 'err $LINENO' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  rc=1

+  

+ diff --git a/test/common b/test/common

+ index 6bcefca..3c54d63 100644

+ --- a/test/common

+ +++ b/test/common

+ @@ -46,6 +46,21 @@ err()

+  	exit $rc

+  }

+  

+ +reset()

+ +{

+ +	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ +	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ +	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +}

+ +

+ +reset1()

+ +{

+ +	$NDCTL disable-region -b $NFIT_TEST_BUS1 all

+ +	$NDCTL zero-labels -b $NFIT_TEST_BUS1 all

+ +	$NDCTL enable-region -b $NFIT_TEST_BUS1 all

+ +}

+ +

+ +

+  # check_min_kver

+  # $1: Supported kernel version. format: X.Y

+  #

+ diff --git a/test/create.sh b/test/create.sh

+ index b0fd99f..e9baaa0 100755

+ --- a/test/create.sh

+ +++ b/test/create.sh

+ @@ -15,9 +15,7 @@ trap 'err $LINENO' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  rc=1

+  

+ diff --git a/test/daxctl-create.sh b/test/daxctl-create.sh

+ index 198779a..d319a39 100755

+ --- a/test/daxctl-create.sh

+ +++ b/test/daxctl-create.sh

+ @@ -10,7 +10,7 @@ trap 'cleanup $LINENO' ERR

+  cleanup()

+  {

+  	printf "Error at line %d\n" "$1"

+ -	[[ $testdev ]] && reset

+ +	[[ $testdev ]] && reset_dax

+  	exit $rc

+  }

+  

+ @@ -70,7 +70,7 @@ reset_dev()

+  	"$DAXCTL" enable-device "$testdev"

+  }

+  

+ -reset()

+ +reset_dax()

+  {

+  	test -n "$testdev"

+  

+ diff --git a/test/daxdev-errors.sh b/test/daxdev-errors.sh

+ index 9547d78..e13453d 100755

+ --- a/test/daxdev-errors.sh

+ +++ b/test/daxdev-errors.sh

+ @@ -15,9 +15,7 @@ trap 'err $LINENO' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  rc=1

+  

+ diff --git a/test/firmware-update.sh b/test/firmware-update.sh

+ index 8cc9c41..93ce166 100755

+ --- a/test/firmware-update.sh

+ +++ b/test/firmware-update.sh

+ @@ -10,11 +10,9 @@ image="update-fw.img"

+  

+  trap 'err $LINENO' ERR

+  

+ -reset()

+ +fwupd_reset()

+  {

+ -	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +	reset

+  	if [ -f $image ]; then

+  		rm -f $image

+  	fi

+ @@ -73,7 +71,7 @@ do_tests()

+  check_min_kver "4.16" || do_skip "may lack firmware update test handling"

+  

+  modprobe nfit_test

+ -reset

+ +fwupd_reset

+  detect

+  rc=1

+  do_tests

+ diff --git a/test/inject-error.sh b/test/inject-error.sh

+ index 7d0b826..fd823b6 100755

+ --- a/test/inject-error.sh

+ +++ b/test/inject-error.sh

+ @@ -37,13 +37,6 @@ create()

+  	[ $size -gt 0 ] || err "$LINENO"

+  }

+  

+ -reset()

+ -{

+ -	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ -}

+ -

+  check_status()

+  {

+  	local sector="$1"

+ diff --git a/test/max_available_extent_ns.sh b/test/max_available_extent_ns.sh

+ index 343f3c9..47a921f 100755

+ --- a/test/max_available_extent_ns.sh

+ +++ b/test/max_available_extent_ns.sh

+ @@ -11,13 +11,6 @@ trap 'err $LINENO' ERR

+  check_min_kver "4.19" || do_skip "kernel $KVER may not support max_available_size"

+  check_prereq "jq"

+  

+ -init()

+ -{

+ -	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ -}

+ -

+  do_test()

+  {

+  	region=$($NDCTL list -b $NFIT_TEST_BUS0 -R -t pmem | jq -r 'sort_by(-.size) | .[].dev' | head -1)

+ @@ -40,7 +33,7 @@ do_test()

+  

+  modprobe nfit_test

+  rc=1

+ -init

+ +reset

+  do_test

+  _cleanup

+  exit 0

+ diff --git a/test/monitor.sh b/test/monitor.sh

+ index c015c11..6aa4196 100755

+ --- a/test/monitor.sh

+ +++ b/test/monitor.sh

+ @@ -19,13 +19,6 @@ trap 'err $LINENO' ERR

+  

+  check_min_kver "4.15" || do_skip "kernel $KVER may not support monitor service"

+  

+ -init()

+ -{

+ -	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ -}

+ -

+  start_monitor()

+  {

+  	logfile=$(mktemp)

+ @@ -112,7 +105,7 @@ test_filter_region()

+  

+  test_filter_namespace()

+  {

+ -	init

+ +	reset

+  	monitor_namespace=$($NDCTL create-namespace -b $smart_supported_bus | jq -r .dev)

+  	monitor_dimms=$(get_monitor_dimm "-n $monitor_namespace")

+  	start_monitor "-n $monitor_namespace"

+ @@ -170,7 +163,7 @@ do_tests()

+  

+  modprobe nfit_test

+  rc=1

+ -init

+ +reset

+  set_smart_supported_bus

+  do_tests

+  _cleanup

+ diff --git a/test/multi-dax.sh b/test/multi-dax.sh

+ index b343a38..04070ad 100755

+ --- a/test/multi-dax.sh

+ +++ b/test/multi-dax.sh

+ @@ -17,9 +17,7 @@ ALIGN_SIZE=`getconf PAGESIZE`

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  rc=1

+  

+  query=". | sort_by(.available_size) | reverse | .[0].dev"

+ diff --git a/test/pfn-meta-errors.sh b/test/pfn-meta-errors.sh

+ index 0ade2e5..6314897 100755

+ --- a/test/pfn-meta-errors.sh

+ +++ b/test/pfn-meta-errors.sh

+ @@ -29,9 +29,7 @@ trap 'err $LINENO' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  rc=1

+  

+ diff --git a/test/pmem-errors.sh b/test/pmem-errors.sh

+ index 4225c3b..2065780 100755

+ --- a/test/pmem-errors.sh

+ +++ b/test/pmem-errors.sh

+ @@ -28,9 +28,7 @@ trap 'err $LINENO cleanup' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  rc=1

+  

+ diff --git a/test/rescan-partitions.sh b/test/rescan-partitions.sh

+ index 1686de3..51bbd73 100755

+ --- a/test/rescan-partitions.sh

+ +++ b/test/rescan-partitions.sh

+ @@ -25,13 +25,6 @@ check_min_kver "4.16" || do_skip "may not contain fixes for partition rescanning

+  check_prereq "parted"

+  check_prereq "blockdev"

+  

+ -reset()

+ -{

+ -	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ -}

+ -

+  test_mode()

+  {

+  	local mode="$1"

+ diff --git a/test/sector-mode.sh b/test/sector-mode.sh

+ index 7a2faea..439ef33 100755

+ --- a/test/sector-mode.sh

+ +++ b/test/sector-mode.sh

+ @@ -15,13 +15,8 @@ ALIGN_SIZE=`getconf PAGESIZE`

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ -

+ -$NDCTL disable-region -b $NFIT_TEST_BUS1 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS1 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS1 all

+ +reset

+ +reset1

+  

+  rc=1

+  query=". | sort_by(.size) | reverse | .[0].dev"

+ diff --git a/test/track-uuid.sh b/test/track-uuid.sh

+ index be3cf9c..3bacd2c 100755

+ --- a/test/track-uuid.sh

+ +++ b/test/track-uuid.sh

+ @@ -12,9 +12,7 @@ trap 'err $LINENO' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ -$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +reset

+  

+  rc=1

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,104 @@ 

+ From fe37c85f1ffb0b2d04ef60e8ece6a9a44a145cc5 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:00 -0800

+ Subject: [PATCH 072/217] ndctl/test: Initialize the label area by default

+ 

+ The removal of BLK-mode support causes nfit_test regions to not be

+ 'aliased' by default, which means that the only way to enable labels is to

+ initialize the namespace label index block. In support of that the common

+ 'reset()' helper is updated to initialize v1.1 labels instead of zero them.

+ Additionally, it highlighted that some btt tests have silent assumptions of

+ v1.1 vs v1.2 label support. Add a 'resetV()' alternative to the common

+ 'reset()' function that initializes the label area to v1.2.

+ 

+ Link: https://lore.kernel.org/r/164141832017.3990253.10383328274835531066.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/btt-errors.sh     |  4 ++--

+  test/btt-pad-compat.sh |  2 +-

+  test/common            | 11 +++++++++--

+  test/label-compat.sh   |  2 +-

+  4 files changed, 13 insertions(+), 6 deletions(-)

+ 

+ diff --git a/test/btt-errors.sh b/test/btt-errors.sh

+ index 5a20d26..6e69178 100755

+ --- a/test/btt-errors.sh

+ +++ b/test/btt-errors.sh

+ @@ -45,7 +45,7 @@ trap 'err $LINENO cleanup' ERR

+  

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+ -reset

+ +resetV

+  

+  rc=1

+  

+ @@ -124,7 +124,7 @@ dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1

+  

+  # reset everything to get a clean log

+  if grep -q "$MNT" /proc/mounts; then umount $MNT; fi

+ -reset

+ +resetV

+  dev="x"

+  json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector)

+  eval "$(echo "$json" | json2var)"

+ diff --git a/test/btt-pad-compat.sh b/test/btt-pad-compat.sh

+ index be538b7..005316a 100755

+ --- a/test/btt-pad-compat.sh

+ +++ b/test/btt-pad-compat.sh

+ @@ -148,7 +148,7 @@ do_tests()

+  	verify_idx 0 1

+  

+  	# do the same with an old format namespace

+ -	reset

+ +	resetV

+  	create_oldfmt_ns

+  	verify_idx 0 2

+  

+ diff --git a/test/common b/test/common

+ index 3c54d63..b6d4712 100644

+ --- a/test/common

+ +++ b/test/common

+ @@ -49,14 +49,21 @@ err()

+  reset()

+  {

+  	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ +	$NDCTL init-labels -f -b $NFIT_TEST_BUS0 all

+ +	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+ +}

+ +

+ +resetV()

+ +{

+ +	$NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ +	$NDCTL init-labels -f -V 1.2 -b $NFIT_TEST_BUS0 all

+  	$NDCTL enable-region -b $NFIT_TEST_BUS0 all

+  }

+  

+  reset1()

+  {

+  	$NDCTL disable-region -b $NFIT_TEST_BUS1 all

+ -	$NDCTL zero-labels -b $NFIT_TEST_BUS1 all

+ +	$NDCTL init-labels -f -b $NFIT_TEST_BUS1 all

+  	$NDCTL enable-region -b $NFIT_TEST_BUS1 all

+  }

+  

+ diff --git a/test/label-compat.sh b/test/label-compat.sh

+ index 8ab2858..7ae4d5e 100755

+ --- a/test/label-compat.sh

+ +++ b/test/label-compat.sh

+ @@ -17,7 +17,7 @@ trap 'err $LINENO' ERR

+  # setup (reset nfit_test dimms)

+  modprobe nfit_test

+  $NDCTL disable-region -b $NFIT_TEST_BUS0 all

+ -$NDCTL zero-labels -b $NFIT_TEST_BUS0 all

+ +$NDCTL init-labels -f -b $NFIT_TEST_BUS0 all

+  

+  # grab the largest pmem region on -b $NFIT_TEST_BUS0

+  query=". | sort_by(.available_size) | reverse | .[0].dev"

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,43 @@ 

+ From 756a6598a0fa6cebdd0e98564af089ca6b463fb1 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:05 -0800

+ Subject: [PATCH 073/217] ndctl/test: Skip BLK flags checks

+ 

+ With the removal of BLK-mode support, test/libndctl will fail to detect the

+ JEDEC format on the nfit_test bus. Report + skip that check rather than

+ fail the test when that happens.

+ 

+ Link: https://lore.kernel.org/r/164141832529.3990253.16538298357542644310.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/libndctl.c | 4 ++--

+  1 file changed, 2 insertions(+), 2 deletions(-)

+ 

+ diff --git a/test/libndctl.c b/test/libndctl.c

+ index c0e4b4c..1e97926 100644

+ --- a/test/libndctl.c

+ +++ b/test/libndctl.c

+ @@ -2535,7 +2535,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,

+  				fprintf(stderr, "dimm%d expected formats: %d got: %d\n",

+  						i, dimms[i].formats,

+  						ndctl_dimm_get_formats(dimm));

+ -				return -ENXIO;

+ +				fprintf(stderr, "continuing...\n");

+  			}

+  			for (j = 0; j < dimms[i].formats; j++) {

+  				if (ndctl_dimm_get_formatN(dimm, j) != dimms[i].format[j]) {

+ @@ -2543,7 +2543,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,

+  						"dimm%d expected format[%d]: %d got: %d\n",

+  							i, j, dimms[i].format[j],

+  							ndctl_dimm_get_formatN(dimm, j));

+ -					return -ENXIO;

+ +					fprintf(stderr, "continuing...\n");

+  				}

+  			}

+  		}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,41 @@ 

+ From b787320498508192f1e04ac38d39da4eb3ca26e9 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:10 -0800

+ Subject: [PATCH 074/217] ndctl/test: Move sector-mode to a different region

+ 

+ Previously the largest region on the nfit_test.1 bus belonged to a BLK-mode

+ region. With the removal of BLK-mode support update the test to instead

+ find a suitable PMEM region to perform the checkout.

+ 

+ Link: https://lore.kernel.org/r/164141833068.3990253.15694496866707006837.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/sector-mode.sh | 8 ++++----

+  1 file changed, 4 insertions(+), 4 deletions(-)

+ 

+ diff --git a/test/sector-mode.sh b/test/sector-mode.sh

+ index 439ef33..f70b0f1 100755

+ --- a/test/sector-mode.sh

+ +++ b/test/sector-mode.sh

+ @@ -19,11 +19,11 @@ reset

+  reset1

+  

+  rc=1

+ -query=". | sort_by(.size) | reverse | .[0].dev"

+ -NAMESPACE=$($NDCTL list -b $NFIT_TEST_BUS1 -N | jq -r "$query")

+ -REGION=$($NDCTL list -R --namespace=$NAMESPACE | jq -r "(.[]) | .dev")

+ +query=". | sort_by(.available_size) | reverse | .[0].dev"

+ +REGION=$($NDCTL list -R -b $NFIT_TEST_BUS1 | jq -r "$query")

+  echo 0 > /sys/bus/nd/devices/$REGION/read_only

+ -$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K

+ +echo $ALIGN_SIZE > /sys/bus/nd/devices/$REGION/align

+ +NAMESPACE=$($NDCTL create-namespace --no-autolabel -r $REGION -m sector -f -l 4K | jq -r ".dev")

+  $NDCTL create-namespace --no-autolabel -e $NAMESPACE -m dax -f -a $ALIGN_SIZE

+  $NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K

+  

+ -- 

+ 2.27.0

+ 

The added file is too large to be shown here, see it at: SOURCES/0075-ndctl-Deprecate-BLK-aperture-support.patch
@@ -0,0 +1,78 @@ 

+ From 9bfb567715d1b45e6598e6b38bef531312c72db3 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:21 -0800

+ Subject: [PATCH 076/217] ndctl/test: Fix support for missing dax_pmem_compat

+  module

+ 

+ The kernel is moving to drop CONFIG_DEV_DAX_PMEM_COMPAT. Update

+ ndctl_test_init() to not error out if dax_pmem_compat is missing. It seems

+ that the original implementation of support for missing dax_pmem_compat was

+ broken, or since that time newer versions of kmod_module_new_from_name() no

+ longer fail when the module is missing.

+ 

+ Link: https://lore.kernel.org/r/164141834155.3990253.5388773351209410262.stgit@dwillia2-desk3.amr.corp.intel.com

+ Fixes: b7991dbc22f3 ("ndctl/test: Relax dax_pmem_compat requirement")

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/core.c | 25 +++++++++++--------------

+  1 file changed, 11 insertions(+), 14 deletions(-)

+ 

+ diff --git a/test/core.c b/test/core.c

+ index dc1405d..5d1aa23 100644

+ --- a/test/core.c

+ +++ b/test/core.c

+ @@ -120,7 +120,6 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,

+  		"nfit",

+  		"device_dax",

+  		"dax_pmem",

+ -		"dax_pmem_core",

+  		"dax_pmem_compat",

+  		"libnvdimm",

+  		"nd_btt",

+ @@ -180,29 +179,27 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,

+  		/*

+  		 * Skip device-dax bus-model modules on pre-v5.1

+  		 */

+ -		if ((strcmp(name, "dax_pmem_core") == 0

+ -				|| strcmp(name, "dax_pmem_compat") == 0)

+ -				&& !ndctl_test_attempt(test,

+ -					KERNEL_VERSION(5, 1, 0)))

+ +		if ((strcmp(name, "dax_pmem_compat") == 0) &&

+ +		    !ndctl_test_attempt(test, KERNEL_VERSION(5, 1, 0)))

+  			continue;

+  

+  retry:

+  		rc = kmod_module_new_from_name(*ctx, name, mod);

+ -

+ -		/*

+ -		 * dax_pmem_compat is not required, missing is ok,

+ -		 * present-but-production is not ok.

+ -		 */

+ -		if (rc && strcmp(name, "dax_pmem_compat") == 0)

+ -			continue;

+ -

+  		if (rc) {

+ -			log_err(&log_ctx, "%s.ko: missing\n", name);

+ +			log_err(&log_ctx, "failed to interrogate %s.ko\n",

+ +				name);

+  			break;

+  		}

+  

+  		path = kmod_module_get_path(*mod);

+  		if (!path) {

+ +			/*

+ +			 * dax_pmem_compat is not required, missing is

+ +			 * ok, present-but-production is not ok.

+ +			 */

+ +			if (strcmp(name, "dax_pmem_compat") == 0)

+ +				continue;

+ +

+  			if (family != NVDIMM_FAMILY_INTEL &&

+  			    (strcmp(name, "nfit") == 0 ||

+  			     strcmp(name, "nd_e820") == 0))

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,104 @@ 

+ From d1b966de2b32f6152bc3b9c3f5d842ba12407a87 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:32 -0800

+ Subject: [PATCH 078/217] Documentation: Drop attrs.adoc include

+ 

+ In preparation for switching build systems, drop the attrs.adoc include for

+ communicating variables to asciidoc. Simply add the necessary variable

+ values to the invocation of the command using the --attribute argument.

+ 

+ Link: https://lore.kernel.org/r/164141835217.3990253.17678912974035740752.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .gitignore                                      |  1 -

+  Documentation/daxctl/Makefile.am                | 17 +++++++----------

+  .../daxctl/daxctl-reconfigure-device.txt        |  2 --

+  Documentation/ndctl/Makefile.am                 | 17 +++++++----------

+  Documentation/ndctl/intel-nvdimm-security.txt   |  2 --

+  Documentation/ndctl/ndctl-load-keys.txt         |  2 --

+  Documentation/ndctl/ndctl-monitor.txt           |  2 --

+  Documentation/ndctl/ndctl-sanitize-dimm.txt     |  2 --

+  Documentation/ndctl/ndctl-setup-passphrase.txt  |  2 --

+  Documentation/ndctl/ndctl-update-passphrase.txt |  2 --

+  10 files changed, 14 insertions(+), 35 deletions(-)

+ 

+ diff -up ndctl-71.1/.gitignore.orig ndctl-71.1/.gitignore

+ --- ndctl-71.1/.gitignore.orig	2022-10-07 15:58:15.663005697 -0400

+ +++ ndctl-71.1/.gitignore	2022-10-07 15:58:57.238147247 -0400

+ @@ -23,7 +23,6 @@ Documentation/daxctl/asciidoctor-extensi

+  Documentation/ndctl/asciidoctor-extensions.rb

+  Documentation/cxl/asciidoctor-extensions.rb

+  Documentation/cxl/lib/asciidoctor-extensions.rb

+ -Documentation/ndctl/attrs.adoc

+  .dirstamp

+  daxctl/config.h

+  daxctl/daxctl

+ diff -up ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt.orig ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt

+ --- ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt	2022-10-07 15:59:06.192177733 -0400

+ @@ -1,7 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+  

+ -include::attrs.adoc[]

+ -

+  THEORY OF OPERATION

+  -------------------

+  The Intel Device Specific Methods (DSM) specification v1.7 and v1.8 [1]

+ diff -up ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt

+ --- ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt	2022-10-07 15:59:06.192177733 -0400

+ @@ -1,7 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+  

+ -include::attrs.adoc[]

+ -

+  ndctl-load-keys(1)

+  ==================

+  

+ diff -up ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt

+ --- ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt	2022-10-07 15:59:06.192177733 -0400

+ @@ -1,7 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+  

+ -include::attrs.adoc[]

+ -

+  ndctl-monitor(1)

+  ================

+  

+ diff -up ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt

+ --- ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt	2022-10-07 15:59:06.192177733 -0400

+ @@ -1,7 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+  

+ -include::attrs.adoc[]

+ -

+  ndctl-sanitize-dimm(1)

+  ======================

+  

+ diff -up ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt

+ --- ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt	2022-10-07 15:59:06.193177737 -0400

+ @@ -1,7 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+  

+ -include::attrs.adoc[]

+ -

+  ndctl-setup-passphrase(1)

+  =========================

+  

+ diff -up ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt

+ --- ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt	2022-10-07 15:59:06.193177737 -0400

+ @@ -1,7 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+  

+ -include::attrs.adoc[]

+ -

+  ndctl-update-passphrase(1)

+  ==========================

+  

@@ -0,0 +1,53 @@ 

+ From 3297995248081d31d282fc9a339894989ff94e23 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:37 -0800

+ Subject: [PATCH 079/217] build: Drop unnecessary $tool/config.h includes

+ 

+ In preparation for support for meson as the build infrastructure remove

+ some explicit config.h includes that will be replaced by a unified config.h

+ at the top of the project.

+ 

+ Link: https://lore.kernel.org/r/164141835727.3990253.12971738434561351928.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  daxctl/migrate.c | 1 -

+  ndctl/keys.c     | 1 -

+  ndctl/monitor.c  | 1 -

+  3 files changed, 3 deletions(-)

+ 

+ diff -up ndctl-71.1/daxctl/migrate.c.orig ndctl-71.1/daxctl/migrate.c

+ --- ndctl-71.1/daxctl/migrate.c.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/daxctl/migrate.c	2022-10-07 16:01:20.316634385 -0400

+ @@ -5,7 +5,6 @@

+  #include <stdio.h>

+  #include <errno.h>

+  #include <fcntl.h>

+ -#include <daxctl/config.h>

+  #include <daxctl/libdaxctl.h>

+  #include <util/parse-options.h>

+  #include <ccan/array_size/array_size.h>

+ diff -up ndctl-71.1/ndctl/keys.c.orig ndctl-71.1/ndctl/keys.c

+ --- ndctl-71.1/ndctl/keys.c.orig	2022-10-07 16:01:03.161575978 -0400

+ +++ ndctl-71.1/ndctl/keys.c	2022-10-07 16:01:20.317634389 -0400

+ @@ -13,7 +13,6 @@

+  #include <keyutils.h>

+  #include <syslog.h>

+  

+ -#include <ndctl/config.h>

+  #include <ndctl/ndctl.h>

+  #include <ndctl/libndctl.h>

+  

+ diff -up ndctl-71.1/ndctl/monitor.c.orig ndctl-71.1/ndctl/monitor.c

+ --- ndctl-71.1/ndctl/monitor.c.orig	2022-10-07 16:01:03.164575988 -0400

+ +++ ndctl-71.1/ndctl/monitor.c	2022-10-07 16:01:20.318634392 -0400

+ @@ -10,7 +10,6 @@

+  #include <util/util.h>

+  #include <util/parse-options.h>

+  #include <util/strbuf.h>

+ -#include <ndctl/config.h>

+  #include <ndctl/ndctl.h>

+  #include <ndctl/libndctl.h>

+  #include <sys/epoll.h>

@@ -0,0 +1,355 @@ 

+ From d12d5f82755db50277e50c8daa97be15107f924d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:42 -0800

+ Subject: [PATCH 080/217] test: Prepare out of line builds

+ 

+ In preparation for converting to meson prepare the unit tests to run out of

+ a build directory rather than out of the source directory. Introduce

+ TEST_PATH for the location of the test executables.

+ 

+ Link: https://lore.kernel.org/r/164141836235.3990253.5237538466465550643.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/btt-errors.sh     |  4 +---

+  test/common            | 37 +++++++++++++++++++++----------------

+  test/dax-pmd.c         | 11 +++++++++--

+  test/dax.sh            |  6 +++---

+  test/daxdev-errors.sh  |  4 ++--

+  test/device-dax-fio.sh |  2 +-

+  test/dm.sh             |  4 ++--

+  test/inject-smart.sh   |  2 +-

+  test/mmap.sh           |  6 +++---

+  test/monitor.sh        |  6 +++---

+  test/pmem-errors.sh    |  8 +++-----

+  test/sub-section.sh    |  4 ++--

+  test/track-uuid.sh     |  2 +-

+  13 files changed, 52 insertions(+), 44 deletions(-)

+ 

+ diff --git a/test/btt-errors.sh b/test/btt-errors.sh

+ index 6e69178..18518d5 100755

+ --- a/test/btt-errors.sh

+ +++ b/test/btt-errors.sh

+ @@ -11,14 +11,12 @@ rc=77

+  

+  cleanup()

+  {

+ -	rm -f $FILE

+ -	rm -f $MNT/$FILE

+  	if grep -q "$MNT" /proc/mounts; then

+  		umount $MNT

+  	else

+  		rc=77

+  	fi

+ -	rmdir $MNT

+ +	rm -rf $MNT

+  }

+  

+  force_raw()

+ diff --git a/test/common b/test/common

+ index b6d4712..fb48795 100644

+ --- a/test/common

+ +++ b/test/common

+ @@ -4,27 +4,32 @@

+  # Global variables

+  

+  # NDCTL

+ -#

+ -if [ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ]; then

+ -	export NDCTL=../ndctl/ndctl

+ -elif [ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ]; then

+ -	export NDCTL=./ndctl/ndctl

+ -else

+ -	echo "Couldn't find an ndctl binary"

+ -	exit 1

+ +if [ -z $NDCTL ]; then

+ +	if [ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ]; then

+ +		export NDCTL=../ndctl/ndctl

+ +	elif [ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ]; then

+ +		export NDCTL=./ndctl/ndctl

+ +	else

+ +		echo "Couldn't find an ndctl binary"

+ +		exit 1

+ +	fi

+  fi

+  

+  # DAXCTL

+ -#

+ -if [ -f "../daxctl/daxctl" ] && [ -x "../daxctl/daxctl" ]; then

+ -	export DAXCTL=../daxctl/daxctl

+ -elif [ -f "./daxctl/daxctl" ] && [ -x "./daxctl/daxctl" ]; then

+ -	export DAXCTL=./daxctl/daxctl

+ -else

+ -	echo "Couldn't find an daxctl binary"

+ -	exit 1

+ +if [ -z $DAXCTL ]; then

+ +	if [ -f "../daxctl/daxctl" ] && [ -x "../daxctl/daxctl" ]; then

+ +		export DAXCTL=../daxctl/daxctl

+ +	elif [ -f "./daxctl/daxctl" ] && [ -x "./daxctl/daxctl" ]; then

+ +		export DAXCTL=./daxctl/daxctl

+ +	else

+ +		echo "Couldn't find an daxctl binary"

+ +		exit 1

+ +	fi

+  fi

+  

+ +if [ -z $TEST_PATH ]; then

+ +	export TEST_PATH=.

+ +fi

+  

+  # NFIT_TEST_BUS[01]

+  #

+ diff --git a/test/dax-pmd.c b/test/dax-pmd.c

+ index 7648e34..f840875 100644

+ --- a/test/dax-pmd.c

+ +++ b/test/dax-pmd.c

+ @@ -24,7 +24,8 @@

+  	__func__, __LINE__, strerror(errno))

+  #define faili(i) fprintf(stderr, "%s: failed at: %d: %d (%s)\n", \

+  	__func__, __LINE__, i, strerror(errno))

+ -#define TEST_FILE "test_dax_data"

+ +#define TEST_DIR "test_dax_mnt"

+ +#define TEST_FILE TEST_DIR "/test_dax_data"

+  

+  #define REGION_MEM_SIZE 4096*4

+  #define REGION_PM_SIZE        4096*512

+ @@ -171,8 +172,14 @@ int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t off

+  		}

+  		rc = -ENXIO;

+  

+ +		rc = mkdir(TEST_DIR, 0600);

+ +		if (rc < 0 && errno != EEXIST) {

+ +			faili(i);

+ +			munmap(addr, 2 * align);

+ +			break;

+ +		}

+  		fd2 = open(TEST_FILE, O_CREAT|O_TRUNC|O_DIRECT|O_RDWR,

+ -				DEFFILEMODE);

+ +				0600);

+  		if (fd2 < 0) {

+  			faili(i);

+  			munmap(addr, 2*align);

+ diff --git a/test/dax.sh b/test/dax.sh

+ index bcdd4e9..bb9848b 100755

+ --- a/test/dax.sh

+ +++ b/test/dax.sh

+ @@ -15,13 +15,13 @@ cleanup() {

+  	else

+  		rc=77

+  	fi

+ -	rmdir $MNT

+ +	rm -rf $MNT

+  	exit $rc

+  }

+  

+  run_test() {

+  	rc=0

+ -	if ! trace-cmd record -e fs_dax:dax_pmd_fault_done ./dax-pmd $MNT/$FILE; then

+ +	if ! trace-cmd record -e fs_dax:dax_pmd_fault_done $TEST_PATH/dax-pmd $MNT/$FILE; then

+  		rc=$?

+  		if [ "$rc" -ne 77 ] && [ "$rc" -ne 0 ]; then

+  			cleanup "$1"

+ @@ -104,7 +104,7 @@ set -e

+  mkdir -p $MNT

+  trap 'err $LINENO cleanup' ERR

+  

+ -dev=$(./dax-dev)

+ +dev=$($TEST_PATH/dax-dev)

+  json=$($NDCTL list -N -n $dev)

+  eval $(json2var <<< "$json")

+  rc=1

+ diff --git a/test/daxdev-errors.sh b/test/daxdev-errors.sh

+ index e13453d..7f79718 100755

+ --- a/test/daxdev-errors.sh

+ +++ b/test/daxdev-errors.sh

+ @@ -62,8 +62,8 @@ read sector len < /sys/bus/nd/devices/$region/badblocks

+  echo "sector: $sector len: $len"

+  

+  # run the daxdev-errors test

+ -test -x ./daxdev-errors

+ -./daxdev-errors $busdev $region

+ +test -x $TEST_PATH/daxdev-errors

+ +$TEST_PATH/daxdev-errors $busdev $region

+  

+  # check badblocks, should be empty

+  if read sector len < /sys/bus/platform/devices/nfit_test.0/$busdev/$region/badblocks; then

+ diff --git a/test/device-dax-fio.sh b/test/device-dax-fio.sh

+ index f57a9d2..c43ac05 100755

+ --- a/test/device-dax-fio.sh

+ +++ b/test/device-dax-fio.sh

+ @@ -18,7 +18,7 @@ if ! fio --enghelp | grep -q "dev-dax"; then

+  	exit 77

+  fi

+  

+ -dev=$(./dax-dev)

+ +dev=$($TEST_PATH/dax-dev)

+  for align in 4k 2m 1g

+  do

+  	json=$($NDCTL create-namespace -m devdax -a $align -f -e $dev)

+ diff --git a/test/dm.sh b/test/dm.sh

+ index 4656e5b..b780a65 100755

+ --- a/test/dm.sh

+ +++ b/test/dm.sh

+ @@ -8,7 +8,7 @@ SKIP=77

+  FAIL=1

+  SUCCESS=0

+  

+ -. ./common

+ +. $(dirname $0)/common

+  

+  MNT=test_dax_mnt

+  TEST_DM_PMEM=/dev/mapper/test_pmem

+ @@ -30,7 +30,7 @@ cleanup() {

+  	if [ -L $TEST_DM_PMEM ]; then

+  		dmsetup remove $TEST_DM_PMEM

+  	fi

+ -	rmdir $MNT

+ +	rm -rf $MNT

+  	# opportunistic cleanup, not fatal if these fail

+  	namespaces=$($NDCTL list -N | jq -r ".[] | select(.name==\"$NAME\") | .dev")

+  	for i in $namespaces

+ diff --git a/test/inject-smart.sh b/test/inject-smart.sh

+ index 4ca83b8..8b91360 100755

+ --- a/test/inject-smart.sh

+ +++ b/test/inject-smart.sh

+ @@ -170,7 +170,7 @@ check_prereq "jq"

+  modprobe nfit_test

+  rc=1

+  

+ -jlist=$(./list-smart-dimm -b $bus)

+ +jlist=$($TEST_PATH/list-smart-dimm -b $bus)

+  dimm="$(jq '.[]."dev"?, ."dev"?' <<< $jlist | sort | head -1 | xargs)"

+  test -n "$dimm"

+  

+ diff --git a/test/mmap.sh b/test/mmap.sh

+ index 50a1d34..760257d 100755

+ --- a/test/mmap.sh

+ +++ b/test/mmap.sh

+ @@ -7,7 +7,7 @@

+  MNT=test_mmap_mnt

+  FILE=image

+  DEV=""

+ -TEST=./mmap

+ +TEST=$TEST_PATH/mmap

+  rc=77

+  

+  cleanup() {

+ @@ -17,7 +17,7 @@ cleanup() {

+  	else

+  		rc=77

+  	fi

+ -	rmdir $MNT

+ +	rm -rf $MNT

+  	exit $rc

+  }

+  

+ @@ -49,7 +49,7 @@ set -e

+  mkdir -p $MNT

+  trap 'err $LINENO cleanup' ERR

+  

+ -dev=$(./dax-dev)

+ +dev=$($TEST_PATH/dax-dev)

+  json=$($NDCTL list -N -n $dev)

+  eval $(json2var <<< "$json")

+  DEV="/dev/${blockdev}"

+ diff --git a/test/monitor.sh b/test/monitor.sh

+ index 6aa4196..e58c908 100755

+ --- a/test/monitor.sh

+ +++ b/test/monitor.sh

+ @@ -31,7 +31,7 @@ start_monitor()

+  set_smart_supported_bus()

+  {

+  	smart_supported_bus=$NFIT_TEST_BUS0

+ -	monitor_dimms=$(./list-smart-dimm -b $smart_supported_bus | jq -r .[0].dev)

+ +	monitor_dimms=$($TEST_PATH/list-smart-dimm -b $smart_supported_bus | jq -r .[0].dev)

+  	if [ -z $monitor_dimms ]; then

+  		smart_supported_bus=$NFIT_TEST_BUS1

+  	fi

+ @@ -39,14 +39,14 @@ set_smart_supported_bus()

+  

+  get_monitor_dimm()

+  {

+ -	jlist=$(./list-smart-dimm -b $smart_supported_bus $1)

+ +	jlist=$($TEST_PATH/list-smart-dimm -b $smart_supported_bus $1)

+  	monitor_dimms=$(jq '.[]."dev"?, ."dev"?' <<<$jlist | sort | uniq | xargs)

+  	echo $monitor_dimms

+  }

+  

+  call_notify()

+  {

+ -	./smart-notify $smart_supported_bus

+ +	$TEST_PATH/smart-notify $smart_supported_bus

+  	sync; sleep 3

+  }

+  

+ diff --git a/test/pmem-errors.sh b/test/pmem-errors.sh

+ index 2065780..9a59c25 100755

+ --- a/test/pmem-errors.sh

+ +++ b/test/pmem-errors.sh

+ @@ -10,14 +10,12 @@ rc=77

+  

+  cleanup()

+  {

+ -	rm -f $FILE

+ -	rm -f $MNT/$FILE

+  	if [ -n "$blockdev" ]; then

+  		umount /dev/$blockdev

+  	else

+  		rc=77

+  	fi

+ -	rmdir $MNT

+ +	rm -rf $MNT

+  }

+  

+  check_min_kver "4.7" || do_skip "may lack dax error handling"

+ @@ -82,8 +80,8 @@ echo $start_sect 8 > /sys/block/$blockdev/badblocks

+  dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1 && err $LINENO || true

+  

+  # run the dax-errors test

+ -test -x ./dax-errors

+ -./dax-errors $MNT/$FILE

+ +test -x $TEST_PATH/dax-errors

+ +$TEST_PATH/dax-errors $MNT/$FILE

+  

+  # TODO: disable this check till we have clear-on-write in the kernel

+  #if read sector len < /sys/block/$blockdev/badblocks; then

+ diff --git a/test/sub-section.sh b/test/sub-section.sh

+ index 92ae816..77b9633 100755

+ --- a/test/sub-section.sh

+ +++ b/test/sub-section.sh

+ @@ -8,7 +8,7 @@ SKIP=77

+  FAIL=1

+  SUCCESS=0

+  

+ -. ./common

+ +. $(dirname $0)/common

+  

+  check_min_kver "5.3" || do_skip "may lack align sub-section hotplug support"

+  

+ @@ -30,7 +30,7 @@ cleanup() {

+  	if mountpoint -q $MNT; then

+  		umount $MNT

+  	fi

+ -	rmdir $MNT

+ +	rm -rf $MNT

+  	# opportunistic cleanup, not fatal if these fail

+  	namespaces=$($NDCTL list -N | jq -r ".[] | select(.name==\"$NAME\") | .dev")

+  	for i in $namespaces

+ diff --git a/test/track-uuid.sh b/test/track-uuid.sh

+ index 3bacd2c..a967d0e 100755

+ --- a/test/track-uuid.sh

+ +++ b/test/track-uuid.sh

+ @@ -5,7 +5,7 @@

+  blockdev=""

+  rc=77

+  

+ -. ./common

+ +. $(dirname $0)/common

+  

+  set -e

+  trap 'err $LINENO' ERR

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,28 @@ 

+ From 7912cb0d19b5d17321439d118d41e57236b5484b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:47 -0800

+ Subject: [PATCH 081/217] ndctl: Drop executable bit for bash-completion script

+ 

+ The rpm build process warns:

+ 

+ *** WARNING: ./usr/share/bash-completion/completions/ndctl is executable but has no shebang, removing executable bit

+ 

+ Clear the unnecessary executable bit since completion helpers are sourced,

+ not executed.

+ 

+ Link: https://lore.kernel.org/r/164141836772.3990253.4996882214531720931.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  contrib/ndctl | 0

+  1 file changed, 0 insertions(+), 0 deletions(-)

+  mode change 100755 => 100644 contrib/ndctl

+ 

+ diff --git a/contrib/ndctl b/contrib/ndctl

+ old mode 100755

+ new mode 100644

+ -- 

+ 2.27.0

+ 

The added file is too large to be shown here, see it at: SOURCES/0082-build-Add-meson-build-infrastructure.patch
@@ -0,0 +1,223 @@ 

+ From 8b5b941093521dd18fcc99659b3e3b1b9e9456b7 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 5 Jan 2022 13:32:58 -0800

+ Subject: [PATCH 083/217] build: Add meson rpmbuild support

+ 

+ Beyond being a prerequisite for removing autotools support, this capability

+ served as validation that the meson conversion generated all the same files

+ as autotools and installed them to the same expected locations.

+ 

+ The procedure to use the rpmbuild.sh script is:

+ 

+     meson setup build

+     meson compile -C build rhel/ndctl.spec

+     ./rpmbuild.sh build/rhel/ndctl.spec

+ 

+ Link: https://lore.kernel.org/r/164141837841.3990253.11379060834465142446.stgit@dwillia2-desk3.amr.corp.intel.com

+ Tested-by: Alison Schofield <alison.schofield@intel.com>

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .gitignore       |  2 +-

+  Makefile.am      |  2 ++

+  meson.build      |  6 ++++++

+  ndctl.spec.in    | 23 +++++++++++++++++++++++

+  rhel/meson.build | 23 +++++++++++++++++++++++

+  rpmbuild.sh      |  5 ++++-

+  sles/meson.build | 36 ++++++++++++++++++++++++++++++++++++

+  7 files changed, 95 insertions(+), 2 deletions(-)

+  create mode 100644 rhel/meson.build

+  create mode 100644 sles/meson.build

+ 

+ diff -up ndctl-71.1/.gitignore.orig ndctl-71.1/.gitignore

+ --- ndctl-71.1/.gitignore.orig	2022-10-07 16:34:40.712445112 -0400

+ +++ ndctl-71.1/.gitignore	2022-10-07 16:34:52.832486377 -0400

+ @@ -35,7 +35,7 @@ daxctl/lib/libdaxctl.pc

+  ndctl/config.h

+  ndctl/lib/libndctl.pc

+  ndctl/ndctl

+ -rhel/

+ +rhel/ndctl.spec

+  sles/ndctl.spec

+  version.m4

+  *.swp

+ diff -up ndctl-71.1/Makefile.am.orig ndctl-71.1/Makefile.am

+ --- ndctl-71.1/Makefile.am.orig	2022-10-07 16:34:40.687445027 -0400

+ +++ ndctl-71.1/Makefile.am	2022-10-07 16:34:52.832486377 -0400

+ @@ -22,6 +22,7 @@ noinst_SCRIPTS = rhel/ndctl.spec sles/nd

+  CLEANFILES += $(noinst_SCRIPTS)

+  

+  do_rhel_subst = sed -e 's,VERSION,$(VERSION),g' \

+ +            -e 's,MESON,0,g' \

+              -e 's,DAX_DNAME,daxctl-devel,g' \

+              -e 's,CXL_DNAME,cxl-devel,g' \

+              -e 's,DNAME,ndctl-devel,g' \

+ @@ -31,6 +32,7 @@ do_rhel_subst = sed -e 's,VERSION,$(VERS

+  	    -e 's,LNAME,ndctl-libs,g'

+  

+  do_sles_subst = sed -e 's,VERSION,$(VERSION),g' \

+ +            -e 's,MESON,0,g' \

+              -e 's,DAX_DNAME,libdaxctl-devel,g' \

+              -e 's,CXL_DNAME,libcxl-devel,g' \

+              -e 's,DNAME,libndctl-devel,g' \

+ diff -up ndctl-71.1/meson.build.orig ndctl-71.1/meson.build

+ --- ndctl-71.1/meson.build.orig	2022-10-07 16:34:40.715445122 -0400

+ +++ ndctl-71.1/meson.build	2022-10-07 16:34:52.833486380 -0400

+ @@ -278,3 +278,9 @@ if get_option('docs').enabled()

+  endif

+  subdir('test')

+  subdir('contrib')

+ +

+ +# only support spec file generation from git builds

+ +if version_tag == ''

+ +  subdir('rhel')

+ +  subdir('sles')

+ +endif

+ diff -up ndctl-71.1/ndctl.spec.in.orig ndctl-71.1/ndctl.spec.in

+ --- ndctl-71.1/ndctl.spec.in.orig	2022-10-07 16:34:40.645444884 -0400

+ +++ ndctl-71.1/ndctl.spec.in	2022-10-07 16:34:52.833486380 -0400

+ @@ -6,14 +6,20 @@ License:	GPLv2

+  Url:		https://github.com/pmem/ndctl

+  Source0:	https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz

+  

+ +%define with_meson MESON

+  Requires:	LNAME%{?_isa} = %{version}-%{release}

+  Requires:	DAX_LNAME%{?_isa} = %{version}-%{release}

+  Requires:	CXL_LNAME%{?_isa} = %{version}-%{release}

+  BuildRequires:	autoconf

+  %if 0%{?rhel} < 9

+  BuildRequires:	asciidoc

+ +%if !%{with_meson}

+  %define asciidoc --disable-asciidoctor

+ +%endif

+  %else

+ +%if %{with_meson}

+ +%define asciidoctor -Dasciidoctor=enabled

+ +%endif

+  BuildRequires:	rubygem-asciidoctor

+  %endif

+  BuildRequires:	xmlto

+ @@ -28,6 +34,10 @@ BuildRequires:	pkgconfig(bash-completion

+  BuildRequires:	pkgconfig(systemd)

+  BuildRequires:	keyutils-libs-devel

+  

+ +%if %{with_meson}

+ +BuildRequires:	meson

+ +%endif

+ +

+  %description

+  Utility library for managing the "libnvdimm" subsystem.  The "libnvdimm"

+  subsystem defines a kernel device model and control message interface for

+ @@ -115,17 +125,30 @@ libcxl is a library for enumerating and

+  %setup -q ndctl-%{version}

+  

+  %build

+ +%if %{with_meson}

+ +%meson %{?asciidoctor} -Dversion-tag=%{version}

+ +%meson_build

+ +%else

+  echo %{version} > version

+  ./autogen.sh

+  %configure --disable-static --disable-silent-rules %{?asciidoc}

+  make %{?_smp_mflags}

+ +%endif

+  

+  %install

+ +%if %{with_meson}

+ +%meson_install

+ +%else

+  %make_install

+  find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'

+ +%endif

+  

+  %check

+ +%if %{with_meson}

+ +%meson_test

+ +%else

+  make check

+ +%endif

+  

+  %ldconfig_scriptlets -n LNAME

+  

+ diff -up ndctl-71.1/rhel/meson.build.orig ndctl-71.1/rhel/meson.build

+ --- ndctl-71.1/rhel/meson.build.orig	2022-10-07 16:34:52.834486384 -0400

+ +++ ndctl-71.1/rhel/meson.build	2022-10-07 16:34:52.834486384 -0400

+ @@ -0,0 +1,23 @@

+ +rhel_spec1 = vcs_tag(

+ +    input : '../ndctl.spec.in',

+ +    output : 'ndctl.spec.in',

+ +    command: vcs_tagger,

+ +    replace_string : 'VERSION',

+ +)

+ +

+ +rhel_spec2 = custom_target('ndctl.spec',

+ +  command : [

+ +    'sed', '-e', 's,MESON,1,g',

+ +	   '-e', 's,DAX_DNAME,daxctl-devel,g',

+ +	   '-e', 's,CXL_DNAME,cxl-devel,g',

+ +	   '-e', 's,DNAME,ndctl-devel,g',

+ +	   '-e', '/^%defattr.*/d',

+ +	   '-e', 's,DAX_LNAME,daxctl-libs,g',

+ +	   '-e', 's,CXL_LNAME,cxl-libs,g',

+ +	   '-e', 's,LNAME,ndctl-libs,g',

+ +	   '@INPUT@'

+ +  ],

+ +  input : rhel_spec1,

+ +  output : 'ndctl.spec',

+ +  capture : true,

+ +)

+ diff -up ndctl-71.1/rpmbuild.sh.orig ndctl-71.1/rpmbuild.sh

+ --- ndctl-71.1/rpmbuild.sh.orig	2020-12-22 16:44:57.000000000 -0500

+ +++ ndctl-71.1/rpmbuild.sh	2022-10-07 16:34:52.834486384 -0400

+ @@ -1,6 +1,9 @@

+  #!/bin/bash

+ +

+ +spec=${1:-$(dirname $0)/rhel/ndctl.spec)}

+ +

+  pushd $(dirname $0) >/dev/null

+  [ ! -d ~/rpmbuild/SOURCES ] && echo "rpmdev tree not found" && exit 1

+  ./make-git-snapshot.sh

+  popd > /dev/null

+ -rpmbuild -ba $(dirname $0)/rhel/ndctl.spec

+ +rpmbuild --nocheck -ba $spec

+ diff -up ndctl-71.1/sles/meson.build.orig ndctl-71.1/sles/meson.build

+ --- ndctl-71.1/sles/meson.build.orig	2022-10-07 16:34:52.836486391 -0400

+ +++ ndctl-71.1/sles/meson.build	2022-10-07 16:34:52.835486387 -0400

+ @@ -0,0 +1,36 @@

+ +sles_spec1 = vcs_tag(

+ +    input : '../ndctl.spec.in',

+ +    output : 'ndctl.spec.sles.in',

+ +    command: vcs_tagger,

+ +    replace_string : 'VERSION',

+ +)

+ +

+ +header = files('header')

+ +

+ +sles_spec2 = custom_target('ndctl.spec.in',

+ +  command : [

+ +    'cat', header, '@INPUT@',

+ +  ],

+ +  input : sles_spec1,

+ +  output : 'ndctl.spec.in',

+ +  capture : true,

+ +)

+ +

+ +sles_spec3 = custom_target('ndctl.spec',

+ +  command : [

+ +    'sed', '-e', 's,MESON,1,g',

+ +           '-e', 's,DAX_DNAME,libdaxctl-devel,g',

+ +           '-e', 's,CXL_DNAME,libcxl-devel,g',

+ +           '-e', 's,DNAME,libndctl-devel,g',

+ +           '-e', 's,%license,%doc,g',

+ +           '-e', 's,\(^License:.*GPL\)v2,\1-2.0,g',

+ +           '-e', 's,DAX_LNAME,libdaxctl@0@,g'.format(LIBDAXCTL_CURRENT - LIBDAXCTL_AGE),

+ +           '-e', 's,CXL_LNAME,libcxl@0@,g'.format(LIBCXL_CURRENT - LIBCXL_AGE),

+ +           '-e', 's,LNAME,libndctl@0@,g'.format(LIBNDCTL_CURRENT - LIBNDCTL_AGE),

+ +	   '@INPUT@'

+ +  ],

+ +

+ +  input : sles_spec2,

+ +  output : 'ndctl.spec',

+ +  capture : true,

+ +)

The added file is too large to be shown here, see it at: SOURCES/0084-ndctl-Jettison-autotools.patch
@@ -0,0 +1,32 @@ 

+ From 3a8d6e4bc90e899f751b881dc949e79daeeb04bb Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Fri, 7 Jan 2022 11:31:06 -0800

+ Subject: [PATCH 085/217] ndctl/build: Default asciidoctor to enabled

+ 

+ The autotools build infra previously defaulted asciidoctor to enabled, do

+ the same for Meson.

+ 

+ Link: https://lore.kernel.org/r/164158386600.302694.5479584050156277551.stgit@dwillia2-desk3.amr.corp.intel.com

+ Reported-by: Vishal Verma <vishal.l.verma@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  meson_options.txt | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/meson_options.txt b/meson_options.txt

+ index 95312bf..aa4a6dc 100644

+ --- a/meson_options.txt

+ +++ b/meson_options.txt

+ @@ -1,7 +1,7 @@

+  option('version-tag', type : 'string',

+         description : 'override the git version string')

+  option('docs', type : 'feature', value : 'enabled')

+ -option('asciidoctor', type : 'feature', value : 'disabled')

+ +option('asciidoctor', type : 'feature', value : 'enabled')

+  option('systemd', type : 'feature', value : 'enabled')

+  option('keyutils', type : 'feature', value : 'enabled',

+    description : 'enable nvdimm device passphrase management')

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,88 @@ 

+ From 351badda9e5b6454e56f31992e9325c4656680bd Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Fri, 14 Jan 2022 18:32:29 -0700

+ Subject: [PATCH 086/217] ndctl: update README.md for meson build

+ 

+ Update the README to replace the autotools build and test instructions

+ with meson equivalents. Also provide an example for setting meson

+ configuration options by illustrating the destructive unit tests use

+ case.

+ 

+ Link: https://lore.kernel.org/r/20220115013229.1604139-1-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reported-by: Alison Schofield <alison.schofield@intel.com>

+ Reported-by: Jane Chu <jane.chu@oracle.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  README.md | 33 ++++++++++++++++++++++-----------

+  1 file changed, 22 insertions(+), 11 deletions(-)

+ 

+ diff --git a/README.md b/README.md

+ index 6f36a6d..f3fe65b 100644

+ --- a/README.md

+ +++ b/README.md

+ @@ -9,11 +9,14 @@ Build

+  =====

+  

+  ```

+ -./autogen.sh

+ -./configure CFLAGS='-g -O2' --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib64

+ -make

+ -make check

+ -sudo make install

+ +meson setup build;

+ +meson compile -C build;

+ +```

+ +

+ +Optionally, to install:

+ +

+ +```

+ +meson install -C build

+  ```

+  

+  There are a number of packages required for the build steps that may not

+ @@ -34,7 +37,7 @@ https://nvdimm.wiki.kernel.org/start

+  

+  Unit Tests

+  ==========

+ -The unit tests run by `make check` require the nfit_test.ko module to be

+ +The unit tests run by `meson test` require the nfit_test.ko module to be

+  loaded.  To build and install nfit_test.ko:

+  

+  1. Obtain the kernel source.  For example,  

+ @@ -78,8 +81,16 @@ loaded.  To build and install nfit_test.ko:

+     sudo make modules_install

+     ```

+  

+ -1. Now run `make check` in the ndctl source directory, or `ndctl test`,

+ -   if ndctl was built with `--enable-test`.

+ +1. Now run `meson test -C build` in the ndctl source directory, or `ndctl test`,

+ +   if ndctl was built with `-Dtest=enabled` as a configuration option to meson.

+ +

+ +1. To run the 'destructive' set of tests that may clobber existing pmem

+ +   configurations and data, configure meson with the destructive option after the

+ +   `meson setup` step:

+ +

+ +   ```

+ +   meson configure -Dtest=enabled -Ddestructive=enabled build;

+ +   ```

+  

+  Troubleshooting

+  ===============

+ @@ -87,9 +98,9 @@ Troubleshooting

+  The unit tests will validate that the environment is set up correctly

+  before they try to run. If the platform is misconfigured, i.e. the unit

+  test modules are not available, or the test versions of the modules are

+ -superseded by the "in-tree/production" version of the modules `make

+ -check` will skip tests and report a message like the following in

+ -test/test-suite.log:  

+ +superseded by the "in-tree/production" version of the modules `meson

+ +test` will skip tests and report a message like the following in

+ +`build/meson-logs/testlog.txt`

+  

+  ```

+  SKIP: libndctl

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,122 @@ 

+ From a61377ecf015929de27a665d0b5c937315f9e4aa Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:51:54 -0800

+ Subject: [PATCH 087/217] test: Add 'suite' identifiers to tests

+ 

+ In preparation for adding CXL tests, and in anticipation of wanting to only

+ run the CXL tests, label each test with a suite id.

+ 

+ Link: https://lore.kernel.org/r/164298551461.3021641.4591877842309963514.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/meson.build | 73 ++++++++++++++++++++++++------------------------

+  1 file changed, 37 insertions(+), 36 deletions(-)

+ 

+ diff --git a/test/meson.build b/test/meson.build

+ index 94287aa..07a5bb6 100644

+ --- a/test/meson.build

+ +++ b/test/meson.build

+ @@ -152,28 +152,28 @@ pfn_meta_errors = find_program('pfn-meta-errors.sh')

+  track_uuid = find_program('track-uuid.sh')

+  

+  tests = [

+ -  [ 'libndctl',               libndctl ],

+ -  [ 'dsm-fail',               dsm_fail ],

+ -  [ 'create.sh',              create ],

+ -  [ 'clear.sh',               clear ],

+ -  [ 'pmem-errors.sh',         pmem_errors ],

+ -  [ 'daxdev-errors.sh',       daxdev_errors_sh ],

+ -  [ 'multi-dax.sh',           multi_dax ],

+ -  [ 'btt-check.sh',           btt_check ],

+ -  [ 'label-compat.sh',        label_compat ],

+ -  [ 'sector-mode.sh',         sector_mode ],

+ -  [ 'inject-error.sh',        inject_error ],

+ -  [ 'btt-errors.sh',          btt_errors ],

+ -  [ 'hugetlb',                hugetlb ],

+ -  [ 'btt-pad-compat.sh',      btt_pad_compat ],

+ -  [ 'firmware-update.sh',     firmware_update ],

+ -  [ 'ack-shutdown-count-set', ack_shutdown_count ],

+ -  [ 'rescan-partitions.sh',   rescan_partitions ],

+ -  [ 'inject-smart.sh',        inject_smart ],

+ -  [ 'monitor.sh',             monitor ],

+ -  [ 'max_extent_ns',          max_extent ],

+ -  [ 'pfn-meta-errors.sh',     pfn_meta_errors ],

+ -  [ 'track-uuid.sh',          track_uuid ],

+ +  [ 'libndctl',               libndctl,		  'ndctl' ],

+ +  [ 'dsm-fail',               dsm_fail,	      	  'ndctl' ],

+ +  [ 'create.sh',              create,	      	  'ndctl' ],

+ +  [ 'clear.sh',               clear,	      	  'ndctl' ],

+ +  [ 'pmem-errors.sh',         pmem_errors,    	  'ndctl' ],

+ +  [ 'daxdev-errors.sh',       daxdev_errors_sh,	  'dax'	  ],

+ +  [ 'multi-dax.sh',           multi_dax,	  'dax'   ],

+ +  [ 'btt-check.sh',           btt_check,	  'ndctl' ],

+ +  [ 'label-compat.sh',        label_compat,       'ndctl' ],

+ +  [ 'sector-mode.sh',         sector_mode,        'ndctl' ],

+ +  [ 'inject-error.sh',        inject_error,	  'ndctl' ],

+ +  [ 'btt-errors.sh',          btt_errors,	  'ndctl' ],

+ +  [ 'hugetlb',                hugetlb,		  'ndctl' ],

+ +  [ 'btt-pad-compat.sh',      btt_pad_compat,	  'ndctl' ],

+ +  [ 'firmware-update.sh',     firmware_update,	  'ndctl' ],

+ +  [ 'ack-shutdown-count-set', ack_shutdown_count, 'ndctl' ],

+ +  [ 'rescan-partitions.sh',   rescan_partitions,  'ndctl' ],

+ +  [ 'inject-smart.sh',        inject_smart,	  'ndctl' ],

+ +  [ 'monitor.sh',             monitor,		  'ndctl' ],

+ +  [ 'max_extent_ns',          max_extent,	  'ndctl' ],

+ +  [ 'pfn-meta-errors.sh',     pfn_meta_errors,	  'ndctl' ],

+ +  [ 'track-uuid.sh',          track_uuid,	  'ndctl' ],

+  ]

+  

+  if get_option('destructive').enabled()

+ @@ -188,26 +188,26 @@ if get_option('destructive').enabled()

+    mmap_test = find_program('mmap.sh')

+  

+    tests += [

+ -    [ 'pmem-ns',           pmem_ns ],

+ -    [ 'sub-section.sh',    sub_section ],

+ -    [ 'dax-dev',           dax_dev ],

+ -    [ 'dax-ext4.sh',       dax_ext4 ],

+ -    [ 'dax-xfs.sh',        dax_xfs ],

+ -    [ 'align.sh',          align ],

+ -    [ 'device-dax',        device_dax ],

+ -    [ 'revoke-devmem',     revoke_devmem ],

+ -    [ 'device-dax-fio.sh', device_dax_fio ],

+ -    [ 'daxctl-devices.sh', daxctl_devices ],

+ -    [ 'daxctl-create.sh',  daxctl_create ],

+ -    [ 'dm.sh',             dm ],

+ -    [ 'mmap.sh',           mmap_test ],

+ +    [ 'pmem-ns',           pmem_ns,	   'ndctl' ],

+ +    [ 'sub-section.sh',    sub_section,	   'dax'   ],

+ +    [ 'dax-dev',           dax_dev,	   'dax'   ],

+ +    [ 'dax-ext4.sh',       dax_ext4,	   'dax'   ],

+ +    [ 'dax-xfs.sh',        dax_xfs,	   'dax'   ],

+ +    [ 'align.sh',          align,	   'ndctl' ],

+ +    [ 'device-dax',        device_dax,	   'dax'   ],

+ +    [ 'revoke-devmem',     revoke_devmem,  'dax'   ],

+ +    [ 'device-dax-fio.sh', device_dax_fio, 'dax'   ],

+ +    [ 'daxctl-devices.sh', daxctl_devices, 'dax'   ],

+ +    [ 'daxctl-create.sh',  daxctl_create,  'dax'   ],

+ +    [ 'dm.sh',             dm,		   'dax'   ],

+ +    [ 'mmap.sh',           mmap_test,	   'dax'   ],

+    ]

+  endif

+  

+  if get_option('keyutils').enabled()

+    security = find_program('security.sh')

+    tests += [

+ -    [ 'security.sh', security ]

+ +    [ 'security.sh', security, 'ndctl' ]

+    ]

+  endif

+  

+ @@ -226,6 +226,7 @@ foreach t : tests

+        dax_dev,

+        mmap,

+      ],

+ +    suite: t[2],

+      timeout : 0,

+      env : [

+        'NDCTL=@0@'.format(ndctl_tool.full_path()),

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,287 @@ 

+ From d7c5fa695a91d66485ca1febd6f29c3a483e20f6 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:00 -0800

+ Subject: [PATCH 088/217] ndctl: Rename util_filter to ndctl_filter

+ 

+ In preparation for introducing a cxl_filter_walk() implementation rename

+ the current filter_walk infrastructure with an ndctl_ prefix.

+ 

+ Link: https://lore.kernel.org/r/164298552014.3021641.16369576632179722489.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/filter.c         |  4 ++--

+  ndctl/filter.h         | 21 +++++++++++----------

+  ndctl/list.c           | 14 +++++++-------

+  ndctl/monitor.c        | 12 ++++++------

+  test/list-smart-dimm.c | 12 ++++++------

+  5 files changed, 32 insertions(+), 31 deletions(-)

+ 

+ diff -up ndctl-71.1/ndctl/filter.c.orig ndctl-71.1/ndctl/filter.c

+ --- ndctl-71.1/ndctl/filter.c.orig	2022-10-07 17:54:40.799788014 -0400

+ +++ ndctl-71.1/ndctl/filter.c	2022-10-07 17:54:52.592828166 -0400

+ @@ -338,8 +338,8 @@ const char *util_nsmode_name(enum ndctl_

+  	return modes[mode];

+  }

+  

+ -int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,

+ -		struct util_filter_params *param)

+ +int ndctl_filter_walk(struct ndctl_ctx *ctx, struct ndctl_filter_ctx *fctx,

+ +		      struct ndctl_filter_params *param)

+  {

+  	struct ndctl_bus *bus;

+  	unsigned int type = 0;

+ diff -up ndctl-71.1/ndctl/filter.h.orig ndctl-71.1/ndctl/filter.h

+ --- ndctl-71.1/ndctl/filter.h.orig	2022-10-07 17:54:40.799788014 -0400

+ +++ ndctl-71.1/ndctl/filter.h	2022-10-07 17:54:52.593828169 -0400

+ @@ -31,7 +31,7 @@ const char *util_nsmode_name(enum ndctl_

+  

+  struct json_object;

+  

+ -/* json object hierarchy for the util_filter_walk() performed by cmd_list() */

+ +/* json object hierarchy for the ndctl_filter_walk() performed by cmd_list() */

+  struct list_filter_arg {

+  	struct json_object *jnamespaces;

+  	struct json_object *jregions;

+ @@ -50,19 +50,20 @@ struct monitor_filter_arg {

+  };

+  

+  /*

+ - * struct util_filter_ctx - control and callbacks for util_filter_walk()

+ + * struct ndctl_filter_ctx - control and callbacks for ndctl_filter_walk()

+   * ->filter_bus() and ->filter_region() return bool because the

+   * child-object filter routines can not be called if the parent context

+   * is not established. ->filter_dimm() and ->filter_namespace() are leaf

+   * objects, so no child dependencies to check.

+   */

+ -struct util_filter_ctx {

+ -	bool (*filter_bus)(struct ndctl_bus *bus, struct util_filter_ctx *ctx);

+ -	void (*filter_dimm)(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx);

+ +struct ndctl_filter_ctx {

+ +	bool (*filter_bus)(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx);

+ +	void (*filter_dimm)(struct ndctl_dimm *dimm,

+ +			    struct ndctl_filter_ctx *ctx);

+  	bool (*filter_region)(struct ndctl_region *region,

+ -			struct util_filter_ctx *ctx);

+ +			      struct ndctl_filter_ctx *ctx);

+  	void (*filter_namespace)(struct ndctl_namespace *ndns,

+ -			struct util_filter_ctx *ctx);

+ +				 struct ndctl_filter_ctx *ctx);

+  	union {

+  		void *arg;

+  		struct list_filter_arg *list;

+ @@ -70,7 +71,7 @@ struct util_filter_ctx {

+  	};

+  };

+  

+ -struct util_filter_params {

+ +struct ndctl_filter_params {

+  	const char *bus;

+  	const char *region;

+  	const char *type;

+ @@ -81,6 +82,6 @@ struct util_filter_params {

+  };

+  

+  struct ndctl_ctx;

+ -int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,

+ -		struct util_filter_params *param);

+ +int ndctl_filter_walk(struct ndctl_ctx *ctx, struct ndctl_filter_ctx *fctx,

+ +		      struct ndctl_filter_params *param);

+  #endif /* _NDCTL_UTIL_FILTER_H_ */

+ diff -up ndctl-71.1/ndctl/list.c.orig ndctl-71.1/ndctl/list.c

+ --- ndctl-71.1/ndctl/list.c.orig	2022-10-07 17:54:40.806788038 -0400

+ +++ ndctl-71.1/ndctl/list.c	2022-10-07 17:54:52.593828169 -0400

+ @@ -55,7 +55,7 @@ static unsigned long listopts_to_flags(v

+  	return flags;

+  }

+  

+ -static struct util_filter_params param;

+ +static struct ndctl_filter_params param;

+  

+  static int did_fail;

+  

+ @@ -234,7 +234,7 @@ static struct json_object *region_to_jso

+  }

+  

+  static void filter_namespace(struct ndctl_namespace *ndns,

+ -		struct util_filter_ctx *ctx)

+ +			     struct ndctl_filter_ctx *ctx)

+  {

+  	struct json_object *jndns;

+  	struct list_filter_arg *lfa = ctx->list;

+ @@ -272,7 +272,7 @@ static void filter_namespace(struct ndct

+  }

+  

+  static bool filter_region(struct ndctl_region *region,

+ -		struct util_filter_ctx *ctx)

+ +			  struct ndctl_filter_ctx *ctx)

+  {

+  	struct list_filter_arg *lfa = ctx->list;

+  	struct json_object *jbus = lfa->jbus;

+ @@ -318,7 +318,7 @@ static bool filter_region(struct ndctl_r

+  	return true;

+  }

+  

+ -static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)

+ +static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *ctx)

+  {

+  	struct list_filter_arg *lfa = ctx->list;

+  	struct json_object *jdimm;

+ @@ -367,7 +367,7 @@ static void filter_dimm(struct ndctl_dim

+  	json_object_array_add(lfa->jdimms, jdimm);

+  }

+  

+ -static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx)

+ +static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx)

+  {

+  	struct list_filter_arg *lfa = ctx->list;

+  

+ @@ -489,7 +489,7 @@ int cmd_list(int argc, const char **argv

+  		NULL

+  	};

+  	bool lint = !!secure_getenv("NDCTL_LIST_LINT");

+ -	struct util_filter_ctx fctx = { 0 };

+ +	struct ndctl_filter_ctx fctx = { 0 };

+  	struct list_filter_arg lfa = { 0 };

+  	int i, rc;

+  

+ @@ -544,7 +544,7 @@ int cmd_list(int argc, const char **argv

+  	fctx.list = &lfa;

+  	lfa.flags = listopts_to_flags();

+  

+ -	rc = util_filter_walk(ctx, &fctx, &param);

+ +	rc = ndctl_filter_walk(ctx, &fctx, &param);

+  	if (rc)

+  		return rc;

+  

+ diff -up ndctl-71.1/ndctl/monitor.c.orig ndctl-71.1/ndctl/monitor.c

+ --- ndctl-71.1/ndctl/monitor.c.orig	2022-10-07 17:54:40.824788100 -0400

+ +++ ndctl-71.1/ndctl/monitor.c	2022-10-07 17:55:08.025880711 -0400

+ @@ -48,7 +48,7 @@ struct monitor_dimm {

+  	struct list_node list;

+  };

+  

+ -static struct util_filter_params param;

+ +static struct ndctl_filter_params param;

+  

+  static int did_fail;

+  

+ @@ -263,12 +263,12 @@ out:

+  }

+  

+  static bool filter_region(struct ndctl_region *region,

+ -		struct util_filter_ctx *fctx)

+ +			  struct ndctl_filter_ctx *fctx)

+  {

+  	return true;

+  }

+  

+ -static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *fctx)

+ +static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *fctx)

+  {

+  	struct monitor_dimm *mdimm;

+  	struct monitor_filter_arg *mfa = fctx->monitor;

+ @@ -316,7 +316,7 @@ static void filter_dimm(struct ndctl_dim

+  	return;

+  }

+  

+ -static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *fctx)

+ +static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *fctx)

+  {

+  	return true;

+  }

+ @@ -481,7 +481,7 @@ static void parse_config(const char **ar

+  }

+  

+  static int read_config_file(struct ndctl_ctx *ctx, struct monitor *_monitor,

+ -		struct util_filter_params *_param)

+ +		struct ndctl_filter_params *_param)

+  {

+  	FILE *f;

+  	size_t len = 0;

+ @@ -603,7 +603,7 @@ int cmd_monitor(int argc, const char **a

+  		NULL

+  	};

+  	const char *prefix = "./";

+ -	struct util_filter_ctx fctx = { 0 };

+ +	struct ndctl_filter_ctx fctx = { 0 };

+  	struct monitor_filter_arg mfa = { 0 };

+  	int i, rc;

+  

+ @@ -667,7 +667,7 @@ int cmd_monitor(int argc, const char **a

+  	mfa.maxfd_dimm = -1;

+  	mfa.flags = 0;

+  

+ -	rc = util_filter_walk(ctx, &fctx, &param);

+ +	rc = ndctl_filter_walk(ctx, &fctx, &param);

+  	if (rc)

+  		goto out;

+  

+ diff -up ndctl-71.1/test/list-smart-dimm.c.orig ndctl-71.1/test/list-smart-dimm.c

+ --- ndctl-71.1/test/list-smart-dimm.c.orig	2022-10-07 17:54:40.813788062 -0400

+ +++ ndctl-71.1/test/list-smart-dimm.c	2022-10-07 17:54:52.595828176 -0400

+ @@ -11,7 +11,7 @@

+  #include <ndctl/ndctl.h>

+  #include <ndctl/json.h>

+  

+ -struct util_filter_params param;

+ +struct ndctl_filter_params param;

+  static int did_fail;

+  static int jflag = JSON_C_TO_STRING_PRETTY;

+  

+ @@ -23,12 +23,12 @@ do { \

+  } while (0)

+  

+  static bool filter_region(struct ndctl_region *region,

+ -		struct util_filter_ctx *ctx)

+ +		struct ndctl_filter_ctx *ctx)

+  {

+  	return true;

+  }

+  

+ -static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)

+ +static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *ctx)

+  {

+  	struct list_filter_arg *lfa = ctx->list;

+  	struct json_object *jdimm;

+ @@ -57,7 +57,7 @@ static void filter_dimm(struct ndctl_dim

+  	json_object_array_add(lfa->jdimms, jdimm);

+  }

+  

+ -static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx)

+ +static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx)

+  {

+  	return true;

+  }

+ @@ -89,7 +89,7 @@ int main(int argc, const char *argv[])

+  		"list-smart-dimm [<options>]",

+  		NULL

+  	};

+ -	struct util_filter_ctx fctx = { 0 };

+ +	struct ndctl_filter_ctx fctx = { 0 };

+  	struct list_filter_arg lfa = { 0 };

+  

+  	rc = ndctl_new(&ctx);

+ @@ -108,7 +108,7 @@ int main(int argc, const char *argv[])

+  	fctx.list = &lfa;

+  	lfa.flags = 0;

+  

+ -	rc = util_filter_walk(ctx, &fctx, &param);

+ +	rc = ndctl_filter_walk(ctx, &fctx, &param);

+  	if (rc)

+  		return rc;

+  

+ diff -up ndctl-71.1/util/filter.c.orig ndctl-71.1/util/filter.c

+ --- ndctl-71.1/util/filter.c.orig	2022-10-07 17:55:48.192017464 -0400

+ +++ ndctl-71.1/util/filter.c	2022-10-07 17:55:54.474038852 -0400

+ @@ -394,8 +394,8 @@ const char *util_nsmode_name(enum ndctl_

+  	return modes[mode];

+  }

+  

+ -int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,

+ -		struct util_filter_params *param)

+ +int ndctl_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,

+ +		      struct util_filter_params *param)

+  {

+  	struct ndctl_bus *bus;

+  	unsigned int type = 0;

@@ -0,0 +1,54 @@ 

+ From 6dafb0baf8fda14f25e0a764fe8f89d8a4727b0c Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:05 -0800

+ Subject: [PATCH 089/217] build: Add tags

+ 

+ Copy the systemd approach to generating tags with a file listing from git.

+ 

+ Link: https://lore.kernel.org/r/164298552547.3021641.2951502977152843738.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  meson.build | 19 +++++++++++++++++++

+  1 file changed, 19 insertions(+)

+ 

+ diff --git a/meson.build b/meson.build

+ index b22fb2e..68f3d0c 100644

+ --- a/meson.build

+ +++ b/meson.build

+ @@ -82,6 +82,7 @@ project_source_root = meson.current_source_dir()

+  # Cleanup the leftover config.h files to avoid conflicts with the meson

+  # generated config.h

+  git = find_program('git', required : false)

+ +env = find_program('env')

+  if git.found()

+    run_command('clean_config.sh',

+      env : 'GIT_DIR=@0@/.git'.format(project_source_root),

+ @@ -111,6 +112,24 @@ else

+    )

+  endif

+  

+ +if git.found()

+ +  all_files = run_command(

+ +    env, '-u', 'GIT_WORK_TREE',

+ +    git, '--git-dir=@0@/.git'.format(project_source_root),

+ +         'ls-files', ':/*.[ch]',

+ +    check : false)

+ +  if all_files.returncode() == 0

+ +    all_files = files(all_files.stdout().split())

+ +    custom_target(

+ +            'tags',

+ +            output : 'tags',

+ +            command : [env, 'etags', '-o', '@0@/TAGS'.format(project_source_root)] + all_files)

+ +    run_target(

+ +            'ctags',

+ +            command : [env, 'ctags', '-o', '@0@/tags'.format(project_source_root)] + all_files)

+ +  endif

+ +endif

+ +

+  versiondep = declare_dependency(

+    compile_args: ['-include', 'version.h'],

+    sources: version_h

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,194 @@ 

+ From 691cd249750b505753680d2a766280698ce25b75 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:10 -0800

+ Subject: [PATCH 090/217] json: Add support for json_object_new_uint64()

+ 

+ Recent versions of json-c add a proper u64 type. However since ndctl still

+ needs to build against older json-c add build infrastructure to fallback to

+ s64.

+ 

+ Link: https://lore.kernel.org/r/164298553057.3021641.17232869374733997747.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  config.h.meson |  3 +++

+  cxl/json.c     |  6 +++---

+  daxctl/json.c  |  2 +-

+  meson.build    |  6 ++++++

+  ndctl/dimm.c   |  2 +-

+  ndctl/json.c   | 10 +++++-----

+  util/json.c    |  2 +-

+  util/json.h    | 13 ++++++++++++-

+  8 files changed, 32 insertions(+), 12 deletions(-)

+ 

+ diff -up ndctl-71.1/config.h.meson.orig ndctl-71.1/config.h.meson

+ --- ndctl-71.1/config.h.meson.orig	2022-10-07 17:40:36.698914113 -0400

+ +++ ndctl-71.1/config.h.meson	2022-10-07 17:41:24.043075305 -0400

+ @@ -88,6 +88,9 @@

+  /* Define to 1 if you have the `__secure_getenv' function. */

+  #mesondefine HAVE___SECURE_GETENV

+  

+ +/* Define to 1 if you have json_object_new_uint64 in json-c */

+ +#mesondefine HAVE_JSON_U64

+ +

+  /* Define to the sub-directory where libtool stores uninstalled libraries. */

+  #mesondefine LT_OBJDIR

+  

+ diff -up ndctl-71.1/cxl/json.c.orig ndctl-71.1/cxl/json.c

+ --- ndctl-71.1/cxl/json.c.orig	2022-10-07 17:40:36.668914011 -0400

+ +++ ndctl-71.1/cxl/json.c	2022-10-07 17:41:24.043075305 -0400

+ @@ -159,17 +159,17 @@ static struct json_object *util_cxl_memd

+  	}

+  

+  	field = cxl_cmd_health_info_get_dirty_shutdowns(cmd);

+ -	jobj = json_object_new_int64(field);

+ +	jobj = util_json_new_u64(field);

+  	if (jobj)

+  		json_object_object_add(jhealth, "dirty_shutdowns", jobj);

+  

+  	field = cxl_cmd_health_info_get_volatile_errors(cmd);

+ -	jobj = json_object_new_int64(field);

+ +	jobj = util_json_new_u64(field);

+  	if (jobj)

+  		json_object_object_add(jhealth, "volatile_errors", jobj);

+  

+  	field = cxl_cmd_health_info_get_pmem_errors(cmd);

+ -	jobj = json_object_new_int64(field);

+ +	jobj = util_json_new_u64(field);

+  	if (jobj)

+  		json_object_object_add(jhealth, "pmem_errors", jobj);

+  

+ diff -up ndctl-71.1/daxctl/json.c.orig ndctl-71.1/daxctl/json.c

+ --- ndctl-71.1/daxctl/json.c.orig	2022-10-07 17:40:36.671914021 -0400

+ +++ ndctl-71.1/daxctl/json.c	2022-10-07 17:41:24.043075305 -0400

+ @@ -190,7 +190,7 @@ struct json_object *util_daxctl_region_t

+  

+  	align = daxctl_region_get_align(region);

+  	if (align < ULONG_MAX) {

+ -		jobj = json_object_new_int64(align);

+ +		jobj = util_json_new_u64(align);

+  		if (!jobj)

+  			goto err;

+  		json_object_object_add(jregion, "align", jobj);

+ diff -up ndctl-71.1/meson.build.orig ndctl-71.1/meson.build

+ --- ndctl-71.1/meson.build.orig	2022-10-07 17:40:36.720914188 -0400

+ +++ ndctl-71.1/meson.build	2022-10-07 17:41:24.044075308 -0400

+ @@ -240,6 +240,12 @@ foreach ident : ['secure_getenv', '__sec

+    conf.set10('HAVE_' + ident.to_upper(), cc.has_function(ident))

+  endforeach

+  

+ +conf.set10('HAVE_JSON_U64',

+ +  cc.has_function('json_object_new_uint64',

+ +    prefix : '''#include <json-c/json.h>''',

+ +    dependencies : json,

+ +  )

+ +)

+  

+  ndctlconf_dir = sysconfdir / 'ndctl'

+  ndctlconf = ndctlconf_dir / 'monitor.conf'

+ diff -up ndctl-71.1/ndctl/dimm.c.orig ndctl-71.1/ndctl/dimm.c

+ --- ndctl-71.1/ndctl/dimm.c.orig	2022-10-07 17:40:36.673914028 -0400

+ +++ ndctl-71.1/ndctl/dimm.c	2022-10-07 17:41:24.044075308 -0400

+ @@ -168,7 +168,7 @@ static struct json_object *dump_label_js

+  			break;

+  		json_object_object_add(jlabel, "isetcookie", jobj);

+  

+ -		jobj = json_object_new_int64(le64_to_cpu(nslabel.lbasize));

+ +		jobj = util_json_new_u64(le64_to_cpu(nslabel.lbasize));

+  		if (!jobj)

+  			break;

+  		json_object_object_add(jlabel, "lbasize", jobj);

+ diff -up ndctl-71.1/ndctl/json.c.orig ndctl-71.1/ndctl/json.c

+ --- ndctl-71.1/ndctl/json.c.orig	2022-10-07 17:40:36.675914034 -0400

+ +++ ndctl-71.1/ndctl/json.c	2022-10-07 17:41:24.044075308 -0400

+ @@ -357,7 +357,7 @@ static struct json_object *util_##type##

+  		int64_t align;					\

+  								\

+  		align = get_elem(arg, i);			\

+ -		jobj = json_object_new_int64(align);		\

+ +		jobj = util_json_new_u64(align);		\

+  		if (!jobj)					\

+  			goto err;				\

+  		json_object_array_add(arr, jobj);		\

+ @@ -550,7 +550,7 @@ struct json_object *util_region_badblock

+  		if (!jbb)

+  			goto err_array;

+  

+ -		jobj = json_object_new_int64(bb->offset);

+ +		jobj = util_json_new_u64(bb->offset);

+  		if (!jobj)

+  			goto err;

+  		json_object_object_add(jbb, "offset", jobj);

+ @@ -604,7 +604,7 @@ static struct json_object *util_namespac

+  		if (!jbb)

+  			goto err_array;

+  

+ -		jobj = json_object_new_int64(bb->offset);

+ +		jobj = util_json_new_u64(bb->offset);

+  		if (!jobj)

+  			goto err;

+  		json_object_object_add(jbb, "offset", jobj);

+ @@ -682,7 +682,7 @@ static struct json_object *dev_badblocks

+  		if (!jbb)

+  			goto err_array;

+  

+ -		jobj = json_object_new_int64(offset);

+ +		jobj = util_json_new_u64(offset);

+  		if (!jobj)

+  			goto err;

+  		json_object_object_add(jbb, "offset", jobj);

+ @@ -972,7 +972,7 @@ struct json_object *util_namespace_to_js

+  	}

+  

+  	if (align) {

+ -		jobj = json_object_new_int64(align);

+ +		jobj = util_json_new_u64(align);

+  		if (!jobj)

+  			goto err;

+  		json_object_object_add(jndns, "align", jobj);

+ diff -up ndctl-71.1/util/json.c.orig ndctl-71.1/util/json.c

+ --- ndctl-71.1/util/json.c.orig	2022-10-07 17:40:36.682914058 -0400

+ +++ ndctl-71.1/util/json.c	2022-10-07 17:41:24.045075312 -0400

+ @@ -82,7 +82,7 @@ struct json_object *util_json_object_siz

+  struct json_object *util_json_object_hex(unsigned long long val,

+  		unsigned long flags)

+  {

+ -	struct json_object *jobj = json_object_new_int64(val);

+ +	struct json_object *jobj = util_json_new_u64(val);

+  

+  	if (jobj && (flags & UTIL_JSON_HUMAN))

+  		json_object_set_serializer(jobj, display_hex, NULL, NULL);

+ diff -up ndctl-71.1/util/json.h.orig ndctl-71.1/util/json.h

+ --- ndctl-71.1/util/json.h.orig	2022-10-07 17:40:36.683914062 -0400

+ +++ ndctl-71.1/util/json.h	2022-10-07 17:41:24.046075315 -0400

+ @@ -4,6 +4,7 @@

+  #define __UTIL_JSON_H__

+  #include <stdio.h>

+  #include <stdbool.h>

+ +#include <json-c/json.h>

+  

+  enum util_json_flags {

+  	UTIL_JSON_IDLE		= (1 << 0),

+ @@ -19,11 +20,21 @@ enum util_json_flags {

+  	UTIL_JSON_HEALTH	= (1 << 10),

+  };

+  

+ -struct json_object;

+  void util_display_json_array(FILE *f_out, struct json_object *jarray,

+  		unsigned long flags);

+  struct json_object *util_json_object_size(unsigned long long size,

+  		unsigned long flags);

+  struct json_object *util_json_object_hex(unsigned long long val,

+  		unsigned long flags);

+ +#if HAVE_JSON_U64

+ +static inline struct json_object *util_json_new_u64(unsigned long long val)

+ +{

+ +	return json_object_new_uint64(val);

+ +}

+ +#else /* fallback to signed */

+ +static inline struct json_object *util_json_new_u64(unsigned long long val)

+ +{

+ +	return json_object_new_int64(val);

+ +}

+ +#endif /* HAVE_JSON_U64 */

+  #endif /* __UTIL_JSON_H__ */

@@ -0,0 +1,32 @@ 

+ From 8f457dc414ec27178828c86533910958542ce73d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:15 -0800

+ Subject: [PATCH 091/217] cxl/json: Cleanup object leak false positive

+ 

+ As written it is a leak of the json object to return if devname is NULL.

+ However, the devname can not be NULL because the memdev would not have been

+ enumerated. Drop the error checking.

+ 

+ Link: https://lore.kernel.org/r/164298553566.3021641.11858634436119663877.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/json.c | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 97ed76b..3ef9f76 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -190,7 +190,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  	struct json_object *jdev, *jobj;

+  

+  	jdev = json_object_new_object();

+ -	if (!devname || !jdev)

+ +	if (!jdev)

+  		return NULL;

+  

+  	jobj = json_object_new_string(devname);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,118 @@ 

+ From 0ce0152d8e29f85325a3a59f94051228540abf6a Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:20 -0800

+ Subject: [PATCH 092/217] cxl/list: Support multiple memdev device name filter

+  arguments

+ 

+ Similar to 'ndctl list', allow for a syntax like:

+ 

+     cxl list -m "$(seq -s ' ' 2 5)"

+ 

+ ...to filter the output to just those 4 memdevs.

+ 

+ Link: https://lore.kernel.org/r/164298554075.3021641.17678360870961637912.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt | 21 ++++++++++++++++++-

+  cxl/filter.c                   | 38 ++++++++++++++++++++++++----------

+  2 files changed, 47 insertions(+), 12 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index c8d10fb..686e0ea 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -30,7 +30,7 @@ OPTIONS

+  -------

+  -m::

+  --memdev=::

+ -	Specify a cxl memory device name to filter the listing. For example:

+ +	Specify CXL memory device name(s), or device id(s), to filter the listing. For example:

+  ----

+  # cxl list --memdev=mem0

+  {

+ @@ -38,6 +38,25 @@ OPTIONS

+    "pmem_size":268435456,

+    "ram_size":0,

+  }

+ +

+ +# cxl list -m "0 mem1 2"

+ +[

+ +  {

+ +    "memdev":"mem0",

+ +    "pmem_size":268435456,

+ +    "ram_size":0

+ +  },

+ +  {

+ +    "memdev":"mem2",

+ +    "pmem_size":268435456,

+ +    "ram_size":268435456

+ +  },

+ +  {

+ +    "memdev":"mem1",

+ +    "pmem_size":268435456,

+ +    "ram_size":268435456

+ +  }

+ +]

+  ----

+  

+  -M::

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 21322ed..efafaf5 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -2,24 +2,40 @@

+  // Copyright (C) 2015-2020 Intel Corporation. All rights reserved.

+  #include <stdio.h>

+  #include <string.h>

+ +#include <stdlib.h>

+  #include <cxl/libcxl.h>

+  #include "filter.h"

+  

+  struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+ -                                         const char *ident)

+ +					  const char *__ident)

+  {

+ -       int memdev_id;

+ +	char *ident, *save;

+ +	const char *name;

+ +	int memdev_id;

+  

+ -       if (!ident || strcmp(ident, "all") == 0)

+ -               return memdev;

+ +	if (!__ident)

+ +		return memdev;

+  

+ -       if (strcmp(ident, cxl_memdev_get_devname(memdev)) == 0)

+ -               return memdev;

+ +	ident = strdup(__ident);

+ +	if (!ident)

+ +		return NULL;

+  

+ -       if ((sscanf(ident, "%d", &memdev_id) == 1

+ -                       || sscanf(ident, "mem%d", &memdev_id) == 1)

+ -                       && cxl_memdev_get_id(memdev) == memdev_id)

+ -               return memdev;

+ +	for (name = strtok_r(ident, " ", &save); name;

+ +	     name = strtok_r(NULL, " ", &save)) {

+ +		if (strcmp(name, "all") == 0)

+ +			break;

+  

+ -       return NULL;

+ +		if ((sscanf(name, "%d", &memdev_id) == 1 ||

+ +		     sscanf(name, "mem%d", &memdev_id) == 1) &&

+ +		    cxl_memdev_get_id(memdev) == memdev_id)

+ +			break;

+ +

+ +		if (strcmp(name, cxl_memdev_get_devname(memdev)) == 0)

+ +			break;

+ +	}

+ +

+ +	free(ident);

+ +	if (name)

+ +		return memdev;

+ +	return NULL;

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,55 @@ 

+ From a36b8b815d2e8bfd8438b44d4775bdf3ffc3a6d8 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:26 -0800

+ Subject: [PATCH 093/217] cxl/list: Support comma separated lists

+ 

+ In addition to supporting a syntax like:

+ 

+    cxl list -m "0 1 2"

+ 

+ ...support:

+ 

+    cxl list -m 0,1,2

+ 

+ Link: https://lore.kernel.org/r/164298554612.3021641.3315920699556984273.stgit@dwillia2-desk3.amr.corp.intel.com

+ Reported-by: Vishal Verma <vishal.l.verma@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/filter.c | 13 +++++++++++--

+  1 file changed, 11 insertions(+), 2 deletions(-)

+ 

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index efafaf5..405b653 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -6,6 +6,15 @@

+  #include <cxl/libcxl.h>

+  #include "filter.h"

+  

+ +static const char *which_sep(const char *filter)

+ +{

+ +	if (strchr(filter, ' '))

+ +		return " ";

+ +	if (strchr(filter, ','))

+ +		return ",";

+ +	return " ";

+ +}

+ +

+  struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  					  const char *__ident)

+  {

+ @@ -20,8 +29,8 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  	if (!ident)

+  		return NULL;

+  

+ -	for (name = strtok_r(ident, " ", &save); name;

+ -	     name = strtok_r(NULL, " ", &save)) {

+ +	for (name = strtok_r(ident, which_sep(__ident), &save); name;

+ +	     name = strtok_r(NULL, which_sep(__ident), &save)) {

+  		if (strcmp(name, "all") == 0)

+  			break;

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,292 @@ 

+ From f833845ce72490e4c80b3ccc9972d5329f69a381 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:31 -0800

+ Subject: [PATCH 094/217] cxl/list: Introduce cxl_filter_walk()

+ 

+ In preparation for introducing more objects and filtering options for 'cxl

+ list' introduce cxl_filter_walk() to centralize CXL topology walks. It

+ fills the same role as ndctl_filter_walk() as a way to distribute topology

+ interrogation beyond 'cxl list' to other commands, and serve as the

+ template for CXL object hierarchy in JSON output payloads.

+ 

+ Use the common dbg() logger for log messages.

+ 

+ Link: https://lore.kernel.org/r/164298555121.3021641.16127840206319352254.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt |   2 +

+  cxl/filter.c                   |  50 ++++++++++++++++

+  cxl/filter.h                   |  18 +++++-

+  cxl/list.c                     | 102 +++++++--------------------------

+  cxl/meson.build                |   1 +

+  5 files changed, 90 insertions(+), 83 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 686e0ea..4d409ba 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -15,6 +15,8 @@ SYNOPSIS

+  Walk the CXL capable device hierarchy in the system and list all device

+  instances along with some of their major attributes.

+  

+ +Options can be specified to limit the output to specific objects.

+ +

+  EXAMPLE

+  -------

+  ----

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 405b653..d1ff4b6 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -1,10 +1,16 @@

+  // SPDX-License-Identifier: GPL-2.0

+  // Copyright (C) 2015-2020 Intel Corporation. All rights reserved.

+ +#include <errno.h>

+  #include <stdio.h>

+  #include <string.h>

+  #include <stdlib.h>

+ +#include <util/log.h>

+ +#include <util/json.h>

+  #include <cxl/libcxl.h>

+ +#include <json-c/json.h>

+ +

+  #include "filter.h"

+ +#include "json.h"

+  

+  static const char *which_sep(const char *filter)

+  {

+ @@ -48,3 +54,47 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  		return memdev;

+  	return NULL;

+  }

+ +

+ +static unsigned long params_to_flags(struct cxl_filter_params *param)

+ +{

+ +	unsigned long flags = 0;

+ +

+ +	if (param->idle)

+ +		flags |= UTIL_JSON_IDLE;

+ +	if (param->human)

+ +		flags |= UTIL_JSON_HUMAN;

+ +	if (param->health)

+ +		flags |= UTIL_JSON_HEALTH;

+ +	return flags;

+ +}

+ +

+ +int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+ +{

+ +	struct json_object *jplatform = json_object_new_array();

+ +	unsigned long flags = params_to_flags(p);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (!jplatform) {

+ +		dbg(p, "platform object allocation failure\n");

+ +		return -ENOMEM;

+ +	}

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		struct json_object *jdev;

+ +

+ +		if (!util_cxl_memdev_filter(memdev, p->memdev_filter))

+ +			continue;

+ +		if (p->memdevs) {

+ +			jdev = util_cxl_memdev_to_json(memdev, flags);

+ +			if (!jdev) {

+ +				dbg(p, "memdev object allocation failure\n");

+ +				continue;

+ +			}

+ +			json_object_array_add(jplatform, jdev);

+ +		}

+ +	}

+ +

+ +	util_display_json_array(stdout, jplatform, flags);

+ +

+ +	return 0;

+ +}

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index da80033..664b74b 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -1,7 +1,21 @@

+  /* SPDX-License-Identifier: GPL-2.0 */

+ -/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */

+ +/* Copyright (C) 2021 Intel Corporation. All rights reserved. */

+  #ifndef _CXL_UTIL_FILTER_H_

+  #define _CXL_UTIL_FILTER_H_

+ +

+ +#include <stdbool.h>

+ +#include <util/log.h>

+ +

+ +struct cxl_filter_params {

+ +	const char *memdev_filter;

+ +	bool memdevs;

+ +	bool idle;

+ +	bool human;

+ +	bool health;

+ +	struct log_ctx ctx;

+ +};

+ +

+  struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+ -		const char *ident);

+ +					  const char *ident);

+ +int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);

+  #endif /* _CXL_UTIL_FILTER_H_ */

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 7f7a04d..1730307 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -9,60 +9,27 @@

+  #include <json-c/json.h>

+  #include <cxl/libcxl.h>

+  #include <util/parse-options.h>

+ -#include <ccan/array_size/array_size.h>

+  

+ -#include "json.h"

+  #include "filter.h"

+  

+ -static struct {

+ -	bool memdevs;

+ -	bool idle;

+ -	bool human;

+ -	bool health;

+ -} list;

+ -

+ -static unsigned long listopts_to_flags(void)

+ -{

+ -	unsigned long flags = 0;

+ -

+ -	if (list.idle)

+ -		flags |= UTIL_JSON_IDLE;

+ -	if (list.human)

+ -		flags |= UTIL_JSON_HUMAN;

+ -	if (list.health)

+ -		flags |= UTIL_JSON_HEALTH;

+ -	return flags;

+ -}

+ -

+ -static struct {

+ -	const char *memdev;

+ -} param;

+ -

+ -static int did_fail;

+ -

+ -#define fail(fmt, ...) \

+ -do { \

+ -	did_fail = 1; \

+ -	fprintf(stderr, "cxl-%s:%s:%d: " fmt, \

+ -			VERSION, __func__, __LINE__, ##__VA_ARGS__); \

+ -} while (0)

+ +static struct cxl_filter_params param;

+  

+  static int num_list_flags(void)

+  {

+ -	return list.memdevs;

+ +	return param.memdevs;

+  }

+  

+  int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  {

+  	const struct option options[] = {

+ -		OPT_STRING('m', "memdev", &param.memdev, "memory device name",

+ +		OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name",

+  			   "filter by CXL memory device name"),

+ -		OPT_BOOLEAN('M', "memdevs", &list.memdevs,

+ +		OPT_BOOLEAN('M', "memdevs", &param.memdevs,

+  			    "include CXL memory device info"),

+ -		OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),

+ -		OPT_BOOLEAN('u', "human", &list.human,

+ +		OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+ +		OPT_BOOLEAN('u', "human", &param.human,

+  				"use human friendly number formats "),

+ -		OPT_BOOLEAN('H', "health", &list.health,

+ +		OPT_BOOLEAN('H', "health", &param.health,

+  				"include memory device health information "),

+  		OPT_END(),

+  	};

+ @@ -70,9 +37,6 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  		"cxl list [<options>]",

+  		NULL

+  	};

+ -	struct json_object *jdevs = NULL;

+ -	unsigned long list_flags;

+ -	struct cxl_memdev *memdev;

+  	int i;

+  

+  	argc = parse_options(argc, argv, options, u, 0);

+ @@ -83,46 +47,22 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  		usage_with_options(u, options);

+  

+  	if (num_list_flags() == 0) {

+ -		/*

+ -		 * TODO: We likely want to list regions by default if nothing

+ -		 * was explicitly asked for. But until we have region support,

+ -		 * print this error asking for devices explicitly.

+ -		 * Once region support is added, this TODO can be removed.

+ -		 */

+ -		error("please specify entities to list, e.g. using -m/-M\n");

+ -		usage_with_options(u, options);

+ -	}

+ -

+ -	list_flags = listopts_to_flags();

+ -

+ -	cxl_memdev_foreach(ctx, memdev) {

+ -		struct json_object *jdev = NULL;

+ -

+ -		if (!util_cxl_memdev_filter(memdev, param.memdev))

+ -			continue;

+ -

+ -		if (list.memdevs) {

+ -			if (!jdevs) {

+ -				jdevs = json_object_new_array();

+ -				if (!jdevs) {

+ -					fail("\n");

+ -					continue;

+ -				}

+ -			}

+ -

+ -			jdev = util_cxl_memdev_to_json(memdev, list_flags);

+ -			if (!jdev) {

+ -				fail("\n");

+ -				continue;

+ -			}

+ -			json_object_array_add(jdevs, jdev);

+ +		if (param.memdev_filter)

+ +			param.memdevs = true;

+ +		else {

+ +			/*

+ +			 * TODO: We likely want to list regions by default if

+ +			 * nothing was explicitly asked for. But until we have

+ +			 * region support, print this error asking for devices

+ +			 * explicitly.  Once region support is added, this TODO

+ +			 * can be removed.

+ +			 */

+ +			error("please specify entities to list, e.g. using -m/-M\n");

+ +			usage_with_options(u, options);

+  		}

+  	}

+  

+ -	if (jdevs)

+ -		util_display_json_array(stdout, jdevs, list_flags);

+ +	log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");

+  

+ -	if (did_fail)

+ -		return -ENOMEM;

+ -	return 0;

+ +	return cxl_filter_walk(ctx, &param);

+  }

+ diff --git a/cxl/meson.build b/cxl/meson.build

+ index 805924b..fc7ee71 100644

+ --- a/cxl/meson.build

+ +++ b/cxl/meson.build

+ @@ -3,6 +3,7 @@ cxl_src = [

+    'list.c',

+    'memdev.c',

+    '../util/json.c',

+ +  '../util/log.c',

+    'json.c',

+    'filter.c',

+  ]

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,159 @@ 

+ From 2d1b8cea119ca2bb0eec8ebb2dfb1b6c4d844ddd Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:36 -0800

+ Subject: [PATCH 095/217] cxl/list: Emit device serial numbers

+ 

+ Starting with the v5.17 kernel the CXL driver emits the mandatory device

+ serial number for each memory device. Include it in the memory device

+ listing.

+ 

+ Link: https://lore.kernel.org/r/164298555630.3021641.3246226448369816200.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt | 15 +++++++++------

+  cxl/json.c                     | 11 ++++++++++-

+  cxl/lib/libcxl.c               | 11 +++++++++++

+  cxl/lib/libcxl.sym             |  5 +++++

+  cxl/lib/private.h              |  1 +

+  cxl/libcxl.h                   |  1 +

+  6 files changed, 37 insertions(+), 7 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 4d409ba..bd0207e 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -41,22 +41,25 @@ OPTIONS

+    "ram_size":0,

+  }

+  

+ -# cxl list -m "0 mem1 2"

+ +# cxl list -M --memdev="0 mem3 5"

+  [

+    {

+      "memdev":"mem0",

+      "pmem_size":268435456,

+ -    "ram_size":0

+ +    "ram_size":0,

+ +    "serial":0

+    },

+    {

+ -    "memdev":"mem2",

+ +    "memdev":"mem3",

+      "pmem_size":268435456,

+ -    "ram_size":268435456

+ +    "ram_size":268435456,

+ +    "serial":2

+    },

+    {

+ -    "memdev":"mem1",

+ +    "memdev":"mem5",

+      "pmem_size":268435456,

+ -    "ram_size":268435456

+ +    "ram_size":268435456,

+ +    "serial":4

+    }

+  ]

+  ----

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 3ef9f76..d8e65df 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -1,5 +1,6 @@

+  // SPDX-License-Identifier: GPL-2.0

+ -// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.

+ +// Copyright (C) 2015-2021 Intel Corporation. All rights reserved.

+ +#include <limits.h>

+  #include <util/json.h>

+  #include <uuid/uuid.h>

+  #include <cxl/libcxl.h>

+ @@ -188,6 +189,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  {

+  	const char *devname = cxl_memdev_get_devname(memdev);

+  	struct json_object *jdev, *jobj;

+ +	unsigned long long serial;

+  

+  	jdev = json_object_new_object();

+  	if (!jdev)

+ @@ -210,5 +212,12 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  		if (jobj)

+  			json_object_object_add(jdev, "health", jobj);

+  	}

+ +

+ +	serial = cxl_memdev_get_serial(memdev);

+ +	if (serial < ULLONG_MAX) {

+ +		jobj = util_json_object_hex(serial, flags);

+ +		if (jobj)

+ +			json_object_object_add(jdev, "serial", jobj);

+ +	}

+  	return jdev;

+  }

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 3390eb9..8d3cf80 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -296,6 +296,12 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  	if (memdev->lsa_size == ULLONG_MAX)

+  		goto err_read;

+  

+ +	sprintf(path, "%s/serial", cxlmem_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		memdev->serial = ULLONG_MAX;

+ +	else

+ +		memdev->serial = strtoull(buf, NULL, 0);

+ +

+  	memdev->dev_path = strdup(cxlmem_base);

+  	if (!memdev->dev_path)

+  		goto err_read;

+ @@ -371,6 +377,11 @@ CXL_EXPORT int cxl_memdev_get_id(struct cxl_memdev *memdev)

+  	return memdev->id;

+  }

+  

+ +CXL_EXPORT unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev)

+ +{

+ +	return memdev->serial;

+ +}

+ +

+  CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)

+  {

+  	return devpath_to_devname(memdev->dev_path);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 077d104..4411035 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -73,3 +73,8 @@ global:

+  local:

+          *;

+  };

+ +

+ +LIBCXL_2 {

+ +global:

+ +	cxl_memdev_get_serial;

+ +} LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index a1b8b50..28f7e16 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -31,6 +31,7 @@ struct cxl_memdev {

+  	size_t lsa_size;

+  	struct kmod_module *module;

+  	struct cxl_nvdimm_bridge *bridge;

+ +	unsigned long long serial;

+  };

+  

+  enum cxl_cmd_query_status {

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 89d35ba..bcdede8 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -35,6 +35,7 @@ struct cxl_memdev;

+  struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);

+  struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);

+  int cxl_memdev_get_id(struct cxl_memdev *memdev);

+ +unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);

+  int cxl_memdev_get_major(struct cxl_memdev *memdev);

+  int cxl_memdev_get_minor(struct cxl_memdev *memdev);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,163 @@ 

+ From d7854adcd1e517d2372ec51f4a1ede2d549975e8 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:41 -0800

+ Subject: [PATCH 096/217] cxl/list: Add filter by serial support

+ 

+ Given that serial numbers are intended to be unique device identifiers,

+ enable them as a memdev filter option.

+ 

+ Link: https://lore.kernel.org/r/164298556167.3021641.5470955268978068465.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt |  4 ++++

+  cxl/filter.c                   | 38 ++++++++++++++++++++++++++++++----

+  cxl/filter.h                   |  4 +++-

+  cxl/list.c                     |  4 +++-

+  cxl/memdev.c                   |  2 +-

+  5 files changed, 45 insertions(+), 7 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index bd0207e..224c972 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -64,6 +64,10 @@ OPTIONS

+  ]

+  ----

+  

+ +-s::

+ +--serial=::

+ +	Specify CXL memory device serial number(s) to filter the listing

+ +

+  -M::

+  --memdevs::

+  	Include CXL memory devices in the listing

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index d1ff4b6..26efc65 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -21,15 +21,45 @@ static const char *which_sep(const char *filter)

+  	return " ";

+  }

+  

+ +static struct cxl_memdev *

+ +util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials)

+ +{

+ +	unsigned long long serial = 0;

+ +	char *serials, *save, *end;

+ +	const char *arg;

+ +

+ +	if (!__serials)

+ +		return memdev;

+ +

+ +	serials = strdup(__serials);

+ +	if (!serials)

+ +		return NULL;

+ +

+ +	for (arg = strtok_r(serials, which_sep(__serials), &save); arg;

+ +	     arg = strtok_r(NULL, which_sep(__serials), &save)) {

+ +		serial = strtoull(arg, &end, 0);

+ +		if (!arg[0] || end[0] != 0)

+ +			continue;

+ +		if (cxl_memdev_get_serial(memdev) == serial)

+ +			break;

+ +	}

+ +

+ +	free(serials);

+ +	if (arg)

+ +		return memdev;

+ +	return NULL;

+ +}

+ +

+  struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+ -					  const char *__ident)

+ +					  const char *__ident,

+ +					  const char *serials)

+  {

+  	char *ident, *save;

+  	const char *name;

+  	int memdev_id;

+  

+  	if (!__ident)

+ -		return memdev;

+ +		return util_cxl_memdev_serial_filter(memdev, serials);

+  

+  	ident = strdup(__ident);

+  	if (!ident)

+ @@ -51,7 +81,7 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  

+  	free(ident);

+  	if (name)

+ -		return memdev;

+ +		return util_cxl_memdev_serial_filter(memdev, serials);

+  	return NULL;

+  }

+  

+ @@ -82,7 +112,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	cxl_memdev_foreach(ctx, memdev) {

+  		struct json_object *jdev;

+  

+ -		if (!util_cxl_memdev_filter(memdev, p->memdev_filter))

+ +		if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter))

+  			continue;

+  		if (p->memdevs) {

+  			jdev = util_cxl_memdev_to_json(memdev, flags);

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 664b74b..12d9344 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -8,6 +8,7 @@

+  

+  struct cxl_filter_params {

+  	const char *memdev_filter;

+ +	const char *serial_filter;

+  	bool memdevs;

+  	bool idle;

+  	bool human;

+ @@ -16,6 +17,7 @@ struct cxl_filter_params {

+  };

+  

+  struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+ -					  const char *ident);

+ +					  const char *__ident,

+ +					  const char *serials);

+  int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);

+  #endif /* _CXL_UTIL_FILTER_H_ */

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 1730307..6bc48df 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -24,6 +24,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  	const struct option options[] = {

+  		OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name",

+  			   "filter by CXL memory device name"),

+ +		OPT_STRING('s', "serial", &param.serial_filter, "memory device serial",

+ +			   "filter by CXL memory device serial number"),

+  		OPT_BOOLEAN('M', "memdevs", &param.memdevs,

+  			    "include CXL memory device info"),

+  		OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+ @@ -47,7 +49,7 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  		usage_with_options(u, options);

+  

+  	if (num_list_flags() == 0) {

+ -		if (param.memdev_filter)

+ +		if (param.memdev_filter || param.serial_filter)

+  			param.memdevs = true;

+  		else {

+  			/*

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index d063d51..b9141be 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -248,7 +248,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  			continue;

+  

+  		cxl_memdev_foreach (ctx, memdev) {

+ -			if (!util_cxl_memdev_filter(memdev, argv[i]))

+ +			if (!util_cxl_memdev_filter(memdev, argv[i], NULL))

+  				continue;

+  

+  			if (action == action_write) {

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,164 @@ 

+ From 0be46d9c6638903978d16388c765a1907d5970bc Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:47 -0800

+ Subject: [PATCH 097/217] cxl/lib: Rename nvdimm bridge to pmem

+ 

+ The kernel has 2 object classes for connecting CXL to NVDIMM. There is an

+ 'nvdimm-bridge' object (one per root CXL port) that represents a CXL NVDIMM

+ Bus, and there are 'pmem' object that represent CXL NVDIMM DIMM devices.

+ The object that the library is currently calling an nvdimm-bridge is

+ actually the 'pmem' object. Rename accordingly.

+ 

+ The exported function cxl_memdev_nvdimm_bridge_active() is not renamed, but

+ since it is a cxl_memdev operation and 'struct cxl_pmem' is an

+ implementation detail it is fine as is.

+ 

+ Link: https://lore.kernel.org/r/164298556712.3021641.15612755067301105130.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c  | 56 +++++++++++++++++++++++------------------------

+  cxl/lib/private.h |  4 ++--

+  2 files changed, 30 insertions(+), 30 deletions(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 8d3cf80..9839f26 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -45,11 +45,11 @@ struct cxl_ctx {

+  	void *private_data;

+  };

+  

+ -static void free_bridge(struct cxl_nvdimm_bridge *bridge)

+ +static void free_pmem(struct cxl_pmem *pmem)

+  {

+ -	free(bridge->dev_buf);

+ -	free(bridge->dev_path);

+ -	free(bridge);

+ +	free(pmem->dev_buf);

+ +	free(pmem->dev_path);

+ +	free(pmem);

+  }

+  

+  static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+ @@ -57,7 +57,7 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+  	if (head)

+  		list_del_from(head, &memdev->list);

+  	kmod_module_unref(memdev->module);

+ -	free_bridge(memdev->bridge);

+ +	free_pmem(memdev->pmem);

+  	free(memdev->firmware_version);

+  	free(memdev->dev_buf);

+  	free(memdev->dev_path);

+ @@ -213,36 +213,36 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)

+  	ctx->ctx.log_priority = priority;

+  }

+  

+ -static void *add_cxl_bridge(void *parent, int id, const char *br_base)

+ +static void *add_cxl_pmem(void *parent, int id, const char *br_base)

+  {

+  	const char *devname = devpath_to_devname(br_base);

+  	struct cxl_memdev *memdev = parent;

+  	struct cxl_ctx *ctx = memdev->ctx;

+ -	struct cxl_nvdimm_bridge *bridge;

+ +	struct cxl_pmem *pmem;

+  

+ -	dbg(ctx, "%s: bridge_base: \'%s\'\n", devname, br_base);

+ +	dbg(ctx, "%s: pmem_base: \'%s\'\n", devname, br_base);

+  

+ -	bridge = calloc(1, sizeof(*bridge));

+ -	if (!bridge)

+ +	pmem = calloc(1, sizeof(*pmem));

+ +	if (!pmem)

+  		goto err_dev;

+ -	bridge->id = id;

+ +	pmem->id = id;

+  

+ -	bridge->dev_path = strdup(br_base);

+ -	if (!bridge->dev_path)

+ +	pmem->dev_path = strdup(br_base);

+ +	if (!pmem->dev_path)

+  		goto err_read;

+  

+ -	bridge->dev_buf = calloc(1, strlen(br_base) + 50);

+ -	if (!bridge->dev_buf)

+ +	pmem->dev_buf = calloc(1, strlen(br_base) + 50);

+ +	if (!pmem->dev_buf)

+  		goto err_read;

+ -	bridge->buf_len = strlen(br_base) + 50;

+ +	pmem->buf_len = strlen(br_base) + 50;

+  

+ -	memdev->bridge = bridge;

+ -	return bridge;

+ +	memdev->pmem = pmem;

+ +	return pmem;

+  

+   err_read:

+ -	free(bridge->dev_buf);

+ -	free(bridge->dev_path);

+ -	free(bridge);

+ +	free(pmem->dev_buf);

+ +	free(pmem->dev_path);

+ +	free(pmem);

+   err_dev:

+  	return NULL;

+  }

+ @@ -319,7 +319,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  		goto err_read;

+  	memdev->buf_len = strlen(cxlmem_base) + 50;

+  

+ -	sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_bridge);

+ +	sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_pmem);

+  

+  	cxl_memdev_foreach(ctx, memdev_dup)

+  		if (memdev_dup->id == memdev->id) {

+ @@ -430,18 +430,18 @@ static int is_enabled(const char *drvpath)

+  CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)

+  {

+  	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ -	struct cxl_nvdimm_bridge *bridge = memdev->bridge;

+ +	struct cxl_pmem *pmem = memdev->pmem;

+  	char *path;

+  	int len;

+  

+ -	if (!bridge)

+ +	if (!pmem)

+  		return 0;

+  

+ -	path = bridge->dev_buf;

+ -	len = bridge->buf_len;

+ +	path = pmem->dev_buf;

+ +	len = pmem->buf_len;

+  

+ -	if (snprintf(path, len, "%s/driver", bridge->dev_path) >= len) {

+ -		err(ctx, "%s: nvdimm bridge buffer too small!\n",

+ +	if (snprintf(path, len, "%s/driver", pmem->dev_path) >= len) {

+ +		err(ctx, "%s: nvdimm pmem buffer too small!\n",

+  				cxl_memdev_get_devname(memdev));

+  		return 0;

+  	}

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 28f7e16..7c81e24 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -10,7 +10,7 @@

+  

+  #define CXL_EXPORT __attribute__ ((visibility("default")))

+  

+ -struct cxl_nvdimm_bridge {

+ +struct cxl_pmem {

+  	int id;

+  	void *dev_buf;

+  	size_t buf_len;

+ @@ -30,7 +30,7 @@ struct cxl_memdev {

+  	int payload_max;

+  	size_t lsa_size;

+  	struct kmod_module *module;

+ -	struct cxl_nvdimm_bridge *bridge;

+ +	struct cxl_pmem *pmem;

+  	unsigned long long serial;

+  };

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,61 @@ 

+ From 5d20a4d2cca923e63cb1604da51788c0fd078ce1 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:52 -0800

+ Subject: [PATCH 098/217] cxl/list: Cleanup options definitions

+ 

+ Clarify which options take lists by adding a "(s)" to the object name, and

+ move the option block out of cmd_list() to reduce the column-80 collisions.

+ 

+ Link: https://lore.kernel.org/r/164298557263.3021641.8121105326167408001.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/list.c | 30 ++++++++++++++++--------------

+  1 file changed, 16 insertions(+), 14 deletions(-)

+ 

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 6bc48df..7e2744d 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -19,22 +19,24 @@ static int num_list_flags(void)

+  	return param.memdevs;

+  }

+  

+ +static const struct option options[] = {

+ +	OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name(s)",

+ +		   "filter by CXL memory device name(s)"),

+ +	OPT_STRING('s', "serial", &param.serial_filter,

+ +		   "memory device serial(s)",

+ +		   "filter by CXL memory device serial number(s)"),

+ +	OPT_BOOLEAN('M', "memdevs", &param.memdevs,

+ +		    "include CXL memory device info"),

+ +	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+ +	OPT_BOOLEAN('u', "human", &param.human,

+ +		    "use human friendly number formats "),

+ +	OPT_BOOLEAN('H', "health", &param.health,

+ +		    "include memory device health information "),

+ +	OPT_END(),

+ +};

+ +

+  int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  {

+ -	const struct option options[] = {

+ -		OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name",

+ -			   "filter by CXL memory device name"),

+ -		OPT_STRING('s', "serial", &param.serial_filter, "memory device serial",

+ -			   "filter by CXL memory device serial number"),

+ -		OPT_BOOLEAN('M', "memdevs", &param.memdevs,

+ -			    "include CXL memory device info"),

+ -		OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+ -		OPT_BOOLEAN('u', "human", &param.human,

+ -				"use human friendly number formats "),

+ -		OPT_BOOLEAN('H', "health", &param.health,

+ -				"include memory device health information "),

+ -		OPT_END(),

+ -	};

+  	const char * const u[] = {

+  		"cxl list [<options>]",

+  		NULL

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,170 @@ 

+ From 7b9ed7e065c6de029385d40de1f7cb0aed3a9108 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:52:57 -0800

+ Subject: [PATCH 099/217] Documentation: Enhance libcxl memdev API

+  documentation

+ 

+ In preparation for adding documentation for more objects, organize the

+ current into subsections and flesh out descriptions for the current APIs.

+ 

+ Link: https://lore.kernel.org/r/164298557771.3021641.14904324834528700206.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/copyright.txt      |   2 +-

+  Documentation/cxl/lib/libcxl.txt | 111 +++++++++++++++++++++++++++----

+  2 files changed, 99 insertions(+), 14 deletions(-)

+ 

+ diff --git a/Documentation/copyright.txt b/Documentation/copyright.txt

+ index a9380e1..af9caf7 100644

+ --- a/Documentation/copyright.txt

+ +++ b/Documentation/copyright.txt

+ @@ -2,7 +2,7 @@

+  

+  COPYRIGHT

+  ---------

+ -Copyright (C) 2016 - 2020, Intel Corporation. License GPLv2: GNU GPL

+ +Copyright (C) 2016 - 2022, Intel Corporation. License GPLv2: GNU GPL

+  version 2 <http://gnu.org/licenses/gpl.html>.  This is free software:

+  you are free to change and redistribute it.  There is NO WARRANTY, to

+  the extent permitted by law.

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 2539369..c127326 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -20,27 +20,100 @@ libcxl provides interfaces to interact with CXL devices in Linux, using sysfs

+  interfaces for most kernel interactions, and the ioctl() interface for command

+  submission.

+  

+ -The starting point for all library interfaces is a 'cxl_ctx' object, returned

+ -by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices are children of the

+ -cxl_ctx object, and can be iterated through using an iterator API.

+ +The starting point for all library interfaces is a 'cxl_ctx' object,

+ +returned by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices and other

+ +CXL device objects are descendants of the cxl_ctx object, and can be

+ +iterated via an object an iterator API of the form

+ +cxl_<object>_foreach(<parent object>, <object iterator>).

+  

+ -Library level interfaces that are agnostic to any device, or a specific

+ -subclass of operations have the prefix 'cxl_'

+ +MEMDEVS

+ +-------

+ +The object representing a CXL memory expander (Type 3 device) is 'struct

+ +cxl_memdev'. Library interfaces related to these devices have the prefix

+ +'cxl_memdev_'. These interfaces are mostly associated with sysfs

+ +interactions (unless otherwise noted in their respective documentation

+ +sections). They are typically used to retrieve data published by the

+ +kernel, or to send data or trigger kernel operations for a given device.

+  

+ -The object representing a CXL Type 3 device is 'cxl_memdev'. Library interfaces

+ -related to these devices have the prefix 'cxl_memdev_'. These interfaces are

+ -mostly associated with sysfs interactions (unless otherwise noted in their

+ -respective documentation pages). They are typically used to retrieve data

+ -published by the kernel, or to send data or trigger kernel operations for a

+ -given device.

+ +=== MEMDEV: Enumeration

+ +----

+ +struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);

+ +struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);

+ +struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);

+ +

+ +#define cxl_memdev_foreach(ctx, memdev) \

+ +        for (memdev = cxl_memdev_get_first(ctx); \

+ +             memdev != NULL; \

+ +             memdev = cxl_memdev_get_next(memdev))

+ +

+ +----

+ +

+ +CXL memdev instances are enumerated from the global library context

+ +'struct cxl_ctx'. By default a memdev only offers a portal to submit

+ +memory device commands, see the port, decoder, and endpoint APIs to

+ +determine what if any CXL Memory Resources are reachable given a

+ +specific memdev.

+ +

+ +=== MEMDEV: Attributes

+ +----

+ +int cxl_memdev_get_id(struct cxl_memdev *memdev);

+ +unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);

+ +const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);

+ +int cxl_memdev_get_major(struct cxl_memdev *memdev);

+ +int cxl_memdev_get_minor(struct cxl_memdev *memdev);

+ +unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);

+ +unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);

+ +const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+ +size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);

+ +int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);

+ +----

+ +

+ +A memdev is given a kernel device name of the form "mem%d" where an id

+ +(cxl_memdev_get_id()) is dynamically allocated as devices are

+ +discovered. Note that there are no guarantees that ids / kernel device

+ +names for memdevs are stable from one boot to the next, devices are

+ +enumerated asynchronously. If a stable identifier is use

+ +cxl_memdev_get_serial() which returns a value according to the 'Device

+ +Serial Number Extended Capability' in the PCIe 5.0 Base Specification.

+ +

+ +The character device node for command submission can be found by default

+ +at /dev/cxl/mem%d, or created with a major / minor returned from

+ +cxl_memdev_get_{major,minor}().

+ +

+ +The 'pmem_size' and 'ram_size' attributes return the current

+ +provisioning of DPA (Device Physical Address / local capacity) in the

+ +device.

+ +

+ +=== MEMDEV: Commands

+ +----

+ +struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ +struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);

+ +struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev);

+ +struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,

+ +					unsigned int offset, unsigned int length);

+ +struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev, void *buf,

+ +					unsigned int offset, unsigned int length);

+ +int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,

+ +			  size_t offset);

+ +int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length,

+ +			  size_t offset);

+ +int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,

+ +			   size_t offset);

+ +

+ +----

+  

+  A 'cxl_cmd' is a reference counted object which is used to perform 'Mailbox'

+  commands as described in the CXL Specification. A 'cxl_cmd' object is tied to a

+  'cxl_memdev'. Associated library interfaces have the prefix 'cxl_cmd_'. Within

+  this sub-class of interfaces, there are:

+  

+ - * 'cxl_cmd_new_*' interfaces that allocate a new cxl_cmd object for a given

+ -   command type.

+ + * 'cxl_cmd_new_*()' interfaces that allocate a new cxl_cmd object for a given

+ +   command type targeted at a given memdev. As part of the command

+ +   instantiation process the library validates that the command is

+ +   supported by the memory device, otherwise it returns NULL to indicate

+ +   'no support'. The libcxl command id is translated by the kernel into

+ +   a CXL standard opcode. See the potential command ids in

+ +   /usr/include/linux/cxl_mem.h.

+  

+   * 'cxl_cmd_submit' which submits the command via ioctl()

+  

+ @@ -49,6 +122,18 @@ this sub-class of interfaces, there are:

+  

+   * 'cxl_cmd_get_*' interfaces to get general command related information.

+  

+ +cxl_cmd_new_raw() supports so called 'RAW' commands where the command id

+ +is 'RAW' and it carries an unmodified CXL memory device command payload

+ +associated with the 'opcode' argument. Given the kernel does minimal

+ +input validation on these commands typically raw commands are not

+ +supported by the kernel outside debug build scenarios. libcxl is limited

+ +to supporting commands that appear in the CXL standard / public

+ +specifications.

+ +

+ +cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple

+ +label access commands over an arbitrary extent of the device's label

+ +area.

+ +

+  include::../../copyright.txt[]

+  

+  SEE ALSO

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,739 @@ 

+ From 9dce91c303720a336c55ecdc2e01e423589b85b2 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:02 -0800

+ Subject: [PATCH 100/217] cxl/list: Add bus objects

+ 

+ A 'struct cxl_bus' represents a CXL.mem domain. It is the root of a

+ Host-managed Device Memory (HDM) hierarchy. When memory devices are enabled

+ for CXL operation they appear underneath a bus in a 'cxl list -BM' listing,

+ otherwise they display as disconnected.

+ 

+ A 'bus' is identical to the kernel's CXL root port object, but given the

+ confusion between CXL root ports, and PCIe root ports, the 'bus' name is

+ less ambiguous. It also serves a similar role in the object hierarchy as a

+ 'struct ndctl_bus' object. It is also the case that the "root" name will

+ appear as the kernel device-name, so the association will be clear.

+ 

+ Link: https://lore.kernel.org/r/164298558278.3021641.16323855851736615358.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format                    |   1 +

+  Documentation/cxl/cxl-list.txt   |  88 ++++++++++++++++---

+  Documentation/cxl/lib/libcxl.txt |  30 +++++++

+  cxl/filter.c                     | 117 ++++++++++++++++++++++++-

+  cxl/filter.h                     |   2 +

+  cxl/json.c                       |  21 +++++

+  cxl/json.h                       |   5 +-

+  cxl/lib/libcxl.c                 | 142 +++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |   5 ++

+  cxl/lib/private.h                |  14 +++

+  cxl/libcxl.h                     |  11 +++

+  cxl/list.c                       |  19 +++--

+  12 files changed, 431 insertions(+), 24 deletions(-)

+ 

+ diff --git a/.clang-format b/.clang-format

+ index d2e77d0..1154c76 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -78,6 +78,7 @@ ExperimentalAutoDetectBinPacking: false

+  # 	| sort -u)

+  ForEachMacros:

+    - 'cxl_memdev_foreach'

+ +  - 'cxl_bus_foreach'

+    - 'daxctl_dev_foreach'

+    - 'daxctl_mapping_foreach'

+    - 'daxctl_region_foreach'

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 224c972..be131ae 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -15,17 +15,60 @@ SYNOPSIS

+  Walk the CXL capable device hierarchy in the system and list all device

+  instances along with some of their major attributes.

+  

+ -Options can be specified to limit the output to specific objects.

+ +Options can be specified to limit the output to specific objects. When a

+ +single object type is specified the return json object is an array of

+ +just those objects, when multiple objects types are specified the

+ +returned the returned object may be an array of arrays with the inner

+ +array named for the given object type.

+ +

+ +Filters can by specifed as either a single identidier, a space separated

+ +quoted string, or a comma separated list. When multiple filter

+ +identifiers are specified within a filter string, like "-m

+ +mem0,mem1,mem2", they are combined as an 'OR' filter.  When multiple

+ +filter string types are specified, like "-m mem0,mem1,mem2 -p port10",

+ +they are combined as an 'AND' filter. So, "-m mem0,mem1,mem2 -p port10"

+ +would only list objects that are beneath port10 AND map mem0, mem1, OR

+ +mem2.

+ +

+ +The --human option in addition to reformatting some fields to more human

+ +friendly strings also unwraps the array to reduce the number of lines of

+ +output.

+  

+  EXAMPLE

+  -------

+  ----

+  # cxl list --memdevs

+ -{

+ -  "memdev":"mem0",

+ -  "pmem_size":268435456,

+ -  "ram_size":0,

+ -}

+ +[

+ +  {

+ +    "memdev":"mem0",

+ +    "pmem_size":268435456,

+ +    "ram_size":0,

+ +    "serial":0

+ +  }

+ +]

+ +

+ +# cxl list -BMu

+ +[

+ +  {

+ +    "anon memdevs":[

+ +      {

+ +        "memdev":"mem0",

+ +        "pmem_size":"256.00 MiB (268.44 MB)",

+ +        "ram_size":0,

+ +        "serial":"0"

+ +      }

+ +    ]

+ +  },

+ +  {

+ +    "buses":[

+ +      {

+ +        "bus":"root0",

+ +        "provider":"ACPI.CXL"

+ +      }

+ +    ]

+ +  }

+ +]

+ +

+  ----

+  

+  OPTIONS

+ @@ -34,13 +77,6 @@ OPTIONS

+  --memdev=::

+  	Specify CXL memory device name(s), or device id(s), to filter the listing. For example:

+  ----

+ -# cxl list --memdev=mem0

+ -{

+ -  "memdev":"mem0",

+ -  "pmem_size":268435456,

+ -  "ram_size":0,

+ -}

+ -

+  # cxl list -M --memdev="0 mem3 5"

+  [

+    {

+ @@ -114,6 +150,32 @@ OPTIONS

+  ]

+  ----

+  

+ +-B::

+ +--buses::

+ +	Include 'bus' / CXL root object(s) in the listing. Typically, on ACPI

+ +	systems the bus object is a singleton associated with the ACPI0017

+ +	device, but there are test scenerios where there may be multiple CXL

+ +	memory hierarchies.

+ +----

+ +# cxl list -B

+ +[

+ +  {

+ +    "bus":"root3",

+ +    "provider":"cxl_test"

+ +  },

+ +  {

+ +    "bus":"root0",

+ +    "provider":"ACPI.CXL"

+ +  }

+ +]

+ +----

+ +

+ +-b::

+ +--bus=::

+ +	Specify CXL root device name(s), device id(s), and / or CXL bus provider

+ +	names to filter the listing. The supported provider names are "ACPI.CXL"

+ +	and "cxl_test".

+ +

+  include::human-option.txt[]

+  

+  include::verbose-option.txt[]

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index c127326..84af66a 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -134,6 +134,36 @@ cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple

+  label access commands over an arbitrary extent of the device's label

+  area.

+  

+ +BUSES

+ +-----

+ +The CXL Memory space is CPU and Device coherent. The address ranges that

+ +support coherent access are described by platform firmware and

+ +communicated to the operating system via a CXL root object 'struct

+ +cxl_bus'.

+ +

+ +=== BUS: Enumeration

+ +----

+ +struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx);

+ +struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);

+ +

+ +#define cxl_bus_foreach(ctx, bus)                                           \

+ +       for (bus = cxl_bus_get_first(ctx); bus != NULL;                      \

+ +            bus = cxl_bus_get_next(bus))

+ +----

+ +

+ +=== BUS: Attributes

+ +----

+ +const char *cxl_bus_get_provider(struct cxl_bus *bus);

+ +const char *cxl_bus_get_devname(struct cxl_bus *bus);

+ +int cxl_bus_get_id(struct cxl_bus *bus);

+ +----

+ +

+ +The provider name of a bus is a persistent name that is independent of

+ +discovery order. The possible provider names are 'ACPI.CXL' and

+ +'cxl_test'. The devname and id attributes, like other objects, are just

+ +the kernel device names that are subject to change based on discovery

+ +order.

+ +

+  include::../../copyright.txt[]

+  

+  SEE ALSO

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 26efc65..5f4844b 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -1,5 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+ -// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.

+ +// Copyright (C) 2015-2022 Intel Corporation. All rights reserved.

+  #include <errno.h>

+  #include <stdio.h>

+  #include <string.h>

+ @@ -21,6 +21,43 @@ static const char *which_sep(const char *filter)

+  	return " ";

+  }

+  

+ +static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,

+ +					   const char *__ident)

+ +{

+ +	char *ident, *save;

+ +	const char *arg;

+ +	int bus_id;

+ +

+ +	if (!__ident)

+ +		return bus;

+ +

+ +	ident = strdup(__ident);

+ +	if (!ident)

+ +		return NULL;

+ +

+ +	for (arg = strtok_r(ident, which_sep(__ident), &save); arg;

+ +	     arg = strtok_r(NULL, which_sep(__ident), &save)) {

+ +		if (strcmp(arg, "all") == 0)

+ +			break;

+ +

+ +		if ((sscanf(arg, "%d", &bus_id) == 1 ||

+ +		     sscanf(arg, "root%d", &bus_id) == 1) &&

+ +		    cxl_bus_get_id(bus) == bus_id)

+ +			break;

+ +

+ +		if (strcmp(arg, cxl_bus_get_devname(bus)) == 0)

+ +			break;

+ +

+ +		if (strcmp(arg, cxl_bus_get_provider(bus)) == 0)

+ +			break;

+ +	}

+ +

+ +	free(ident);

+ +	if (arg)

+ +		return bus;

+ +	return NULL;

+ +}

+ +

+  static struct cxl_memdev *

+  util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials)

+  {

+ @@ -98,21 +135,67 @@ static unsigned long params_to_flags(struct cxl_filter_params *param)

+  	return flags;

+  }

+  

+ +static void splice_array(struct cxl_filter_params *p, struct json_object *jobjs,

+ +			 struct json_object *platform,

+ +			 const char *container_name, bool do_container)

+ +{

+ +	size_t count;

+ +

+ +	if (!json_object_array_length(jobjs)) {

+ +		json_object_put(jobjs);

+ +		return;

+ +	}

+ +

+ +	if (do_container) {

+ +		struct json_object *container = json_object_new_object();

+ +

+ +		if (!container) {

+ +			err(p, "failed to list: %s\n", container_name);

+ +			return;

+ +		}

+ +

+ +		json_object_object_add(container, container_name, jobjs);

+ +		json_object_array_add(platform, container);

+ +		return;

+ +	}

+ +

+ +	for (count = json_object_array_length(jobjs); count; count--) {

+ +		struct json_object *jobj = json_object_array_get_idx(jobjs, 0);

+ +

+ +		json_object_get(jobj);

+ +		json_object_array_del_idx(jobjs, 0, 1);

+ +		json_object_array_add(platform, jobj);

+ +	}

+ +	json_object_put(jobjs);

+ +}

+ +

+  int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  {

+  	struct json_object *jplatform = json_object_new_array();

+ +	struct json_object *jdevs = NULL, *jbuses = NULL;

+  	unsigned long flags = params_to_flags(p);

+  	struct cxl_memdev *memdev;

+ +	int top_level_objs = 0;

+ +	struct cxl_bus *bus;

+  

+  	if (!jplatform) {

+  		dbg(p, "platform object allocation failure\n");

+  		return -ENOMEM;

+  	}

+  

+ +	jdevs = json_object_new_array();

+ +	if (!jdevs)

+ +		goto err;

+ +

+ +	jbuses = json_object_new_array();

+ +	if (!jbuses)

+ +		goto err;

+ +

+  	cxl_memdev_foreach(ctx, memdev) {

+  		struct json_object *jdev;

+  

+ -		if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter))

+ +		if (!util_cxl_memdev_filter(memdev, p->memdev_filter,

+ +					    p->serial_filter))

+  			continue;

+  		if (p->memdevs) {

+  			jdev = util_cxl_memdev_to_json(memdev, flags);

+ @@ -120,11 +203,39 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  				dbg(p, "memdev object allocation failure\n");

+  				continue;

+  			}

+ -			json_object_array_add(jplatform, jdev);

+ +			json_object_array_add(jdevs, jdev);

+ +		}

+ +	}

+ +

+ +	cxl_bus_foreach(ctx, bus) {

+ +		struct json_object *jbus;

+ +

+ +		if (!util_cxl_bus_filter(bus, p->bus_filter))

+ +			continue;

+ +		if (p->buses) {

+ +			jbus = util_cxl_bus_to_json(bus, flags);

+ +			if (!jbus) {

+ +				dbg(p, "bus object allocation failure\n");

+ +				continue;

+ +			}

+ +			json_object_array_add(jbuses, jbus);

+  		}

+  	}

+  

+ +	if (json_object_array_length(jdevs))

+ +		top_level_objs++;

+ +	if (json_object_array_length(jbuses))

+ +		top_level_objs++;

+ +

+ +	splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);

+ +	splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);

+ +

+  	util_display_json_array(stdout, jplatform, flags);

+  

+  	return 0;

+ +err:

+ +	json_object_put(jdevs);

+ +	json_object_put(jbuses);

+ +	json_object_put(jplatform);

+ +	return -ENOMEM;

+  }

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 12d9344..d41e757 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -9,7 +9,9 @@

+  struct cxl_filter_params {

+  	const char *memdev_filter;

+  	const char *serial_filter;

+ +	const char *bus_filter;

+  	bool memdevs;

+ +	bool buses;

+  	bool idle;

+  	bool human;

+  	bool health;

+ diff --git a/cxl/json.c b/cxl/json.c

+ index d8e65df..a584594 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -221,3 +221,24 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  	}

+  	return jdev;

+  }

+ +

+ +struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+ +					 unsigned long flags)

+ +{

+ +	const char *devname = cxl_bus_get_devname(bus);

+ +	struct json_object *jbus, *jobj;

+ +

+ +	jbus = json_object_new_object();

+ +	if (!jbus)

+ +		return NULL;

+ +

+ +	jobj = json_object_new_string(devname);

+ +	if (jobj)

+ +		json_object_object_add(jbus, "bus", jobj);

+ +

+ +	jobj = json_object_new_string(cxl_bus_get_provider(bus));

+ +	if (jobj)

+ +		json_object_object_add(jbus, "provider", jobj);

+ +

+ +	return jbus;

+ +}

+ diff --git a/cxl/json.h b/cxl/json.h

+ index 3abcfe6..4abf6e5 100644

+ --- a/cxl/json.h

+ +++ b/cxl/json.h

+ @@ -1,8 +1,11 @@

+  /* SPDX-License-Identifier: GPL-2.0 */

+ -/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */

+ +/* Copyright (C) 2015-2022 Intel Corporation. All rights reserved. */

+  #ifndef __CXL_UTIL_JSON_H__

+  #define __CXL_UTIL_JSON_H__

+  struct cxl_memdev;

+  struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  		unsigned long flags);

+ +struct cxl_bus;

+ +struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+ +					 unsigned long flags);

+  #endif /* __CXL_UTIL_JSON_H__ */

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 9839f26..8548a45 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -40,7 +40,9 @@ struct cxl_ctx {

+  	int refcount;

+  	void *userdata;

+  	int memdevs_init;

+ +	int buses_init;

+  	struct list_head memdevs;

+ +	struct list_head buses;

+  	struct kmod_ctx *kmod_ctx;

+  	void *private_data;

+  };

+ @@ -64,6 +66,21 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+  	free(memdev);

+  }

+  

+ +static void __free_port(struct cxl_port *port, struct list_head *head)

+ +{

+ +	if (head)

+ +		list_del_from(head, &port->list);

+ +	free(port->dev_buf);

+ +	free(port->dev_path);

+ +	free(port->uport);

+ +}

+ +

+ +static void free_bus(struct cxl_bus *bus, struct list_head *head)

+ +{

+ +	__free_port(&bus->port, head);

+ +	free(bus);

+ +}

+ +

+  /**

+   * cxl_get_userdata - retrieve stored data pointer from library context

+   * @ctx: cxl library context

+ @@ -130,6 +147,7 @@ CXL_EXPORT int cxl_new(struct cxl_ctx **ctx)

+  	dbg(c, "log_priority=%d\n", c->ctx.log_priority);

+  	*ctx = c;

+  	list_head_init(&c->memdevs);

+ +	list_head_init(&c->buses);

+  	c->kmod_ctx = kmod_ctx;

+  

+  	return 0;

+ @@ -160,6 +178,7 @@ CXL_EXPORT struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx)

+  CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)

+  {

+  	struct cxl_memdev *memdev, *_d;

+ +	struct cxl_bus *bus, *_b;

+  

+  	if (ctx == NULL)

+  		return;

+ @@ -170,6 +189,9 @@ CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)

+  	list_for_each_safe(&ctx->memdevs, memdev, _d, list)

+  		free_memdev(memdev, &ctx->memdevs);

+  

+ +	list_for_each_safe(&ctx->buses, bus, _b, port.list)

+ +		free_bus(bus, &ctx->buses);

+ +

+  	kmod_unref(ctx->kmod_ctx);

+  	info(ctx, "context %p released\n", ctx);

+  	free(ctx);

+ @@ -449,6 +471,126 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)

+  	return is_enabled(path);

+  }

+  

+ +static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,

+ +			 const char *cxlport_base)

+ +{

+ +	char *path = calloc(1, strlen(cxlport_base) + 100);

+ +	size_t rc;

+ +

+ +	if (!path)

+ +		return -ENOMEM;

+ +

+ +	port->id = id;

+ +	port->ctx = ctx;

+ +

+ +	port->dev_path = strdup(cxlport_base);

+ +	if (!port->dev_path)

+ +		goto err;

+ +

+ +	port->dev_buf = calloc(1, strlen(cxlport_base) + 50);

+ +	if (!port->dev_buf)

+ +		goto err;

+ +	port->buf_len = strlen(cxlport_base) + 50;

+ +

+ +	rc = snprintf(port->dev_buf, port->buf_len, "%s/uport", cxlport_base);

+ +	if (rc >= port->buf_len)

+ +		goto err;

+ +	port->uport = realpath(port->dev_buf, NULL);

+ +	if (!port->uport)

+ +		goto err;

+ +

+ +	return 0;

+ +err:

+ +	free(port->dev_path);

+ +	free(port->dev_buf);

+ +	free(path);

+ +	return -ENOMEM;

+ +}

+ +

+ +static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)

+ +{

+ +	const char *devname = devpath_to_devname(cxlbus_base);

+ +	struct cxl_bus *bus, *bus_dup;

+ +	struct cxl_ctx *ctx = parent;

+ +	struct cxl_port *port;

+ +	int rc;

+ +

+ +	dbg(ctx, "%s: base: \'%s\'\n", devname, cxlbus_base);

+ +

+ +	bus = calloc(1, sizeof(*bus));

+ +	if (!bus)

+ +		return NULL;

+ +

+ +	port = &bus->port;

+ +	rc = cxl_port_init(port, ctx, id, cxlbus_base);

+ +	if (rc)

+ +		goto err;

+ +

+ +	cxl_bus_foreach(ctx, bus_dup)

+ +		if (bus_dup->port.id == bus->port.id) {

+ +			free_bus(bus, NULL);

+ +			return bus_dup;

+ +		}

+ +

+ +	list_add(&ctx->buses, &port->list);

+ +	return bus;

+ +

+ +err:

+ +	free(bus);

+ +	return NULL;

+ +}

+ +

+ +static void cxl_buses_init(struct cxl_ctx *ctx)

+ +{

+ +	if (ctx->buses_init)

+ +		return;

+ +

+ +	ctx->buses_init = 1;

+ +

+ +	sysfs_device_parse(ctx, "/sys/bus/cxl/devices", "root", ctx,

+ +			   add_cxl_bus);

+ +}

+ +

+ +CXL_EXPORT struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx)

+ +{

+ +	cxl_buses_init(ctx);

+ +

+ +	return list_top(&ctx->buses, struct cxl_bus, port.list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus)

+ +{

+ +	struct cxl_ctx *ctx = bus->port.ctx;

+ +

+ +	return list_next(&ctx->buses, bus, port.list);

+ +}

+ +

+ +CXL_EXPORT const char *cxl_bus_get_devname(struct cxl_bus *bus)

+ +{

+ +	struct cxl_port *port = &bus->port;

+ +

+ +	return devpath_to_devname(port->dev_path);

+ +}

+ +

+ +CXL_EXPORT int cxl_bus_get_id(struct cxl_bus *bus)

+ +{

+ +	struct cxl_port *port = &bus->port;

+ +

+ +	return port->id;

+ +}

+ +

+ +CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus)

+ +{

+ +	struct cxl_port *port = &bus->port;

+ +	const char *devname = devpath_to_devname(port->uport);

+ +

+ +	if (strcmp(devname, "ACPI0017:00") == 0)

+ +		return "ACPI.CXL";

+ +	if (strcmp(devname, "cxl_acpi.0") == 0)

+ +		return "cxl_test";

+ +	return devname;

+ +}

+ +

+  CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)

+  {

+  	if (!cmd)

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 4411035..781ff99 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -77,4 +77,9 @@ local:

+  LIBCXL_2 {

+  global:

+  	cxl_memdev_get_serial;

+ +	cxl_bus_get_first;

+ +	cxl_bus_get_next;

+ +	cxl_bus_get_provider;

+ +	cxl_bus_get_devname;

+ +	cxl_bus_get_id;

+  } LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 7c81e24..0758d05 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -34,6 +34,20 @@ struct cxl_memdev {

+  	unsigned long long serial;

+  };

+  

+ +struct cxl_port {

+ +	int id;

+ +	void *dev_buf;

+ +	size_t buf_len;

+ +	char *dev_path;

+ +	char *uport;

+ +	struct cxl_ctx *ctx;

+ +	struct list_node list;

+ +};

+ +

+ +struct cxl_bus {

+ +	struct cxl_port port;

+ +};

+ +

+  enum cxl_cmd_query_status {

+  	CXL_CMD_QUERY_NOT_RUN = 0,

+  	CXL_CMD_QUERY_OK,

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index bcdede8..da66eb2 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -57,6 +57,17 @@ int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,

+               memdev != NULL; \

+               memdev = cxl_memdev_get_next(memdev))

+  

+ +struct cxl_bus;

+ +struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx);

+ +struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);

+ +const char *cxl_bus_get_provider(struct cxl_bus *bus);

+ +const char *cxl_bus_get_devname(struct cxl_bus *bus);

+ +int cxl_bus_get_id(struct cxl_bus *bus);

+ +

+ +#define cxl_bus_foreach(ctx, bus)                                              \

+ +	for (bus = cxl_bus_get_first(ctx); bus != NULL;                        \

+ +	     bus = cxl_bus_get_next(bus))

+ +

+  struct cxl_cmd;

+  const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);

+  struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 7e2744d..9500e61 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -1,5 +1,5 @@

+  // SPDX-License-Identifier: GPL-2.0

+ -/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */

+ +/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */

+  #include <stdio.h>

+  #include <errno.h>

+  #include <stdlib.h>

+ @@ -14,11 +14,6 @@

+  

+  static struct cxl_filter_params param;

+  

+ -static int num_list_flags(void)

+ -{

+ -	return param.memdevs;

+ -}

+ -

+  static const struct option options[] = {

+  	OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name(s)",

+  		   "filter by CXL memory device name(s)"),

+ @@ -27,6 +22,9 @@ static const struct option options[] = {

+  		   "filter by CXL memory device serial number(s)"),

+  	OPT_BOOLEAN('M', "memdevs", &param.memdevs,

+  		    "include CXL memory device info"),

+ +	OPT_STRING('b', "bus", &param.bus_filter, "bus device name",

+ +		   "filter by CXL bus device name(s)"),

+ +	OPT_BOOLEAN('B', "buses", &param.buses, "include CXL bus info"),

+  	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+  	OPT_BOOLEAN('u', "human", &param.human,

+  		    "use human friendly number formats "),

+ @@ -35,6 +33,11 @@ static const struct option options[] = {

+  	OPT_END(),

+  };

+  

+ +static int num_list_flags(void)

+ +{

+ +       return !!param.memdevs + !!param.buses;

+ +}

+ +

+  int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  {

+  	const char * const u[] = {

+ @@ -53,7 +56,9 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  	if (num_list_flags() == 0) {

+  		if (param.memdev_filter || param.serial_filter)

+  			param.memdevs = true;

+ -		else {

+ +		if (param.bus_filter)

+ +			param.buses = true;

+ +		if (num_list_flags() == 0) {

+  			/*

+  			 * TODO: We likely want to list regions by default if

+  			 * nothing was explicitly asked for. But until we have

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,44 @@ 

+ From 91f78bbcda7fc644041dfabfa679c6a627f90e76 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:08 -0800

+ Subject: [PATCH 101/217] util/json: Warn on stderr about empty list results

+ 

+ Help interactive users notice something is wrong with the list parameters

+ by warning that no devices matched the specified filter settings.

+ 

+ Link: https://lore.kernel.org/r/164298558814.3021641.13051269428355986099.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/json.c | 7 +++++--

+  1 file changed, 5 insertions(+), 2 deletions(-)

+ 

+ diff --git a/util/json.c b/util/json.c

+ index bd5f8fc..f8cc81f 100644

+ --- a/util/json.c

+ +++ b/util/json.c

+ @@ -3,6 +3,7 @@

+  #include <limits.h>

+  #include <string.h>

+  #include <stdio.h>

+ +#include <util/util.h>

+  #include <util/json.h>

+  #include <json-c/json.h>

+  #include <json-c/printbuf.h>

+ @@ -95,9 +96,11 @@ void util_display_json_array(FILE *f_out, struct json_object *jarray,

+  	int len = json_object_array_length(jarray);

+  	int jflag = JSON_C_TO_STRING_PRETTY;

+  

+ -	if (json_object_array_length(jarray) > 1 || !(flags & UTIL_JSON_HUMAN))

+ +	if (len > 1 || !(flags & UTIL_JSON_HUMAN)) {

+ +		if (len == 0)

+ +			warning("no matching devices found\n");

+  		fprintf(f_out, "%s\n", json_object_to_json_string_ext(jarray, jflag));

+ -	else if (len) {

+ +	} else if (len) {

+  		struct json_object *jobj;

+  

+  		jobj = json_object_array_get_idx(jarray, 0);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,165 @@ 

+ From ecd7e6e7aabfa2592f3f739a725d135eb43d6314 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:13 -0800

+ Subject: [PATCH 102/217] util/sysfs: Uplevel modalias lookup helper to util/

+ 

+ The to_module() helper looks up modules relative to a modalias. Uplevel

+ this to share with libcxl.

+ 

+ Link: https://lore.kernel.org/r/164298559346.3021641.11059026790676662837.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 33 +++++----------------------------

+  util/sysfs.c         | 27 +++++++++++++++++++++++++++

+  util/sysfs.h         |  8 ++++++++

+  3 files changed, 40 insertions(+), 28 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 47a234c..1374ad9 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -1668,7 +1668,6 @@ static enum ndctl_fwa_result fwa_result_to_result(const char *result)

+  static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,

+  		const char *devname);

+  static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath);

+ -static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias);

+  

+  static int populate_dimm_attributes(struct ndctl_dimm *dimm,

+  				    const char *dimm_base,

+ @@ -1878,7 +1877,7 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)

+  	sprintf(path, "%s/modalias", dimm_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+ -	dimm->module = to_module(ctx, buf);

+ +	dimm->module = util_modalias_to_module(ctx, buf);

+  

+  	dimm->handle = -1;

+  	dimm->phys_id = -1;

+ @@ -2597,7 +2596,7 @@ static void *add_region(void *parent, int id, const char *region_base)

+  	sprintf(path, "%s/modalias", region_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+ -	region->module = to_module(ctx, buf);

+ +	region->module = util_modalias_to_module(ctx, buf);

+  

+  	sprintf(path, "%s/numa_node", region_base);

+  	if ((rc = sysfs_read_attr(ctx, path, buf)) == 0)

+ @@ -3885,28 +3884,6 @@ NDCTL_EXPORT struct ndctl_ctx *ndctl_mapping_get_ctx(

+  	return ndctl_mapping_get_bus(mapping)->ctx;

+  }

+  

+ -static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias)

+ -{

+ -	struct kmod_list *list = NULL;

+ -	struct kmod_module *mod;

+ -	int rc;

+ -

+ -	if (!ctx->kmod_ctx)

+ -		return NULL;

+ -

+ -	rc = kmod_module_new_from_lookup(ctx->kmod_ctx, alias, &list);

+ -	if (rc < 0 || !list) {

+ -		dbg(ctx, "failed to find module for alias: %s %d list: %s\n",

+ -				alias, rc, list ? "populated" : "empty");

+ -		return NULL;

+ -	}

+ -	mod = kmod_module_get_module(list);

+ -	dbg(ctx, "alias: %s module: %s\n", alias, kmod_module_get_name(mod));

+ -	kmod_module_unref_list(list);

+ -

+ -	return mod;

+ -}

+ -

+  static char *get_block_device(struct ndctl_ctx *ctx, const char *block_path)

+  {

+  	char *bdev_name = NULL;

+ @@ -4069,7 +4046,7 @@ static void *add_namespace(void *parent, int id, const char *ndns_base)

+  	sprintf(path, "%s/modalias", ndns_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+ -	ndns->module = to_module(ctx, buf);

+ +	ndns->module = util_modalias_to_module(ctx, buf);

+  

+  	ndctl_namespace_foreach(region, ndns_dup)

+  		if (ndns_dup->id == ndns->id) {

+ @@ -5182,7 +5159,7 @@ static void *add_btt(void *parent, int id, const char *btt_base)

+  	sprintf(path, "%s/modalias", btt_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+ -	btt->module = to_module(ctx, buf);

+ +	btt->module = util_modalias_to_module(ctx, buf);

+  

+  	sprintf(path, "%s/uuid", btt_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+ @@ -5533,7 +5510,7 @@ static void *__add_pfn(struct ndctl_pfn *pfn, const char *pfn_base)

+  	sprintf(path, "%s/modalias", pfn_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+ -	pfn->module = to_module(ctx, buf);

+ +	pfn->module = util_modalias_to_module(ctx, buf);

+  

+  	sprintf(path, "%s/uuid", pfn_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+ diff --git a/util/sysfs.c b/util/sysfs.c

+ index cfbab7d..23330cb 100644

+ --- a/util/sysfs.c

+ +++ b/util/sysfs.c

+ @@ -10,6 +10,7 @@

+  #include <ctype.h>

+  #include <fcntl.h>

+  #include <dirent.h>

+ +#include <libkmod.h>

+  #include <sys/stat.h>

+  #include <sys/types.h>

+  #include <sys/ioctl.h>

+ @@ -118,3 +119,29 @@ int __sysfs_device_parse(struct log_ctx *ctx, const char *base_path,

+  

+  	return add_errors;

+  }

+ +

+ +struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,

+ +					      const char *alias,

+ +					      struct log_ctx *log)

+ +{

+ +	struct kmod_list *list = NULL;

+ +	struct kmod_module *mod;

+ +	int rc;

+ +

+ +	if (!kmod_ctx)

+ +		return NULL;

+ +

+ +	rc = kmod_module_new_from_lookup(kmod_ctx, alias, &list);

+ +	if (rc < 0 || !list) {

+ +		log_dbg(log,

+ +			"failed to find module for alias: %s %d list: %s\n",

+ +			alias, rc, list ? "populated" : "empty");

+ +		return NULL;

+ +	}

+ +	mod = kmod_module_get_module(list);

+ +	log_dbg(log, "alias: %s module: %s\n", alias,

+ +		kmod_module_get_name(mod));

+ +	kmod_module_unref_list(list);

+ +

+ +	return mod;

+ +}

+ diff --git a/util/sysfs.h b/util/sysfs.h

+ index 6485a73..bdee4f5 100644

+ --- a/util/sysfs.h

+ +++ b/util/sysfs.h

+ @@ -27,4 +27,12 @@ static inline const char *devpath_to_devname(const char *devpath)

+  {

+  	return strrchr(devpath, '/') + 1;

+  }

+ +

+ +struct kmod_ctx;

+ +struct kmod_module;

+ +struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,

+ +					      const char *alias,

+ +					      struct log_ctx *log);

+ +#define util_modalias_to_module(ctx, buf)                                      \

+ +	__util_modalias_to_module((ctx)->kmod_ctx, buf, &(ctx)->ctx)

+  #endif /* __UTIL_SYSFS_H__ */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,862 @@ 

+ From fef3f05ca8cdfd8d783162042d5cf20325c8b64b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:18 -0800

+ Subject: [PATCH 103/217] cxl/list: Add port enumeration

+ 

+ Between a cxl_bus (root port) and an endpoint there can be an arbitrary

+ level of switches. Add enumeration for these ports at each level of the

+ hierarchy.

+ 

+ However, given the CXL root ports are also "ports" infer that if the port

+ filter argument is the word "root" or "root%d" then include root ports in

+ the listing. The keyword "switch" is also provided to filter only the ports

+ beneath the root that are not endpoint ports.

+ 

+ Link: https://lore.kernel.org/r/164298559854.3021641.17724828997703051001.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format                    |   1 +

+  Documentation/cxl/cxl-list.txt   |  24 ++++

+  Documentation/cxl/lib/libcxl.txt |  42 ++++++

+  cxl/filter.c                     | 224 ++++++++++++++++++++++++++++++-

+  cxl/filter.h                     |   4 +

+  cxl/json.c                       |  23 ++++

+  cxl/json.h                       |   3 +

+  cxl/lib/libcxl.c                 | 160 +++++++++++++++++++++-

+  cxl/lib/libcxl.sym               |  12 ++

+  cxl/lib/private.h                |  11 ++

+  cxl/libcxl.h                     |  19 +++

+  cxl/list.c                       |  17 ++-

+  12 files changed, 534 insertions(+), 6 deletions(-)

+ 

+ diff --git a/.clang-format b/.clang-format

+ index 1154c76..391cd34 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -79,6 +79,7 @@ ExperimentalAutoDetectBinPacking: false

+  ForEachMacros:

+    - 'cxl_memdev_foreach'

+    - 'cxl_bus_foreach'

+ +  - 'cxl_port_foreach'

+    - 'daxctl_dev_foreach'

+    - 'daxctl_mapping_foreach'

+    - 'daxctl_region_foreach'

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index be131ae..3076deb 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -176,6 +176,30 @@ OPTIONS

+  	names to filter the listing. The supported provider names are "ACPI.CXL"

+  	and "cxl_test".

+  

+ +-P::

+ +--ports::

+ +	Include port objects (CXL / PCIe root ports + Upstream Switch Ports) in

+ +	the listing.

+ +

+ +-p::

+ +--port=::

+ +	Specify CXL Port device name(s), device id(s), and or port type

+ +	names to filter the listing. The supported port type names are "root"

+ +	and "switch". Note that since a bus object is also a port, the following

+ +	two syntaxes are equivalent:

+ +----

+ +# cxl list -B

+ +# cxl list -P -p root

+ +----

+ +	By default, only 'switch' ports are listed.

+ +

+ +-S::

+ +--single::

+ +	Specify whether the listing should emit all the objects that are

+ +	descendants of a port that matches the port filter, or only direct

+ +	descendants of the individual ports that match the filter. By default

+ +	all descendant objects are listed.

+ +

+  include::human-option.txt[]

+  

+  include::verbose-option.txt[]

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 84af66a..804e9ca 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -164,6 +164,48 @@ discovery order. The possible provider names are 'ACPI.CXL' and

+  the kernel device names that are subject to change based on discovery

+  order.

+  

+ +PORTS

+ +-----

+ +CXL ports track the PCIe hierarchy between a platform firmware CXL root

+ +object, through CXL / PCIe Host Bridges, CXL / PCIe Root Ports, and CXL

+ +/ PCIe Switch Ports.

+ +

+ +=== PORT: Enumeration

+ +----

+ +struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);

+ +struct cxl_port *cxl_port_get_first(struct cxl_port *parent);

+ +struct cxl_port *cxl_port_get_next(struct cxl_port *port);

+ +struct cxl_port *cxl_port_get_parent(struct cxl_port *port);

+ +struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+ +struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);

+ +

+ +#define cxl_port_foreach(parent, port)                                      \

+ +       for (port = cxl_port_get_first(parent); port != NULL;                \

+ +            port = cxl_port_get_next(port))

+ +----

+ +A bus object encapsulates a CXL port object. Use cxl_bus_get_port() to

+ +use generic port APIs on root objects.

+ +

+ +Ports are hierarchical. All but the a root object have another CXL port

+ +as a parent object retrievable via cxl_port_get_parent().

+ +

+ +The root port of a hiearchy can be retrieved via any port instance in

+ +that hierarchy via cxl_port_get_bus().

+ +

+ +=== PORT: Attributes

+ +----

+ +const char *cxl_port_get_devname(struct cxl_port *port);

+ +int cxl_port_get_id(struct cxl_port *port);

+ +int cxl_port_is_enabled(struct cxl_port *port);

+ +bool cxl_port_is_root(struct cxl_port *port);

+ +bool cxl_port_is_switch(struct cxl_port *port);

+ +----

+ +The port type is communicated via cxl_port_is_<type>(). An 'enabled' port

+ +is one that has succeeded in discovering the CXL component registers in

+ +the host device and has enumerated its downstream ports. In order for a

+ +memdev to be enabled for CXL memory operation all CXL ports in its

+ +ancestry must also be enabled.

+ +

+  include::../../copyright.txt[]

+  

+  SEE ALSO

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 5f4844b..8b79db3 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -21,6 +21,101 @@ static const char *which_sep(const char *filter)

+  	return " ";

+  }

+  

+ +bool cxl_filter_has(const char *__filter, const char *needle)

+ +{

+ +	char *filter, *save;

+ +	const char *arg;

+ +

+ +	if (!needle)

+ +		return true;

+ +

+ +	if (!__filter)

+ +		return false;

+ +

+ +	filter = strdup(__filter);

+ +	if (!filter)

+ +		return false;

+ +

+ +	for (arg = strtok_r(filter, which_sep(__filter), &save); arg;

+ +	     arg = strtok_r(NULL, which_sep(__filter), &save))

+ +		if (strstr(arg, needle))

+ +			break;

+ +

+ +	free(filter);

+ +	if (arg)

+ +		return true;

+ +	return false;

+ +}

+ +

+ +static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,

+ +					     const char *__ident)

+ +{

+ +	char *ident, *save;

+ +	const char *arg;

+ +	int port_id;

+ +

+ +	if (!__ident)

+ +		return port;

+ +

+ +	ident = strdup(__ident);

+ +	if (!ident)

+ +		return NULL;

+ +

+ +	for (arg = strtok_r(ident, which_sep(__ident), &save); arg;

+ +	     arg = strtok_r(NULL, which_sep(__ident), &save)) {

+ +		if (strcmp(arg, "all") == 0)

+ +			break;

+ +

+ +		if (strcmp(arg, "root") == 0 && cxl_port_is_root(port))

+ +			break;

+ +

+ +		if (strcmp(arg, "switch") == 0 && cxl_port_is_switch(port))

+ +			break;

+ +

+ +		if ((sscanf(arg, "%d", &port_id) == 1 ||

+ +		     sscanf(arg, "port%d", &port_id) == 1) &&

+ +		    cxl_port_get_id(port) == port_id)

+ +			break;

+ +

+ +		if (strcmp(arg, cxl_port_get_devname(port)) == 0)

+ +			break;

+ +	}

+ +

+ +	free(ident);

+ +	if (arg)

+ +		return port;

+ +	return NULL;

+ +}

+ +

+ +enum cxl_port_filter_mode {

+ +	CXL_PF_SINGLE,

+ +	CXL_PF_ANCESTRY,

+ +};

+ +

+ +static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p)

+ +{

+ +	if (p->single)

+ +		return CXL_PF_SINGLE;

+ +	return CXL_PF_ANCESTRY;

+ +}

+ +

+ +static struct cxl_port *util_cxl_port_filter(struct cxl_port *port,

+ +					     const char *ident,

+ +					     enum cxl_port_filter_mode mode)

+ +{

+ +	struct cxl_port *iter = port;

+ +

+ +	while (iter) {

+ +		if (__util_cxl_port_filter(iter, ident))

+ +			return port;

+ +		if (mode == CXL_PF_SINGLE)

+ +			return NULL;

+ +		iter = cxl_port_get_parent(iter);

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+  static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,

+  					   const char *__ident)

+  {

+ @@ -58,6 +153,31 @@ static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,

+  	return NULL;

+  }

+  

+ +static struct cxl_port *util_cxl_port_filter_by_bus(struct cxl_port *port,

+ +						    const char *__ident)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	struct cxl_bus *bus;

+ +

+ +	if (!__ident)

+ +		return port;

+ +

+ +	if (cxl_port_is_root(port)) {

+ +		bus = cxl_port_to_bus(port);

+ +		bus = util_cxl_bus_filter(bus, __ident);

+ +		return bus ? port : NULL;

+ +	}

+ +

+ +	cxl_bus_foreach(ctx, bus) {

+ +		if (!util_cxl_bus_filter(bus, __ident))

+ +			continue;

+ +		if (bus == cxl_port_get_bus(port))

+ +			return port;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+  static struct cxl_memdev *

+  util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials)

+  {

+ @@ -169,10 +289,82 @@ static void splice_array(struct cxl_filter_params *p, struct json_object *jobjs,

+  	json_object_put(jobjs);

+  }

+  

+ +static bool cond_add_put_array(struct json_object *jobj, const char *key,

+ +			       struct json_object *array)

+ +{

+ +	if (jobj && array && json_object_array_length(array) > 0) {

+ +		json_object_object_add(jobj, key, array);

+ +		return true;

+ +	} else {

+ +		json_object_put(array);

+ +		return false;

+ +	}

+ +}

+ +

+ +static bool cond_add_put_array_suffix(struct json_object *jobj, const char *key,

+ +				      const char *suffix,

+ +				      struct json_object *array)

+ +{

+ +	char *name;

+ +	bool rc;

+ +

+ +	if (asprintf(&name, "%s:%s", key, suffix) < 0)

+ +		return false;

+ +	rc = cond_add_put_array(jobj, name, array);

+ +	free(name);

+ +	return rc;

+ +}

+ +

+ +static struct json_object *pick_array(struct json_object *child,

+ +				      struct json_object *container)

+ +{

+ +	if (child)

+ +		return child;

+ +	if (container)

+ +		return container;

+ +	return NULL;

+ +}

+ +

+ +static void walk_child_ports(struct cxl_port *parent_port,

+ +			     struct cxl_filter_params *p,

+ +			     struct json_object *jports,

+ +			     unsigned long flags)

+ +{

+ +	struct cxl_port *port;

+ +

+ +	cxl_port_foreach(parent_port, port) {

+ +		const char *devname = cxl_port_get_devname(port);

+ +		struct json_object *jport = NULL;

+ +		struct json_object *jchildports = NULL;

+ +

+ +		if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))

+ +			goto walk_children;

+ +		if (!util_cxl_port_filter_by_bus(port, p->bus_filter))

+ +			goto walk_children;

+ +		if (!p->idle && !cxl_port_is_enabled(port))

+ +			continue;

+ +		if (p->ports)

+ +			jport = util_cxl_port_to_json(port, flags);

+ +		if (!jport)

+ +			continue;

+ +		json_object_array_add(jports, jport);

+ +		jchildports = json_object_new_array();

+ +		if (!jchildports) {

+ +			err(p, "%s: failed to enumerate child ports\n",

+ +			    devname);

+ +			continue;

+ +		}

+ +walk_children:

+ +		walk_child_ports(port, p, pick_array(jchildports, jports),

+ +				 flags);

+ +		cond_add_put_array_suffix(jport, "ports", devname, jchildports);

+ +	}

+ +}

+ +

+  int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  {

+ +	struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL;

+  	struct json_object *jplatform = json_object_new_array();

+ -	struct json_object *jdevs = NULL, *jbuses = NULL;

+  	unsigned long flags = params_to_flags(p);

+  	struct cxl_memdev *memdev;

+  	int top_level_objs = 0;

+ @@ -191,6 +383,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	if (!jbuses)

+  		goto err;

+  

+ +	jports = json_object_new_array();

+ +	if (!jports)

+ +		goto err;

+ +

+  	cxl_memdev_foreach(ctx, memdev) {

+  		struct json_object *jdev;

+  

+ @@ -208,10 +404,15 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	}

+  

+  	cxl_bus_foreach(ctx, bus) {

+ -		struct json_object *jbus;

+ +		struct json_object *jbus = NULL;

+ +		struct json_object *jchildports = NULL;

+ +		struct cxl_port *port = cxl_bus_get_port(bus);

+ +		const char *devname = cxl_bus_get_devname(bus);

+  

+  		if (!util_cxl_bus_filter(bus, p->bus_filter))

+ -			continue;

+ +			goto walk_children;

+ +		if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))

+ +			goto walk_children;

+  		if (p->buses) {

+  			jbus = util_cxl_bus_to_json(bus, flags);

+  			if (!jbus) {

+ @@ -219,16 +420,32 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  				continue;

+  			}

+  			json_object_array_add(jbuses, jbus);

+ +			if (p->ports) {

+ +				jchildports = json_object_new_array();

+ +				if (!jchildports) {

+ +					err(p,

+ +					    "%s: failed to enumerate child ports\n",

+ +					    devname);

+ +					continue;

+ +				}

+ +			}

+  		}

+ +walk_children:

+ +		walk_child_ports(port, p, pick_array(jchildports, jports),

+ +				 flags);

+ +		cond_add_put_array_suffix(jbus, "ports", devname, jchildports);

+  	}

+  

+  	if (json_object_array_length(jdevs))

+  		top_level_objs++;

+  	if (json_object_array_length(jbuses))

+  		top_level_objs++;

+ +	if (json_object_array_length(jports))

+ +		top_level_objs++;

+  

+  	splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);

+  	splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);

+ +	splice_array(p, jports, jplatform, "ports", top_level_objs > 1);

+  

+  	util_display_json_array(stdout, jplatform, flags);

+  

+ @@ -236,6 +453,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  err:

+  	json_object_put(jdevs);

+  	json_object_put(jbuses);

+ +	json_object_put(jports);

+  	json_object_put(jplatform);

+  	return -ENOMEM;

+  }

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index d41e757..0d83304 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -10,7 +10,10 @@ struct cxl_filter_params {

+  	const char *memdev_filter;

+  	const char *serial_filter;

+  	const char *bus_filter;

+ +	const char *port_filter;

+ +	bool single;

+  	bool memdevs;

+ +	bool ports;

+  	bool buses;

+  	bool idle;

+  	bool human;

+ @@ -22,4 +25,5 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  					  const char *__ident,

+  					  const char *serials);

+  int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);

+ +bool cxl_filter_has(const char *needle, const char *__filter);

+  #endif /* _CXL_UTIL_FILTER_H_ */

+ diff --git a/cxl/json.c b/cxl/json.c

+ index a584594..d9f864e 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -242,3 +242,26 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+  

+  	return jbus;

+  }

+ +

+ +struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+ +					  unsigned long flags)

+ +{

+ +	const char *devname = cxl_port_get_devname(port);

+ +	struct json_object *jport, *jobj;

+ +

+ +	jport = json_object_new_object();

+ +	if (!jport)

+ +		return NULL;

+ +

+ +	jobj = json_object_new_string(devname);

+ +	if (jobj)

+ +		json_object_object_add(jport, "port", jobj);

+ +

+ +	if (!cxl_port_is_enabled(port)) {

+ +		jobj = json_object_new_string("disabled");

+ +		if (jobj)

+ +			json_object_object_add(jport, "state", jobj);

+ +	}

+ +

+ +	return jport;

+ +}

+ diff --git a/cxl/json.h b/cxl/json.h

+ index 4abf6e5..36653db 100644

+ --- a/cxl/json.h

+ +++ b/cxl/json.h

+ @@ -8,4 +8,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  struct cxl_bus;

+  struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+  					 unsigned long flags);

+ +struct cxl_port;

+ +struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+ +					  unsigned long flags);

+  #endif /* __CXL_UTIL_JSON_H__ */

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 8548a45..03eff3c 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -66,15 +66,27 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+  	free(memdev);

+  }

+  

+ +static void free_port(struct cxl_port *port, struct list_head *head);

+  static void __free_port(struct cxl_port *port, struct list_head *head)

+  {

+ +	struct cxl_port *child, *_c;

+ +

+  	if (head)

+  		list_del_from(head, &port->list);

+ +	list_for_each_safe(&port->child_ports, child, _c, list)

+ +		free_port(child, &port->child_ports);

+ +	kmod_module_unref(port->module);

+  	free(port->dev_buf);

+  	free(port->dev_path);

+  	free(port->uport);

+  }

+  

+ +static void free_port(struct cxl_port *port, struct list_head *head)

+ +{

+ +	__free_port(port, head);

+ +	free(port);

+ +}

+ +

+  static void free_bus(struct cxl_bus *bus, struct list_head *head)

+  {

+  	__free_port(&bus->port, head);

+ @@ -471,10 +483,12 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)

+  	return is_enabled(path);

+  }

+  

+ -static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,

+ +static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,

+ +			 enum cxl_port_type type, struct cxl_ctx *ctx, int id,

+  			 const char *cxlport_base)

+  {

+  	char *path = calloc(1, strlen(cxlport_base) + 100);

+ +	char buf[SYSFS_ATTR_SIZE];

+  	size_t rc;

+  

+  	if (!path)

+ @@ -482,6 +496,10 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,

+  

+  	port->id = id;

+  	port->ctx = ctx;

+ +	port->type = type;

+ +	port->parent = parent_port;

+ +

+ +	list_head_init(&port->child_ports);

+  

+  	port->dev_path = strdup(cxlport_base);

+  	if (!port->dev_path)

+ @@ -499,6 +517,10 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,

+  	if (!port->uport)

+  		goto err;

+  

+ +	sprintf(path, "%s/modalias", cxlport_base);

+ +	if (sysfs_read_attr(ctx, path, buf) == 0)

+ +		port->module = util_modalias_to_module(ctx, buf);

+ +

+  	return 0;

+  err:

+  	free(port->dev_path);

+ @@ -507,6 +529,135 @@ err:

+  	return -ENOMEM;

+  }

+  

+ +static void *add_cxl_port(void *parent, int id, const char *cxlport_base)

+ +{

+ +	const char *devname = devpath_to_devname(cxlport_base);

+ +	struct cxl_port *port, *port_dup;

+ +	struct cxl_port *parent_port = parent;

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(parent_port);

+ +	int rc;

+ +

+ +	dbg(ctx, "%s: base: \'%s\'\n", devname, cxlport_base);

+ +

+ +	port = calloc(1, sizeof(*port));

+ +	if (!port)

+ +		return NULL;

+ +

+ +	rc = cxl_port_init(port, parent_port, CXL_PORT_SWITCH, ctx, id,

+ +			   cxlport_base);

+ +	if (rc)

+ +		goto err;

+ +

+ +	cxl_port_foreach(parent_port, port_dup)

+ +		if (port_dup->id == port->id) {

+ +			free_port(port, NULL);

+ +			return port_dup;

+ +		}

+ +

+ +	list_add(&parent_port->child_ports, &port->list);

+ +	return port;

+ +

+ +err:

+ +	free(port);

+ +	return NULL;

+ +

+ +}

+ +

+ +static void cxl_ports_init(struct cxl_port *port)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +

+ +	if (port->ports_init)

+ +		return;

+ +

+ +	port->ports_init = 1;

+ +

+ +	sysfs_device_parse(ctx, port->dev_path, "port", port, add_cxl_port);

+ +}

+ +

+ +CXL_EXPORT struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port)

+ +{

+ +	return port->ctx;

+ +}

+ +

+ +CXL_EXPORT struct cxl_port *cxl_port_get_first(struct cxl_port *port)

+ +{

+ +	cxl_ports_init(port);

+ +

+ +	return list_top(&port->child_ports, struct cxl_port, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_port *cxl_port_get_next(struct cxl_port *port)

+ +{

+ +	struct cxl_port *parent_port = port->parent;

+ +

+ +	return list_next(&parent_port->child_ports, port, list);

+ +}

+ +

+ +CXL_EXPORT const char *cxl_port_get_devname(struct cxl_port *port)

+ +{

+ +	return devpath_to_devname(port->dev_path);

+ +}

+ +

+ +CXL_EXPORT int cxl_port_get_id(struct cxl_port *port)

+ +{

+ +	return port->id;

+ +}

+ +

+ +CXL_EXPORT struct cxl_port *cxl_port_get_parent(struct cxl_port *port)

+ +{

+ +	return port->parent;

+ +}

+ +

+ +CXL_EXPORT bool cxl_port_is_root(struct cxl_port *port)

+ +{

+ +	return port->type == CXL_PORT_ROOT;

+ +}

+ +

+ +CXL_EXPORT bool cxl_port_is_switch(struct cxl_port *port)

+ +{

+ +	return port->type == CXL_PORT_SWITCH;

+ +}

+ +

+ +CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port)

+ +{

+ +	struct cxl_bus *bus;

+ +

+ +	if (!cxl_port_is_enabled(port))

+ +		return NULL;

+ +

+ +	if (port->bus)

+ +		return port->bus;

+ +

+ +	while (port->parent)

+ +		port = port->parent;

+ +

+ +	bus = container_of(port, typeof(*bus), port);

+ +	port->bus = bus;

+ +	return bus;

+ +}

+ +

+ +CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	char *path = port->dev_buf;

+ +	int len = port->buf_len;

+ +

+ +	if (snprintf(path, len, "%s/driver", port->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", cxl_port_get_devname(port));

+ +		return 0;

+ +	}

+ +

+ +	return is_enabled(path);

+ +}

+ +

+ +CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)

+ +{

+ +	if (!cxl_port_is_root(port))

+ +		return NULL;

+ +	return container_of(port, struct cxl_bus, port);

+ +}

+ +

+  static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)

+  {

+  	const char *devname = devpath_to_devname(cxlbus_base);

+ @@ -522,7 +673,7 @@ static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)

+  		return NULL;

+  

+  	port = &bus->port;

+ -	rc = cxl_port_init(port, ctx, id, cxlbus_base);

+ +	rc = cxl_port_init(port, NULL, CXL_PORT_ROOT, ctx, id, cxlbus_base);

+  	if (rc)

+  		goto err;

+  

+ @@ -579,6 +730,11 @@ CXL_EXPORT int cxl_bus_get_id(struct cxl_bus *bus)

+  	return port->id;

+  }

+  

+ +CXL_EXPORT struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus)

+ +{

+ +	return &bus->port;

+ +}

+ +

+  CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus)

+  {

+  	struct cxl_port *port = &bus->port;

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 781ff99..a7e923f 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -82,4 +82,16 @@ global:

+  	cxl_bus_get_provider;

+  	cxl_bus_get_devname;

+  	cxl_bus_get_id;

+ +	cxl_bus_get_port;

+ +	cxl_port_get_first;

+ +	cxl_port_get_next;

+ +	cxl_port_get_devname;

+ +	cxl_port_get_id;

+ +	cxl_port_get_ctx;

+ +	cxl_port_is_enabled;

+ +	cxl_port_get_parent;

+ +	cxl_port_is_root;

+ +	cxl_port_is_switch;

+ +	cxl_port_to_bus;

+ +	cxl_port_get_bus;

+  } LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 0758d05..637f90d 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -34,14 +34,25 @@ struct cxl_memdev {

+  	unsigned long long serial;

+  };

+  

+ +enum cxl_port_type {

+ +	CXL_PORT_ROOT,

+ +	CXL_PORT_SWITCH,

+ +};

+ +

+  struct cxl_port {

+  	int id;

+  	void *dev_buf;

+  	size_t buf_len;

+  	char *dev_path;

+  	char *uport;

+ +	int ports_init;

+  	struct cxl_ctx *ctx;

+ +	struct cxl_bus *bus;

+ +	enum cxl_port_type type;

+ +	struct cxl_port *parent;

+ +	struct kmod_module *module;

+  	struct list_node list;

+ +	struct list_head child_ports;

+  };

+  

+  struct cxl_bus {

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index da66eb2..efbb397 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -5,6 +5,7 @@

+  

+  #include <stdarg.h>

+  #include <unistd.h>

+ +#include <stdbool.h>

+  

+  #ifdef HAVE_UUID

+  #include <uuid/uuid.h>

+ @@ -63,11 +64,29 @@ struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);

+  const char *cxl_bus_get_provider(struct cxl_bus *bus);

+  const char *cxl_bus_get_devname(struct cxl_bus *bus);

+  int cxl_bus_get_id(struct cxl_bus *bus);

+ +struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);

+  

+  #define cxl_bus_foreach(ctx, bus)                                              \

+  	for (bus = cxl_bus_get_first(ctx); bus != NULL;                        \

+  	     bus = cxl_bus_get_next(bus))

+  

+ +struct cxl_port;

+ +struct cxl_port *cxl_port_get_first(struct cxl_port *parent);

+ +struct cxl_port *cxl_port_get_next(struct cxl_port *port);

+ +const char *cxl_port_get_devname(struct cxl_port *port);

+ +int cxl_port_get_id(struct cxl_port *port);

+ +struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);

+ +int cxl_port_is_enabled(struct cxl_port *port);

+ +struct cxl_port *cxl_port_get_parent(struct cxl_port *port);

+ +bool cxl_port_is_root(struct cxl_port *port);

+ +bool cxl_port_is_switch(struct cxl_port *port);

+ +struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);

+ +struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+ +

+ +#define cxl_port_foreach(parent, port)                                         \

+ +	for (port = cxl_port_get_first(parent); port != NULL;                  \

+ +	     port = cxl_port_get_next(port))

+ +

+  struct cxl_cmd;

+  const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);

+  struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 9500e61..1ef91b4 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -25,6 +25,11 @@ static const struct option options[] = {

+  	OPT_STRING('b', "bus", &param.bus_filter, "bus device name",

+  		   "filter by CXL bus device name(s)"),

+  	OPT_BOOLEAN('B', "buses", &param.buses, "include CXL bus info"),

+ +	OPT_STRING('p', "port", &param.port_filter, "port device name",

+ +		   "filter by CXL port device name(s)"),

+ +	OPT_BOOLEAN('P', "ports", &param.ports, "include CXL port info"),

+ +	OPT_BOOLEAN('S', "single", &param.single,

+ +		    "skip listing descendant objects"),

+  	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+  	OPT_BOOLEAN('u', "human", &param.human,

+  		    "use human friendly number formats "),

+ @@ -35,7 +40,7 @@ static const struct option options[] = {

+  

+  static int num_list_flags(void)

+  {

+ -       return !!param.memdevs + !!param.buses;

+ +       return !!param.memdevs + !!param.buses + !!param.ports;

+  }

+  

+  int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+ @@ -53,11 +58,18 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  	if (argc)

+  		usage_with_options(u, options);

+  

+ +	if (param.single && !param.port_filter) {

+ +		error("-S/--single expects a port filter: -p/--port=\n");

+ +		usage_with_options(u, options);

+ +	}

+ +

+  	if (num_list_flags() == 0) {

+  		if (param.memdev_filter || param.serial_filter)

+  			param.memdevs = true;

+  		if (param.bus_filter)

+  			param.buses = true;

+ +		if (param.port_filter)

+ +			param.ports = true;

+  		if (num_list_flags() == 0) {

+  			/*

+  			 * TODO: We likely want to list regions by default if

+ @@ -73,5 +85,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  

+  	log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");

+  

+ +	if (cxl_filter_has(param.port_filter, "root") && param.ports)

+ +		param.buses = true;

+ +

+  	return cxl_filter_walk(ctx, &param);

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,103 @@ 

+ From 2a43dce3913b392a13a5ee918c8ee831a25d720e Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:24 -0800

+ Subject: [PATCH 104/217] cxl/list: Add --debug option

+ 

+ Add an option to turn on libray and cxl_filter_walk() messages. Gate it

+ based on the global ENABLE_DEBUG configuration setting.

+ 

+ Link: https://lore.kernel.org/r/164298560409.3021641.11040422738199381922.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt | 6 ++++--

+  cxl/filter.c                   | 3 +++

+  cxl/list.c                     | 9 +++++++++

+  3 files changed, 16 insertions(+), 2 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 3076deb..42b6de6 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -200,9 +200,11 @@ OPTIONS

+  	descendants of the individual ports that match the filter. By default

+  	all descendant objects are listed.

+  

+ -include::human-option.txt[]

+ +--debug::

+ +	If the cxl tool was built with debug enabled, turn on debug

+ +	messages.

+  

+ -include::verbose-option.txt[]

+ +include::human-option.txt[]

+  

+  include::../copyright.txt[]

+  

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 8b79db3..32171a4 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -387,6 +387,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	if (!jports)

+  		goto err;

+  

+ +	dbg(p, "walk memdevs\n");

+  	cxl_memdev_foreach(ctx, memdev) {

+  		struct json_object *jdev;

+  

+ @@ -403,6 +404,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  		}

+  	}

+  

+ +	dbg(p, "walk buses\n");

+  	cxl_bus_foreach(ctx, bus) {

+  		struct json_object *jbus = NULL;

+  		struct json_object *jchildports = NULL;

+ @@ -431,6 +433,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  			}

+  		}

+  walk_children:

+ +		dbg(p, "walk ports\n");

+  		walk_child_ports(port, p, pick_array(jchildports, jports),

+  				 flags);

+  		cond_add_put_array_suffix(jbus, "ports", devname, jchildports);

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 1ef91b4..01ab19b 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -13,6 +13,7 @@

+  #include "filter.h"

+  

+  static struct cxl_filter_params param;

+ +static bool debug;

+  

+  static const struct option options[] = {

+  	OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name(s)",

+ @@ -35,6 +36,9 @@ static const struct option options[] = {

+  		    "use human friendly number formats "),

+  	OPT_BOOLEAN('H', "health", &param.health,

+  		    "include memory device health information "),

+ +#ifdef ENABLE_DEBUG

+ +	OPT_BOOLEAN(0, "debug", &debug, "debug list walk"),

+ +#endif

+  	OPT_END(),

+  };

+  

+ @@ -84,9 +88,14 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  	}

+  

+  	log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");

+ +	if (debug) {

+ +		cxl_set_log_priority(ctx, LOG_DEBUG);

+ +		param.ctx.log_priority = LOG_DEBUG;

+ +	}

+  

+  	if (cxl_filter_has(param.port_filter, "root") && param.ports)

+  		param.buses = true;

+  

+ +	dbg(&param, "walk topology\n");

+  	return cxl_filter_walk(ctx, &param);

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,746 @@ 

+ From 7eb06a5293531854e7a28666e955106094d3552b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:29 -0800

+ Subject: [PATCH 105/217] cxl/list: Add endpoints

+ 

+ Endpoints are port-like objects that represent the HDM decoders at terminal

+ end of a decode chain. Unlike port decoders that route to downstream ports,

+ endpoint decoders route to endpoint DPA (Device Physical Address) ranges.

+ 

+ Link: https://lore.kernel.org/r/164298560917.3021641.13753578554905796298.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format                    |   1 +

+  Documentation/cxl/cxl-list.txt   |  16 ++++

+  Documentation/cxl/lib/libcxl.txt |  31 ++++++-

+  cxl/filter.c                     | 147 ++++++++++++++++++++++++++++---

+  cxl/filter.h                     |   2 +

+  cxl/json.c                       |  20 ++++-

+  cxl/json.h                       |   2 +

+  cxl/lib/libcxl.c                 | 107 ++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |   9 ++

+  cxl/lib/private.h                |  10 +++

+  cxl/libcxl.h                     |  15 ++++

+  cxl/list.c                       |  13 ++-

+  12 files changed, 355 insertions(+), 18 deletions(-)

+ 

+ diff --git a/.clang-format b/.clang-format

+ index 391cd34..106bc5e 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -80,6 +80,7 @@ ForEachMacros:

+    - 'cxl_memdev_foreach'

+    - 'cxl_bus_foreach'

+    - 'cxl_port_foreach'

+ +  - 'cxl_endpoint_foreach'

+    - 'daxctl_dev_foreach'

+    - 'daxctl_mapping_foreach'

+    - 'daxctl_region_foreach'

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 42b6de6..d342da2 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -190,6 +190,12 @@ OPTIONS

+  ----

+  # cxl list -B

+  # cxl list -P -p root

+ +----

+ +	Additionally, endpoint objects are also ports so the following commands

+ +	are also equivalent.

+ +----

+ +# cxl list -E

+ +# cxl list -P -p endpoint

+  ----

+  	By default, only 'switch' ports are listed.

+  

+ @@ -200,6 +206,16 @@ OPTIONS

+  	descendants of the individual ports that match the filter. By default

+  	all descendant objects are listed.

+  

+ +-E::

+ +--endpoints::

+ +	Include endpoint objects (CXL Memory Device decoders) in the

+ +	listing.

+ +

+ +-e::

+ +--endpoint::

+ +	Specify CXL endpoint device name(s), or device id(s) to filter

+ +	the emitted endpoint(s).

+ +

+  --debug::

+  	If the cxl tool was built with debug enabled, turn on debug

+  	messages.

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 804e9ca..eebab37 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -199,12 +199,41 @@ int cxl_port_get_id(struct cxl_port *port);

+  int cxl_port_is_enabled(struct cxl_port *port);

+  bool cxl_port_is_root(struct cxl_port *port);

+  bool cxl_port_is_switch(struct cxl_port *port);

+ +bool cxl_port_is_endpoint(struct cxl_port *port);

+  ----

+  The port type is communicated via cxl_port_is_<type>(). An 'enabled' port

+  is one that has succeeded in discovering the CXL component registers in

+  the host device and has enumerated its downstream ports. In order for a

+  memdev to be enabled for CXL memory operation all CXL ports in its

+ -ancestry must also be enabled.

+ +ancestry must also be enabled including a root port, an arbitrary number

+ +of intervening switch ports, and a terminal endpoint port.

+ +

+ +ENDPOINTS

+ +---------

+ +CXL endpoint objects encapsulate the set of host-managed device-memory

+ +(HDM) decoders in a physical memory device. The endpoint is the last hop

+ +in a decoder chain that translate SPA to DPA (system-physical-address to

+ +device-local-physical-address).

+ +

+ +=== ENDPOINT: Enumeration

+ +----

+ +struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent);

+ +struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);

+ +struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);

+ +struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+ +struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+ +

+ +#define cxl_endpoint_foreach(port, endpoint)                                 \

+ +       for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;       \

+ +            endpoint = cxl_endpoint_get_next(endpoint))

+ +----

+ +

+ +=== ENDPOINT: Attributes

+ +----

+ +const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint);

+ +int cxl_endpoint_get_id(struct cxl_endpoint *endpoint);

+ +int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);

+ +----

+  

+  include::../../copyright.txt[]

+  

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 32171a4..5d80d1b 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -47,8 +47,42 @@ bool cxl_filter_has(const char *__filter, const char *needle)

+  	return false;

+  }

+  

+ +static struct cxl_endpoint *

+ +util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident)

+ +{

+ +	char *ident, *save;

+ +	const char *arg;

+ +	int endpoint_id;

+ +

+ +	if (!__ident)

+ +		return endpoint;

+ +

+ +	ident = strdup(__ident);

+ +	if (!ident)

+ +		return NULL;

+ +

+ +	for (arg = strtok_r(ident, which_sep(__ident), &save); arg;

+ +	     arg = strtok_r(NULL, which_sep(__ident), &save)) {

+ +		if (strcmp(arg, "all") == 0)

+ +			break;

+ +

+ +		if ((sscanf(arg, "%d", &endpoint_id) == 1 ||

+ +		     sscanf(arg, "endpoint%d", &endpoint_id) == 1) &&

+ +		    cxl_endpoint_get_id(endpoint) == endpoint_id)

+ +			break;

+ +

+ +		if (strcmp(arg, cxl_endpoint_get_devname(endpoint)) == 0)

+ +			break;

+ +	}

+ +

+ +	free(ident);

+ +	if (arg)

+ +		return endpoint;

+ +	return NULL;

+ +}

+ +

+  static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,

+ -					     const char *__ident)

+ +					       const char *__ident)

+  {

+  	char *ident, *save;

+  	const char *arg;

+ @@ -72,6 +106,9 @@ static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,

+  		if (strcmp(arg, "switch") == 0 && cxl_port_is_switch(port))

+  			break;

+  

+ +		if (strcmp(arg, "endpoint") == 0 && cxl_port_is_endpoint(port))

+ +			break;

+ +

+  		if ((sscanf(arg, "%d", &port_id) == 1 ||

+  		     sscanf(arg, "port%d", &port_id) == 1) &&

+  		    cxl_port_get_id(port) == port_id)

+ @@ -116,6 +153,24 @@ static struct cxl_port *util_cxl_port_filter(struct cxl_port *port,

+  	return NULL;

+  }

+  

+ +static struct cxl_endpoint *

+ +util_cxl_endpoint_filter_by_port(struct cxl_endpoint *endpoint,

+ +				 const char *ident,

+ +				 enum cxl_port_filter_mode mode)

+ +{

+ +	struct cxl_port *iter = cxl_endpoint_get_port(endpoint);

+ +

+ +	if (util_cxl_port_filter(iter, ident, CXL_PF_SINGLE))

+ +		return endpoint;

+ +	iter = cxl_port_get_parent(iter);

+ +	if (!iter)

+ +		return NULL;

+ +	if (util_cxl_port_filter(iter, ident, mode))

+ +		return endpoint;

+ +

+ +	return NULL;

+ +}

+ +

+  static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,

+  					   const char *__ident)

+  {

+ @@ -325,10 +380,34 @@ static struct json_object *pick_array(struct json_object *child,

+  	return NULL;

+  }

+  

+ +static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,

+ +			   struct json_object *jeps, unsigned long flags)

+ +{

+ +	struct cxl_endpoint *endpoint;

+ +

+ +	cxl_endpoint_foreach(port, endpoint) {

+ +		struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint);

+ +		struct json_object *jendpoint;

+ +

+ +		if (!util_cxl_endpoint_filter(endpoint, p->endpoint_filter))

+ +			continue;

+ +		if (!util_cxl_port_filter_by_bus(ep_port, p->bus_filter))

+ +			continue;

+ +		if (!util_cxl_endpoint_filter_by_port(endpoint, p->port_filter,

+ +						      pf_mode(p)))

+ +			continue;

+ +		if (!p->idle && !cxl_endpoint_is_enabled(endpoint))

+ +			continue;

+ +		jendpoint = util_cxl_endpoint_to_json(endpoint, flags);

+ +		if (jendpoint)

+ +			json_object_array_add(jeps, jendpoint);

+ +	}

+ +}

+ +

+  static void walk_child_ports(struct cxl_port *parent_port,

+  			     struct cxl_filter_params *p,

+  			     struct json_object *jports,

+ -			     unsigned long flags)

+ +			     struct json_object *jeps, unsigned long flags)

+  {

+  	struct cxl_port *port;

+  

+ @@ -336,6 +415,7 @@ static void walk_child_ports(struct cxl_port *parent_port,

+  		const char *devname = cxl_port_get_devname(port);

+  		struct json_object *jport = NULL;

+  		struct json_object *jchildports = NULL;

+ +		struct json_object *jchildendpoints = NULL;

+  

+  		if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))

+  			goto walk_children;

+ @@ -343,21 +423,41 @@ static void walk_child_ports(struct cxl_port *parent_port,

+  			goto walk_children;

+  		if (!p->idle && !cxl_port_is_enabled(port))

+  			continue;

+ -		if (p->ports)

+ +		if (p->ports) {

+  			jport = util_cxl_port_to_json(port, flags);

+ -		if (!jport)

+ -			continue;

+ -		json_object_array_add(jports, jport);

+ -		jchildports = json_object_new_array();

+ -		if (!jchildports) {

+ -			err(p, "%s: failed to enumerate child ports\n",

+ -			    devname);

+ -			continue;

+ +			if (!jport) {

+ +				err(p, "%s: failed to list\n", devname);

+ +				continue;

+ +			}

+ +			json_object_array_add(jports, jport);

+ +			jchildports = json_object_new_array();

+ +			if (!jchildports) {

+ +				err(p, "%s: failed to enumerate child ports\n",

+ +				    devname);

+ +				continue;

+ +			}

+ +		}

+ +

+ +		if (p->ports && p->endpoints) {

+ +			jchildendpoints = json_object_new_array();

+ +			if (!jchildendpoints) {

+ +				err(p,

+ +				    "%s: failed to enumerate child endpoints\n",

+ +				    devname);

+ +				continue;

+ +			}

+  		}

+ +

+  walk_children:

+ +		if (p->endpoints)

+ +			walk_endpoints(port, p, pick_array(jchildendpoints, jeps),

+ +				       flags);

+ +

+  		walk_child_ports(port, p, pick_array(jchildports, jports),

+ -				 flags);

+ +				 pick_array(jchildendpoints, jeps), flags);

+  		cond_add_put_array_suffix(jport, "ports", devname, jchildports);

+ +		cond_add_put_array_suffix(jport, "endpoints", devname,

+ +					  jchildendpoints);

+  	}

+  }

+  

+ @@ -366,6 +466,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL;

+  	struct json_object *jplatform = json_object_new_array();

+  	unsigned long flags = params_to_flags(p);

+ +	struct json_object *jeps = NULL;

+  	struct cxl_memdev *memdev;

+  	int top_level_objs = 0;

+  	struct cxl_bus *bus;

+ @@ -387,6 +488,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	if (!jports)

+  		goto err;

+  

+ +	jeps = json_object_new_array();

+ +	if (!jeps)

+ +		goto err;

+ +

+  	dbg(p, "walk memdevs\n");

+  	cxl_memdev_foreach(ctx, memdev) {

+  		struct json_object *jdev;

+ @@ -408,6 +513,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	cxl_bus_foreach(ctx, bus) {

+  		struct json_object *jbus = NULL;

+  		struct json_object *jchildports = NULL;

+ +		struct json_object *jchildeps = NULL;

+  		struct cxl_port *port = cxl_bus_get_port(bus);

+  		const char *devname = cxl_bus_get_devname(bus);

+  

+ @@ -431,12 +537,23 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  					continue;

+  				}

+  			}

+ +			if (p->endpoints) {

+ +				jchildeps = json_object_new_array();

+ +				if (!jchildeps) {

+ +					err(p,

+ +					    "%s: failed to enumerate child endpoints\n",

+ +					    devname);

+ +					continue;

+ +				}

+ +			}

+  		}

+  walk_children:

+  		dbg(p, "walk ports\n");

+  		walk_child_ports(port, p, pick_array(jchildports, jports),

+ -				 flags);

+ +				 pick_array(jchildeps, jeps), flags);

+  		cond_add_put_array_suffix(jbus, "ports", devname, jchildports);

+ +		cond_add_put_array_suffix(jbus, "endpoints", devname,

+ +					  jchildeps);

+  	}

+  

+  	if (json_object_array_length(jdevs))

+ @@ -445,10 +562,13 @@ walk_children:

+  		top_level_objs++;

+  	if (json_object_array_length(jports))

+  		top_level_objs++;

+ +	if (json_object_array_length(jeps))

+ +		top_level_objs++;

+  

+  	splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);

+  	splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);

+  	splice_array(p, jports, jplatform, "ports", top_level_objs > 1);

+ +	splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1);

+  

+  	util_display_json_array(stdout, jplatform, flags);

+  

+ @@ -457,6 +577,7 @@ err:

+  	json_object_put(jdevs);

+  	json_object_put(jbuses);

+  	json_object_put(jports);

+ +	json_object_put(jeps);

+  	json_object_put(jplatform);

+  	return -ENOMEM;

+  }

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 0d83304..bbd341c 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -11,7 +11,9 @@ struct cxl_filter_params {

+  	const char *serial_filter;

+  	const char *bus_filter;

+  	const char *port_filter;

+ +	const char *endpoint_filter;

+  	bool single;

+ +	bool endpoints;

+  	bool memdevs;

+  	bool ports;

+  	bool buses;

+ diff --git a/cxl/json.c b/cxl/json.c

+ index d9f864e..08f6192 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -243,8 +243,9 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+  	return jbus;

+  }

+  

+ -struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+ -					  unsigned long flags)

+ +static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,

+ +						   const char *name_key,

+ +						   unsigned long flags)

+  {

+  	const char *devname = cxl_port_get_devname(port);

+  	struct json_object *jport, *jobj;

+ @@ -255,7 +256,7 @@ struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+  

+  	jobj = json_object_new_string(devname);

+  	if (jobj)

+ -		json_object_object_add(jport, "port", jobj);

+ +		json_object_object_add(jport, name_key, jobj);

+  

+  	if (!cxl_port_is_enabled(port)) {

+  		jobj = json_object_new_string("disabled");

+ @@ -265,3 +266,16 @@ struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+  

+  	return jport;

+  }

+ +

+ +struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+ +					  unsigned long flags)

+ +{

+ +	return __util_cxl_port_to_json(port, "port", flags);

+ +}

+ +

+ +struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint,

+ +					      unsigned long flags)

+ +{

+ +	return __util_cxl_port_to_json(cxl_endpoint_get_port(endpoint),

+ +				       "endpoint", flags);

+ +}

+ diff --git a/cxl/json.h b/cxl/json.h

+ index 36653db..8f45190 100644

+ --- a/cxl/json.h

+ +++ b/cxl/json.h

+ @@ -11,4 +11,6 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+  struct cxl_port;

+  struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+  					  unsigned long flags);

+ +struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint,

+ +					      unsigned long flags);

+  #endif /* __CXL_UTIL_JSON_H__ */

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 03eff3c..a25e715 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -67,14 +67,18 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+  }

+  

+  static void free_port(struct cxl_port *port, struct list_head *head);

+ +static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head);

+  static void __free_port(struct cxl_port *port, struct list_head *head)

+  {

+  	struct cxl_port *child, *_c;

+ +	struct cxl_endpoint *endpoint, *_e;

+  

+  	if (head)

+  		list_del_from(head, &port->list);

+  	list_for_each_safe(&port->child_ports, child, _c, list)

+  		free_port(child, &port->child_ports);

+ +	list_for_each_safe(&port->endpoints, endpoint, _e, port.list)

+ +		free_endpoint(endpoint, &port->endpoints);

+  	kmod_module_unref(port->module);

+  	free(port->dev_buf);

+  	free(port->dev_path);

+ @@ -87,6 +91,12 @@ static void free_port(struct cxl_port *port, struct list_head *head)

+  	free(port);

+  }

+  

+ +static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head)

+ +{

+ +	__free_port(&endpoint->port, head);

+ +	free(endpoint);

+ +}

+ +

+  static void free_bus(struct cxl_bus *bus, struct list_head *head)

+  {

+  	__free_port(&bus->port, head);

+ @@ -500,6 +510,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,

+  	port->parent = parent_port;

+  

+  	list_head_init(&port->child_ports);

+ +	list_head_init(&port->endpoints);

+  

+  	port->dev_path = strdup(cxlport_base);

+  	if (!port->dev_path)

+ @@ -529,6 +540,97 @@ err:

+  	return -ENOMEM;

+  }

+  

+ +static void *add_cxl_endpoint(void *parent, int id, const char *cxlep_base)

+ +{

+ +	const char *devname = devpath_to_devname(cxlep_base);

+ +	struct cxl_endpoint *endpoint, *endpoint_dup;

+ +	struct cxl_port *port = parent;

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	int rc;

+ +

+ +	dbg(ctx, "%s: base: \'%s\'\n", devname, cxlep_base);

+ +

+ +	endpoint = calloc(1, sizeof(*endpoint));

+ +	if (!endpoint)

+ +		return NULL;

+ +

+ +	rc = cxl_port_init(&endpoint->port, port, CXL_PORT_ENDPOINT, ctx, id,

+ +			   cxlep_base);

+ +	if (rc)

+ +		goto err;

+ +

+ +	cxl_endpoint_foreach(port, endpoint_dup)

+ +		if (endpoint_dup->port.id == endpoint->port.id) {

+ +			free_endpoint(endpoint, NULL);

+ +			return endpoint_dup;

+ +		}

+ +

+ +	list_add(&port->endpoints, &endpoint->port.list);

+ +	return endpoint;

+ +

+ +err:

+ +	free(endpoint);

+ +	return NULL;

+ +

+ +}

+ +

+ +static void cxl_endpoints_init(struct cxl_port *port)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +

+ +	if (port->endpoints_init)

+ +		return;

+ +

+ +	port->endpoints_init = 1;

+ +

+ +	sysfs_device_parse(ctx, port->dev_path, "endpoint", port,

+ +			   add_cxl_endpoint);

+ +}

+ +

+ +CXL_EXPORT struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint)

+ +{

+ +	return endpoint->port.ctx;

+ +}

+ +

+ +CXL_EXPORT struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *port)

+ +{

+ +	cxl_endpoints_init(port);

+ +

+ +	return list_top(&port->endpoints, struct cxl_endpoint, port.list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint)

+ +{

+ +	struct cxl_port *port = endpoint->port.parent;

+ +

+ +	return list_next(&port->endpoints, endpoint, port.list);

+ +}

+ +

+ +CXL_EXPORT const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint)

+ +{

+ +	return devpath_to_devname(endpoint->port.dev_path);

+ +}

+ +

+ +CXL_EXPORT int cxl_endpoint_get_id(struct cxl_endpoint *endpoint)

+ +{

+ +	return endpoint->port.id;

+ +}

+ +

+ +CXL_EXPORT struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint)

+ +{

+ +	return endpoint->port.parent;

+ +}

+ +

+ +CXL_EXPORT struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint)

+ +{

+ +	return &endpoint->port;

+ +}

+ +

+ +CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)

+ +{

+ +	return cxl_port_is_enabled(&endpoint->port);

+ +}

+ +

+  static void *add_cxl_port(void *parent, int id, const char *cxlport_base)

+  {

+  	const char *devname = devpath_to_devname(cxlport_base);

+ @@ -619,6 +721,11 @@ CXL_EXPORT bool cxl_port_is_switch(struct cxl_port *port)

+  	return port->type == CXL_PORT_SWITCH;

+  }

+  

+ +CXL_EXPORT bool cxl_port_is_endpoint(struct cxl_port *port)

+ +{

+ +	return port->type == CXL_PORT_ENDPOINT;

+ +}

+ +

+  CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port)

+  {

+  	struct cxl_bus *bus;

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index a7e923f..7a51a0c 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -93,5 +93,14 @@ global:

+  	cxl_port_is_root;

+  	cxl_port_is_switch;

+  	cxl_port_to_bus;

+ +	cxl_port_is_endpoint;

+  	cxl_port_get_bus;

+ +	cxl_endpoint_get_first;

+ +	cxl_endpoint_get_next;

+ +	cxl_endpoint_get_devname;

+ +	cxl_endpoint_get_id;

+ +	cxl_endpoint_get_ctx;

+ +	cxl_endpoint_is_enabled;

+ +	cxl_endpoint_get_parent;

+ +	cxl_endpoint_get_port;

+  } LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 637f90d..cedd2f2 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -17,6 +17,7 @@ struct cxl_pmem {

+  	char *dev_path;

+  };

+  

+ +struct cxl_endpoint;

+  struct cxl_memdev {

+  	int id, major, minor;

+  	void *dev_buf;

+ @@ -32,11 +33,13 @@ struct cxl_memdev {

+  	struct kmod_module *module;

+  	struct cxl_pmem *pmem;

+  	unsigned long long serial;

+ +	struct cxl_endpoint *endpoint;

+  };

+  

+  enum cxl_port_type {

+  	CXL_PORT_ROOT,

+  	CXL_PORT_SWITCH,

+ +	CXL_PORT_ENDPOINT,

+  };

+  

+  struct cxl_port {

+ @@ -46,6 +49,7 @@ struct cxl_port {

+  	char *dev_path;

+  	char *uport;

+  	int ports_init;

+ +	int endpoints_init;

+  	struct cxl_ctx *ctx;

+  	struct cxl_bus *bus;

+  	enum cxl_port_type type;

+ @@ -53,12 +57,18 @@ struct cxl_port {

+  	struct kmod_module *module;

+  	struct list_node list;

+  	struct list_head child_ports;

+ +	struct list_head endpoints;

+  };

+  

+  struct cxl_bus {

+  	struct cxl_port port;

+  };

+  

+ +struct cxl_endpoint {

+ +	struct cxl_port port;

+ +	struct cxl_memdev *memdev;

+ +};

+ +

+  enum cxl_cmd_query_status {

+  	CXL_CMD_QUERY_NOT_RUN = 0,

+  	CXL_CMD_QUERY_OK,

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index efbb397..f6ba9a1 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -81,12 +81,27 @@ struct cxl_port *cxl_port_get_parent(struct cxl_port *port);

+  bool cxl_port_is_root(struct cxl_port *port);

+  bool cxl_port_is_switch(struct cxl_port *port);

+  struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);

+ +bool cxl_port_is_endpoint(struct cxl_port *port);

+  struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+  

+  #define cxl_port_foreach(parent, port)                                         \

+  	for (port = cxl_port_get_first(parent); port != NULL;                  \

+  	     port = cxl_port_get_next(port))

+  

+ +struct cxl_endpoint;

+ +struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent);

+ +struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);

+ +const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint);

+ +int cxl_endpoint_get_id(struct cxl_endpoint *endpoint);

+ +struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);

+ +int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);

+ +struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+ +struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+ +

+ +#define cxl_endpoint_foreach(port, endpoint)                                   \

+ +	for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;        \

+ +	     endpoint = cxl_endpoint_get_next(endpoint))

+ +

+  struct cxl_cmd;

+  const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);

+  struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 01ab19b..b15e01c 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -31,6 +31,11 @@ static const struct option options[] = {

+  	OPT_BOOLEAN('P', "ports", &param.ports, "include CXL port info"),

+  	OPT_BOOLEAN('S', "single", &param.single,

+  		    "skip listing descendant objects"),

+ +	OPT_STRING('e', "endpoint", &param.endpoint_filter,

+ +		   "endpoint device name",

+ +		   "filter by CXL endpoint device name(s)"),

+ +	OPT_BOOLEAN('E', "endpoints", &param.endpoints,

+ +		    "include CXL endpoint info"),

+  	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+  	OPT_BOOLEAN('u', "human", &param.human,

+  		    "use human friendly number formats "),

+ @@ -44,7 +49,8 @@ static const struct option options[] = {

+  

+  static int num_list_flags(void)

+  {

+ -       return !!param.memdevs + !!param.buses + !!param.ports;

+ +	return !!param.memdevs + !!param.buses + !!param.ports +

+ +	       !!param.endpoints;

+  }

+  

+  int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+ @@ -74,6 +80,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  			param.buses = true;

+  		if (param.port_filter)

+  			param.ports = true;

+ +		if (param.endpoint_filter)

+ +			param.endpoints = true;

+  		if (num_list_flags() == 0) {

+  			/*

+  			 * TODO: We likely want to list regions by default if

+ @@ -96,6 +104,9 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  	if (cxl_filter_has(param.port_filter, "root") && param.ports)

+  		param.buses = true;

+  

+ +	if (cxl_filter_has(param.port_filter, "endpoint") && param.ports)

+ +		param.endpoints = true;

+ +

+  	dbg(&param, "walk topology\n");

+  	return cxl_filter_walk(ctx, &param);

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,154 @@ 

+ From f39735be3c1157fdfa7dd5c781048a411ebe4dc5 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:34 -0800

+ Subject: [PATCH 106/217] cxl/list: Add 'host' entries for port-like objects

+ 

+ Add the device name of the "host" device for a given CXL port object. The

+ kernel calls this the 'uport' attribute.

+ 

+ Link: https://lore.kernel.org/r/164298561473.3021641.16508989603599026269.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt   |  9 +++++++++

+  Documentation/cxl/lib/libcxl.txt |  5 +++++

+  cxl/json.c                       |  4 ++++

+  cxl/lib/libcxl.c                 | 10 ++++++++++

+  cxl/lib/libcxl.sym               |  2 ++

+  cxl/libcxl.h                     |  2 ++

+  6 files changed, 32 insertions(+)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index d342da2..30b6161 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -210,6 +210,15 @@ OPTIONS

+  --endpoints::

+  	Include endpoint objects (CXL Memory Device decoders) in the

+  	listing.

+ +----

+ +# cxl list -E

+ +[

+ +  {

+ +    "endpoint":"endpoint2",

+ +    "host":"mem0"

+ +  }

+ +]

+ +----

+  

+  -e::

+  --endpoint::

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index eebab37..e4b372d 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -178,6 +178,7 @@ struct cxl_port *cxl_port_get_next(struct cxl_port *port);

+  struct cxl_port *cxl_port_get_parent(struct cxl_port *port);

+  struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+  struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);

+ +const char *cxl_port_get_host(struct cxl_port *port);

+  

+  #define cxl_port_foreach(parent, port)                                      \

+         for (port = cxl_port_get_first(parent); port != NULL;                \

+ @@ -192,6 +193,9 @@ as a parent object retrievable via cxl_port_get_parent().

+  The root port of a hiearchy can be retrieved via any port instance in

+  that hierarchy via cxl_port_get_bus().

+  

+ +The host of a port is the corresponding device name of the PCIe Root

+ +Port, or Switch Upstream Port with CXL capabilities.

+ +

+  === PORT: Attributes

+  ----

+  const char *cxl_port_get_devname(struct cxl_port *port);

+ @@ -222,6 +226,7 @@ struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);

+  struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+ +const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);

+  

+  #define cxl_endpoint_foreach(port, endpoint)                                 \

+         for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;       \

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 08f6192..af3b4fe 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -258,6 +258,10 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,

+  	if (jobj)

+  		json_object_object_add(jport, name_key, jobj);

+  

+ +	jobj = json_object_new_string(cxl_port_get_host(port));

+ +	if (jobj)

+ +		json_object_object_add(jport, "host", jobj);

+ +

+  	if (!cxl_port_is_enabled(port)) {

+  		jobj = json_object_new_string("disabled");

+  		if (jobj)

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index a25e715..5f48202 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -626,6 +626,11 @@ CXL_EXPORT struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint)

+  	return &endpoint->port;

+  }

+  

+ +CXL_EXPORT const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint)

+ +{

+ +	return cxl_port_get_host(&endpoint->port);

+ +}

+ +

+  CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)

+  {

+  	return cxl_port_is_enabled(&endpoint->port);

+ @@ -744,6 +749,11 @@ CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port)

+  	return bus;

+  }

+  

+ +CXL_EXPORT const char *cxl_port_get_host(struct cxl_port *port)

+ +{

+ +	return devpath_to_devname(port->uport);

+ +}

+ +

+  CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)

+  {

+  	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 7a51a0c..dc2863e 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -95,6 +95,7 @@ global:

+  	cxl_port_to_bus;

+  	cxl_port_is_endpoint;

+  	cxl_port_get_bus;

+ +	cxl_port_get_host;

+  	cxl_endpoint_get_first;

+  	cxl_endpoint_get_next;

+  	cxl_endpoint_get_devname;

+ @@ -103,4 +104,5 @@ global:

+  	cxl_endpoint_is_enabled;

+  	cxl_endpoint_get_parent;

+  	cxl_endpoint_get_port;

+ +	cxl_endpoint_get_host;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index f6ba9a1..a60777e 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -83,6 +83,7 @@ bool cxl_port_is_switch(struct cxl_port *port);

+  struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);

+  bool cxl_port_is_endpoint(struct cxl_port *port);

+  struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+ +const char *cxl_port_get_host(struct cxl_port *port);

+  

+  #define cxl_port_foreach(parent, port)                                         \

+  	for (port = cxl_port_get_first(parent); port != NULL;                  \

+ @@ -97,6 +98,7 @@ struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);

+  int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+ +const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);

+  

+  #define cxl_endpoint_foreach(port, endpoint)                                   \

+  	for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;        \

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,175 @@ 

+ From eec8c953a840a1cbdca63352c64cec3e48e86afe Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:39 -0800

+ Subject: [PATCH 107/217] cxl/list: Add 'host' entries for memdevs

+ 

+ For debugging CXL port connectivity issues it will be useful to have the

+ PCI device name for the memory expander in the 'memdev' listing.

+ 

+ Link: https://lore.kernel.org/r/164298561980.3021641.9636572507721689266.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt   |  3 ++-

+  Documentation/cxl/lib/libcxl.txt |  4 ++++

+  cxl/json.c                       |  5 +++++

+  cxl/lib/libcxl.c                 | 24 ++++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |  1 +

+  cxl/lib/private.h                |  1 +

+  cxl/libcxl.h                     |  1 +

+  7 files changed, 38 insertions(+), 1 deletion(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 30b6161..9c21ab7 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -43,7 +43,8 @@ EXAMPLE

+      "memdev":"mem0",

+      "pmem_size":268435456,

+      "ram_size":0,

+ -    "serial":0

+ +    "serial":0,

+ +    "host":"0000:35:00.0"

+    }

+  ]

+  

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index e4b372d..91fd33e 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -40,6 +40,7 @@ kernel, or to send data or trigger kernel operations for a given device.

+  struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);

+  struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);

+  struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);

+ +const char *cxl_memdev_get_host(struct cxl_memdev *memdev)

+  

+  #define cxl_memdev_foreach(ctx, memdev) \

+          for (memdev = cxl_memdev_get_first(ctx); \

+ @@ -54,6 +55,9 @@ memory device commands, see the port, decoder, and endpoint APIs to

+  determine what if any CXL Memory Resources are reachable given a

+  specific memdev.

+  

+ +The host of a memdev is the PCIe Endpoint device that registered its CXL

+ +capabilities with the Linux CXL core.

+ +

+  === MEMDEV: Attributes

+  ----

+  int cxl_memdev_get_id(struct cxl_memdev *memdev);

+ diff --git a/cxl/json.c b/cxl/json.c

+ index af3b4fe..1868686 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -219,6 +219,11 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  		if (jobj)

+  			json_object_object_add(jdev, "serial", jobj);

+  	}

+ +

+ +	jobj = json_object_new_string(cxl_memdev_get_host(memdev));

+ +	if (jobj)

+ +		json_object_object_add(jdev, "host", jobj);

+ +

+  	return jdev;

+  }

+  

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 5f48202..c4ddc7d 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -63,6 +63,7 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+  	free(memdev->firmware_version);

+  	free(memdev->dev_buf);

+  	free(memdev->dev_path);

+ +	free(memdev->host);

+  	free(memdev);

+  }

+  

+ @@ -297,6 +298,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  	char *path = calloc(1, strlen(cxlmem_base) + 100);

+  	struct cxl_ctx *ctx = parent;

+  	struct cxl_memdev *memdev, *memdev_dup;

+ +	char *host, *rpath = NULL;

+  	char buf[SYSFS_ATTR_SIZE];

+  	struct stat st;

+  

+ @@ -350,6 +352,22 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  	if (!memdev->dev_path)

+  		goto err_read;

+  

+ +	rpath = realpath(cxlmem_base, NULL);

+ +	if (!rpath)

+ +		goto err_read;

+ +	host = strrchr(rpath, '/');

+ +	if (host) {

+ +		host[0] = '\0';

+ +		host = strrchr(rpath, '/');

+ +	}

+ +	if (!host)

+ +		goto err_read;

+ +	memdev->host = strdup(host + 1);

+ +	if (!memdev->host)

+ +		goto err_read;

+ +	free(rpath);

+ +	rpath = NULL;

+ +

+  	sprintf(path, "%s/firmware_version", cxlmem_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+  		goto err_read;

+ @@ -381,6 +399,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  	free(memdev->dev_buf);

+  	free(memdev->dev_path);

+  	free(memdev);

+ +	free(rpath);

+   err_dev:

+  	free(path);

+  	return NULL;

+ @@ -431,6 +450,11 @@ CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)

+  	return devpath_to_devname(memdev->dev_path);

+  }

+  

+ +CXL_EXPORT const char *cxl_memdev_get_host(struct cxl_memdev *memdev)

+ +{

+ +	return memdev->host;

+ +}

+ +

+  CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev)

+  {

+  	return memdev->major;

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index dc2863e..8f0688a 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -77,6 +77,7 @@ local:

+  LIBCXL_2 {

+  global:

+  	cxl_memdev_get_serial;

+ +	cxl_memdev_get_host;

+  	cxl_bus_get_first;

+  	cxl_bus_get_next;

+  	cxl_bus_get_provider;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index cedd2f2..b097bdf 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -22,6 +22,7 @@ struct cxl_memdev {

+  	int id, major, minor;

+  	void *dev_buf;

+  	size_t buf_len;

+ +	char *host;

+  	char *dev_path;

+  	char *firmware_version;

+  	struct cxl_ctx *ctx;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index a60777e..5487b55 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -38,6 +38,7 @@ struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);

+  int cxl_memdev_get_id(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);

+ +const char *cxl_memdev_get_host(struct cxl_memdev *memdev);

+  int cxl_memdev_get_major(struct cxl_memdev *memdev);

+  int cxl_memdev_get_minor(struct cxl_memdev *memdev);

+  struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,499 @@ 

+ From 41d6769393f449008abf934e815f137360889633 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:45 -0800

+ Subject: [PATCH 108/217] cxl/list: Move enabled memdevs underneath their

+  endpoint

+ 

+ When a memdev is enabled it means that the kernel was able to validate a

+ CXL connection from the CXL root, through intervening switches, and to the

+ endpoint. Reflect that state by listing memdevs as child objects of

+ endpoints, or aggregated into an array if individual endpoints are not

+ listed.

+ 

+ Link: https://lore.kernel.org/r/164298562531.3021641.10620937879296964476.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt   |  11 ++-

+  Documentation/cxl/lib/libcxl.txt |   2 +

+  cxl/filter.c                     | 130 ++++++++++++++++++++++++-------

+  cxl/json.c                       |   6 ++

+  cxl/lib/libcxl.c                 |  97 +++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |   3 +

+  cxl/libcxl.h                     |   4 +

+  7 files changed, 223 insertions(+), 30 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 9c21ab7..1751868 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -19,7 +19,16 @@ Options can be specified to limit the output to specific objects. When a

+  single object type is specified the return json object is an array of

+  just those objects, when multiple objects types are specified the

+  returned the returned object may be an array of arrays with the inner

+ -array named for the given object type.

+ +array named for the given object type. The top-level arrays are ellided

+ +when the objects can nest under a higher object-type in the hierararchy.

+ +The potential top-level array names and their nesting properties are:

+ +

+ +"anon memdevs":: (disabled memory devices) do not nest

+ +"buses":: do not nest

+ +"ports":: nest under buses

+ +"endpoints":: nest under ports or buses (if ports are not emitted)

+ +"memdevs":: nest under endpoints or ports (if endpoints are not

+ +   emitted) or buses (if endpoints and ports are not emitted)

+  

+  Filters can by specifed as either a single identidier, a space separated

+  quoted string, or a comma separated list. When multiple filter

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 91fd33e..73b0fb9 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -41,6 +41,7 @@ struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);

+  struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);

+  struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_host(struct cxl_memdev *memdev)

+ +struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint);

+  

+  #define cxl_memdev_foreach(ctx, memdev) \

+          for (memdev = cxl_memdev_get_first(ctx); \

+ @@ -231,6 +232,7 @@ struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+  const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);

+ +struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);

+  

+  #define cxl_endpoint_foreach(port, endpoint)                                 \

+         for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;       \

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 5d80d1b..2130816 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -381,13 +381,16 @@ static struct json_object *pick_array(struct json_object *child,

+  }

+  

+  static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,

+ -			   struct json_object *jeps, unsigned long flags)

+ +			   struct json_object *jeps, struct json_object *jdevs,

+ +			   unsigned long flags)

+  {

+  	struct cxl_endpoint *endpoint;

+  

+  	cxl_endpoint_foreach(port, endpoint) {

+  		struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint);

+ -		struct json_object *jendpoint;

+ +		const char *devname = cxl_endpoint_get_devname(endpoint);

+ +		struct json_object *jendpoint = NULL;

+ +		struct cxl_memdev *memdev;

+  

+  		if (!util_cxl_endpoint_filter(endpoint, p->endpoint_filter))

+  			continue;

+ @@ -398,24 +401,54 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,

+  			continue;

+  		if (!p->idle && !cxl_endpoint_is_enabled(endpoint))

+  			continue;

+ -		jendpoint = util_cxl_endpoint_to_json(endpoint, flags);

+ -		if (jendpoint)

+ +		if (p->endpoints) {

+ +			jendpoint = util_cxl_endpoint_to_json(endpoint, flags);

+ +			if (!jendpoint) {

+ +				err(p, "%s: failed to list\n", devname);

+ +				continue;

+ +			}

+  			json_object_array_add(jeps, jendpoint);

+ +		}

+ +		if (p->memdevs) {

+ +			struct json_object *jobj;

+ +

+ +			memdev = cxl_endpoint_get_memdev(endpoint);

+ +			if (!memdev)

+ +				continue;

+ +			if (!util_cxl_memdev_filter(memdev, p->memdev_filter,

+ +						    p->serial_filter))

+ +				continue;

+ +			if (!p->idle && !cxl_memdev_is_enabled(memdev))

+ +				continue;

+ +			jobj = util_cxl_memdev_to_json(memdev, flags);

+ +			if (!jobj) {

+ +				err(p, "failed to json serialize %s\n",

+ +				    cxl_memdev_get_devname(memdev));

+ +				continue;

+ +			}

+ +			if (p->endpoints)

+ +				json_object_object_add(jendpoint, "memdev",

+ +						       jobj);

+ +			else

+ +				json_object_array_add(jdevs, jobj);

+ +		}

+  	}

+  }

+  

+  static void walk_child_ports(struct cxl_port *parent_port,

+  			     struct cxl_filter_params *p,

+  			     struct json_object *jports,

+ -			     struct json_object *jeps, unsigned long flags)

+ +			     struct json_object *jeps,

+ +			     struct json_object *jdevs, unsigned long flags)

+  {

+  	struct cxl_port *port;

+  

+  	cxl_port_foreach(parent_port, port) {

+  		const char *devname = cxl_port_get_devname(port);

+  		struct json_object *jport = NULL;

+ +		struct json_object *jchilddevs = NULL;

+  		struct json_object *jchildports = NULL;

+ -		struct json_object *jchildendpoints = NULL;

+ +		struct json_object *jchildeps = NULL;

+  

+  		if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))

+  			goto walk_children;

+ @@ -436,28 +469,41 @@ static void walk_child_ports(struct cxl_port *parent_port,

+  				    devname);

+  				continue;

+  			}

+ -		}

+  

+ -		if (p->ports && p->endpoints) {

+ -			jchildendpoints = json_object_new_array();

+ -			if (!jchildendpoints) {

+ -				err(p,

+ -				    "%s: failed to enumerate child endpoints\n",

+ -				    devname);

+ -				continue;

+ +			if (p->memdevs && !p->endpoints) {

+ +				jchilddevs = json_object_new_array();

+ +				if (!jchilddevs) {

+ +					err(p,

+ +					    "%s: failed to enumerate child memdevs\n",

+ +					    devname);

+ +					continue;

+ +				}

+ +			}

+ +

+ +			if (p->endpoints) {

+ +				jchildeps = json_object_new_array();

+ +				if (!jchildeps) {

+ +					err(p,

+ +					    "%s: failed to enumerate child endpoints\n",

+ +					    devname);

+ +					continue;

+ +				}

+  			}

+  		}

+  

+  walk_children:

+ -		if (p->endpoints)

+ -			walk_endpoints(port, p, pick_array(jchildendpoints, jeps),

+ -				       flags);

+ +		if (p->endpoints || p->memdevs)

+ +			walk_endpoints(port, p, pick_array(jchildeps, jeps),

+ +				       pick_array(jchilddevs, jdevs), flags);

+  

+  		walk_child_ports(port, p, pick_array(jchildports, jports),

+ -				 pick_array(jchildendpoints, jeps), flags);

+ +				 pick_array(jchildeps, jeps),

+ +				 pick_array(jchilddevs, jdevs), flags);

+  		cond_add_put_array_suffix(jport, "ports", devname, jchildports);

+  		cond_add_put_array_suffix(jport, "endpoints", devname,

+ -					  jchildendpoints);

+ +					  jchildeps);

+ +		cond_add_put_array_suffix(jport, "memdevs", devname,

+ +					  jchilddevs);

+  	}

+  }

+  

+ @@ -466,6 +512,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL;

+  	struct json_object *jplatform = json_object_new_array();

+  	unsigned long flags = params_to_flags(p);

+ +	struct json_object *janondevs = NULL;

+  	struct json_object *jeps = NULL;

+  	struct cxl_memdev *memdev;

+  	int top_level_objs = 0;

+ @@ -476,8 +523,8 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  		return -ENOMEM;

+  	}

+  

+ -	jdevs = json_object_new_array();

+ -	if (!jdevs)

+ +	janondevs = json_object_new_array();

+ +	if (!janondevs)

+  		goto err;

+  

+  	jbuses = json_object_new_array();

+ @@ -492,20 +539,28 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	if (!jeps)

+  		goto err;

+  

+ +	jdevs = json_object_new_array();

+ +	if (!jdevs)

+ +		goto err;

+ +

+  	dbg(p, "walk memdevs\n");

+  	cxl_memdev_foreach(ctx, memdev) {

+ -		struct json_object *jdev;

+ +		struct json_object *janondev;

+  

+  		if (!util_cxl_memdev_filter(memdev, p->memdev_filter,

+  					    p->serial_filter))

+  			continue;

+ +		if (cxl_memdev_is_enabled(memdev))

+ +			continue;

+ +		if (!p->idle)

+ +			continue;

+  		if (p->memdevs) {

+ -			jdev = util_cxl_memdev_to_json(memdev, flags);

+ -			if (!jdev) {

+ +			janondev = util_cxl_memdev_to_json(memdev, flags);

+ +			if (!janondev) {

+  				dbg(p, "memdev object allocation failure\n");

+  				continue;

+  			}

+ -			json_object_array_add(jdevs, jdev);

+ +			json_object_array_add(janondevs, janondev);

+  		}

+  	}

+  

+ @@ -513,6 +568,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	cxl_bus_foreach(ctx, bus) {

+  		struct json_object *jbus = NULL;

+  		struct json_object *jchildports = NULL;

+ +		struct json_object *jchilddevs = NULL;

+  		struct json_object *jchildeps = NULL;

+  		struct cxl_port *port = cxl_bus_get_port(bus);

+  		const char *devname = cxl_bus_get_devname(bus);

+ @@ -546,17 +602,29 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  					continue;

+  				}

+  			}

+ +

+ +			if (p->memdevs && !p->ports && !p->endpoints) {

+ +				jchilddevs = json_object_new_array();

+ +				if (!jchilddevs) {

+ +					err(p,

+ +					    "%s: failed to enumerate child memdevs\n",

+ +					    devname);

+ +					continue;

+ +				}

+ +			}

+  		}

+  walk_children:

+  		dbg(p, "walk ports\n");

+  		walk_child_ports(port, p, pick_array(jchildports, jports),

+ -				 pick_array(jchildeps, jeps), flags);

+ +				 pick_array(jchildeps, jeps),

+ +				 pick_array(jchilddevs, jdevs), flags);

+  		cond_add_put_array_suffix(jbus, "ports", devname, jchildports);

+  		cond_add_put_array_suffix(jbus, "endpoints", devname,

+  					  jchildeps);

+ +		cond_add_put_array_suffix(jbus, "memdevs", devname, jchilddevs);

+  	}

+  

+ -	if (json_object_array_length(jdevs))

+ +	if (json_object_array_length(janondevs))

+  		top_level_objs++;

+  	if (json_object_array_length(jbuses))

+  		top_level_objs++;

+ @@ -564,20 +632,24 @@ walk_children:

+  		top_level_objs++;

+  	if (json_object_array_length(jeps))

+  		top_level_objs++;

+ +	if (json_object_array_length(jdevs))

+ +		top_level_objs++;

+  

+ -	splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);

+ +	splice_array(p, janondevs, jplatform, "anon memdevs", top_level_objs > 1);

+  	splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);

+  	splice_array(p, jports, jplatform, "ports", top_level_objs > 1);

+  	splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1);

+ +	splice_array(p, jdevs, jplatform, "memdevs", top_level_objs > 1);

+  

+  	util_display_json_array(stdout, jplatform, flags);

+  

+  	return 0;

+  err:

+ -	json_object_put(jdevs);

+ +	json_object_put(janondevs);

+  	json_object_put(jbuses);

+  	json_object_put(jports);

+  	json_object_put(jeps);

+ +	json_object_put(jdevs);

+  	json_object_put(jplatform);

+  	return -ENOMEM;

+  }

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 1868686..b809332 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -224,6 +224,12 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  	if (jobj)

+  		json_object_object_add(jdev, "host", jobj);

+  

+ +	if (!cxl_memdev_is_enabled(memdev)) {

+ +		jobj = json_object_new_string("disabled");

+ +		if (jobj)

+ +			json_object_object_add(jdev, "state", jobj);

+ +	}

+ +

+  	return jdev;

+  }

+  

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index c4ddc7d..4523ca6 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -480,6 +480,60 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev

+  	return memdev->firmware_version;

+  }

+  

+ +static struct cxl_endpoint *cxl_port_find_endpoint(struct cxl_port *parent_port,

+ +						   struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_endpoint *endpoint;

+ +	struct cxl_port *port;

+ +

+ +	cxl_port_foreach(parent_port, port) {

+ +		cxl_endpoint_foreach(port, endpoint)

+ +			if (strcmp(cxl_endpoint_get_host(endpoint),

+ +				   cxl_memdev_get_devname(memdev)) == 0)

+ +				return endpoint;

+ +		endpoint = cxl_port_find_endpoint(port, memdev);

+ +		if (endpoint)

+ +			return endpoint;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+ +CXL_EXPORT struct cxl_endpoint *

+ +cxl_memdev_get_endpoint(struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	struct cxl_endpoint *endpoint = NULL;

+ +	struct cxl_bus *bus;

+ +

+ +	if (memdev->endpoint)

+ +		return memdev->endpoint;

+ +

+ +	if (!cxl_memdev_is_enabled(memdev))

+ +		return NULL;

+ +

+ +	cxl_bus_foreach (ctx, bus) {

+ +		struct cxl_port *port = cxl_bus_get_port(bus);

+ +

+ +		endpoint = cxl_port_find_endpoint(port, memdev);

+ +		if (endpoint)

+ +			break;

+ +	}

+ +

+ +	if (!endpoint)

+ +		return NULL;

+ +

+ +	if (endpoint->memdev && endpoint->memdev != memdev)

+ +		err(ctx, "%s assigned to %s not %s\n",

+ +		    cxl_endpoint_get_devname(endpoint),

+ +		    cxl_memdev_get_devname(endpoint->memdev),

+ +		    cxl_memdev_get_devname(memdev));

+ +	memdev->endpoint = endpoint;

+ +	endpoint->memdev = memdev;

+ +

+ +	return endpoint;

+ +}

+ +

+  CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)

+  {

+  	return memdev->lsa_size;

+ @@ -495,6 +549,21 @@ static int is_enabled(const char *drvpath)

+  		return 1;

+  }

+  

+ +CXL_EXPORT int cxl_memdev_is_enabled(struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	char *path = memdev->dev_buf;

+ +	int len = memdev->buf_len;

+ +

+ +	if (snprintf(path, len, "%s/driver", memdev->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n",

+ +		    cxl_memdev_get_devname(memdev));

+ +		return 0;

+ +	}

+ +

+ +	return is_enabled(path);

+ +}

+ +

+  CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)

+  {

+  	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ @@ -660,6 +729,34 @@ CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)

+  	return cxl_port_is_enabled(&endpoint->port);

+  }

+  

+ +CXL_EXPORT struct cxl_memdev *

+ +cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint)

+ +{

+ +	struct cxl_ctx *ctx = cxl_endpoint_get_ctx(endpoint);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (endpoint->memdev)

+ +		return endpoint->memdev;

+ +

+ +	if (!cxl_endpoint_is_enabled(endpoint))

+ +		return NULL;

+ +

+ +	cxl_memdev_foreach(ctx, memdev)

+ +		if (strcmp(cxl_memdev_get_devname(memdev),

+ +			   cxl_endpoint_get_host(endpoint)) == 0) {

+ +			if (memdev->endpoint && memdev->endpoint != endpoint)

+ +				err(ctx, "%s assigned to %s not %s\n",

+ +				    cxl_memdev_get_devname(memdev),

+ +				    cxl_endpoint_get_devname(memdev->endpoint),

+ +				    cxl_endpoint_get_devname(endpoint));

+ +			endpoint->memdev = memdev;

+ +			memdev->endpoint = endpoint;

+ +			return memdev;

+ +		}

+ +

+ +	return NULL;

+ +}

+ +

+  static void *add_cxl_port(void *parent, int id, const char *cxlport_base)

+  {

+  	const char *devname = devpath_to_devname(cxlport_base);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 8f0688a..321acac 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -106,4 +106,7 @@ global:

+  	cxl_endpoint_get_parent;

+  	cxl_endpoint_get_port;

+  	cxl_endpoint_get_host;

+ +	cxl_endpoint_get_memdev;

+ +	cxl_memdev_get_endpoint;

+ +	cxl_memdev_is_enabled;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 5487b55..790ece8 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -46,6 +46,8 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+  size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);

+ +struct cxl_endpoint;

+ +struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);

+  int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);

+  int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,

+  		size_t offset);

+ @@ -100,6 +102,8 @@ int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+  const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);

+ +struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint);

+ +int cxl_memdev_is_enabled(struct cxl_memdev *memdev);

+  

+  #define cxl_endpoint_foreach(port, endpoint)                                   \

+  	for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;        \

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,329 @@ 

+ From b90fc91e1034668cfde06f0fd8a7293df8b7690d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:50 -0800

+ Subject: [PATCH 109/217] cxl/list: Filter memdev by ancestry

+ 

+ Whenever a memdev filter is specified limit output of buses, ports and

+ endpoints to those that are in the memdev's ancestry.

+ 

+ Link: https://lore.kernel.org/r/164298563039.3021641.5253222797042241091.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt   | 19 +++++++++

+  Documentation/cxl/lib/libcxl.txt | 11 +++++

+  cxl/filter.c                     | 69 ++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.c                 | 36 +++++++++++++++++

+  cxl/lib/libcxl.sym               |  5 +++

+  cxl/libcxl.h                     |  4 ++

+  6 files changed, 144 insertions(+)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 1751868..bac27c7 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -39,6 +39,25 @@ they are combined as an 'AND' filter. So, "-m mem0,mem1,mem2 -p port10"

+  would only list objects that are beneath port10 AND map mem0, mem1, OR

+  mem2.

+  

+ +Given that many topology queries seek to answer questions relative to a

+ +given memdev, buses, ports, and endpoints can be filtered by one or more

+ +memdevs. For example:

+ +----

+ +# cxl list -P -p switch,endpoint -m mem0

+ +[

+ +  {

+ +    "port":"port1",

+ +    "host":"ACPI0016:00",

+ +    "endpoints:port1":[

+ +      {

+ +        "endpoint":"endpoint2",

+ +        "host":"mem0"

+ +      }

+ +    ]

+ +  }

+ +]

+ +----

+ +

+  The --human option in addition to reformatting some fields to more human

+  friendly strings also unwraps the array to reduce the number of lines of

+  output.

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 73b0fb9..b0253d7 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -150,11 +150,18 @@ cxl_bus'.

+  ----

+  struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx);

+  struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);

+ +struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus);

+ +struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev);

+ +struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint);

+  

+  #define cxl_bus_foreach(ctx, bus)                                           \

+         for (bus = cxl_bus_get_first(ctx); bus != NULL;                      \

+              bus = cxl_bus_get_next(bus))

+  ----

+ +When a memdev is active it has established a CXL port hierarchy between

+ +itself and the root of its associated CXL topology. The

+ +cxl_{memdev,endpoint}_get_bus() helpers walk that topology to retrieve

+ +the associated bus object.

+  

+  === BUS: Attributes

+  ----

+ @@ -209,6 +216,7 @@ int cxl_port_is_enabled(struct cxl_port *port);

+  bool cxl_port_is_root(struct cxl_port *port);

+  bool cxl_port_is_switch(struct cxl_port *port);

+  bool cxl_port_is_endpoint(struct cxl_port *port);

+ +bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);

+  ----

+  The port type is communicated via cxl_port_is_<type>(). An 'enabled' port

+  is one that has succeeded in discovering the CXL component registers in

+ @@ -217,6 +225,9 @@ memdev to be enabled for CXL memory operation all CXL ports in its

+  ancestry must also be enabled including a root port, an arbitrary number

+  of intervening switch ports, and a terminal endpoint port.

+  

+ +cxl_port_hosts_memdev() returns true if the port's host appears in the

+ +memdev host's device topology ancestry.

+ +

+  ENDPOINTS

+  ---------

+  CXL endpoint objects encapsulate the set of host-managed device-memory

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 2130816..6dc61a1 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -297,6 +297,66 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  	return NULL;

+  }

+  

+ +static struct cxl_bus *util_cxl_bus_filter_by_memdev(struct cxl_bus *bus,

+ +						     const char *ident,

+ +						     const char *serial)

+ +{

+ +	struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (!ident && !serial)

+ +		return bus;

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		if (!util_cxl_memdev_filter(memdev, ident, serial))

+ +			continue;

+ +		if (cxl_memdev_get_bus(memdev) == bus)

+ +			return bus;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+ +static struct cxl_endpoint *

+ +util_cxl_endpoint_filter_by_memdev(struct cxl_endpoint *endpoint,

+ +				   const char *ident, const char *serial)

+ +{

+ +	struct cxl_ctx *ctx = cxl_endpoint_get_ctx(endpoint);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (!ident && !serial)

+ +		return endpoint;

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		if (!util_cxl_memdev_filter(memdev, ident, serial))

+ +			continue;

+ +		if (cxl_memdev_get_endpoint(memdev) == endpoint)

+ +			return endpoint;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+ +static struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,

+ +						       const char *ident,

+ +						       const char *serial)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (!ident && !serial)

+ +		return port;

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		if (!util_cxl_memdev_filter(memdev, ident, serial))

+ +			continue;

+ +		if (cxl_port_hosts_memdev(port, memdev))

+ +			return port;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+  static unsigned long params_to_flags(struct cxl_filter_params *param)

+  {

+  	unsigned long flags = 0;

+ @@ -399,6 +459,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,

+  		if (!util_cxl_endpoint_filter_by_port(endpoint, p->port_filter,

+  						      pf_mode(p)))

+  			continue;

+ +		if (!util_cxl_endpoint_filter_by_memdev(

+ +			    endpoint, p->memdev_filter, p->serial_filter))

+ +			continue;

+  		if (!p->idle && !cxl_endpoint_is_enabled(endpoint))

+  			continue;

+  		if (p->endpoints) {

+ @@ -450,6 +513,9 @@ static void walk_child_ports(struct cxl_port *parent_port,

+  		struct json_object *jchildports = NULL;

+  		struct json_object *jchildeps = NULL;

+  

+ +		if (!util_cxl_port_filter_by_memdev(port, p->memdev_filter,

+ +						    p->serial_filter))

+ +			continue;

+  		if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))

+  			goto walk_children;

+  		if (!util_cxl_port_filter_by_bus(port, p->bus_filter))

+ @@ -573,6 +639,9 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  		struct cxl_port *port = cxl_bus_get_port(bus);

+  		const char *devname = cxl_bus_get_devname(bus);

+  

+ +		if (!util_cxl_bus_filter_by_memdev(bus, p->memdev_filter,

+ +						   p->serial_filter))

+ +			continue;

+  		if (!util_cxl_bus_filter(bus, p->bus_filter))

+  			goto walk_children;

+  		if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 4523ca6..0065f6b 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -455,6 +455,15 @@ CXL_EXPORT const char *cxl_memdev_get_host(struct cxl_memdev *memdev)

+  	return memdev->host;

+  }

+  

+ +CXL_EXPORT struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_endpoint *endpoint = cxl_memdev_get_endpoint(memdev);

+ +

+ +	if (!endpoint)

+ +		return NULL;

+ +	return cxl_endpoint_get_bus(endpoint);

+ +}

+ +

+  CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev)

+  {

+  	return memdev->major;

+ @@ -724,6 +733,13 @@ CXL_EXPORT const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint)

+  	return cxl_port_get_host(&endpoint->port);

+  }

+  

+ +CXL_EXPORT struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint)

+ +{

+ +	struct cxl_port *port = &endpoint->port;

+ +

+ +	return cxl_port_get_bus(port);

+ +}

+ +

+  CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)

+  {

+  	return cxl_port_is_enabled(&endpoint->port);

+ @@ -875,6 +891,21 @@ CXL_EXPORT const char *cxl_port_get_host(struct cxl_port *port)

+  	return devpath_to_devname(port->uport);

+  }

+  

+ +CXL_EXPORT bool cxl_port_hosts_memdev(struct cxl_port *port,

+ +				      struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_endpoint *endpoint = cxl_memdev_get_endpoint(memdev);

+ +	struct cxl_port *iter;

+ +

+ +	if (!endpoint)

+ +		return false;

+ +

+ +	iter = cxl_endpoint_get_port(endpoint);

+ +	while (iter && iter != port)

+ +		iter = iter->parent;

+ +	return iter != NULL;

+ +}

+ +

+  CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)

+  {

+  	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ @@ -985,6 +1016,11 @@ CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus)

+  	return devname;

+  }

+  

+ +CXL_EXPORT struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus)

+ +{

+ +	return cxl_port_get_ctx(&bus->port);

+ +}

+ +

+  CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)

+  {

+  	if (!cmd)

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 321acac..29f3498 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -84,6 +84,7 @@ global:

+  	cxl_bus_get_devname;

+  	cxl_bus_get_id;

+  	cxl_bus_get_port;

+ +	cxl_bus_get_ctx;

+  	cxl_port_get_first;

+  	cxl_port_get_next;

+  	cxl_port_get_devname;

+ @@ -97,6 +98,8 @@ global:

+  	cxl_port_is_endpoint;

+  	cxl_port_get_bus;

+  	cxl_port_get_host;

+ +	cxl_port_get_bus;

+ +	cxl_port_hosts_memdev;

+  	cxl_endpoint_get_first;

+  	cxl_endpoint_get_next;

+  	cxl_endpoint_get_devname;

+ @@ -107,6 +110,8 @@ global:

+  	cxl_endpoint_get_port;

+  	cxl_endpoint_get_host;

+  	cxl_endpoint_get_memdev;

+ +	cxl_endpoint_get_bus;

+  	cxl_memdev_get_endpoint;

+  	cxl_memdev_is_enabled;

+ +	cxl_memdev_get_bus;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 790ece8..e7b675e 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -39,6 +39,7 @@ int cxl_memdev_get_id(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_host(struct cxl_memdev *memdev);

+ +struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev);

+  int cxl_memdev_get_major(struct cxl_memdev *memdev);

+  int cxl_memdev_get_minor(struct cxl_memdev *memdev);

+  struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);

+ @@ -68,6 +69,7 @@ const char *cxl_bus_get_provider(struct cxl_bus *bus);

+  const char *cxl_bus_get_devname(struct cxl_bus *bus);

+  int cxl_bus_get_id(struct cxl_bus *bus);

+  struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);

+ +struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus);

+  

+  #define cxl_bus_foreach(ctx, bus)                                              \

+  	for (bus = cxl_bus_get_first(ctx); bus != NULL;                        \

+ @@ -87,6 +89,7 @@ struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);

+  bool cxl_port_is_endpoint(struct cxl_port *port);

+  struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+  const char *cxl_port_get_host(struct cxl_port *port);

+ +bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);

+  

+  #define cxl_port_foreach(parent, port)                                         \

+  	for (port = cxl_port_get_first(parent); port != NULL;                  \

+ @@ -102,6 +105,7 @@ int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+  const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);

+ +struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint);

+  struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint);

+  int cxl_memdev_is_enabled(struct cxl_memdev *memdev);

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,173 @@ 

+ From 5e1c1ab5bf6b6257552ad9fa242483ec1c1de006 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:53:55 -0800

+ Subject: [PATCH 110/217] cxl/memdev: Use a local logger for debug

+ 

+ The "fail()" macro skips some of the nicer features of the centralized

+ logger. Add one to supplement the library logger.

+ 

+ Link: https://lore.kernel.org/r/164298563547.3021641.16504008034705274247.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/memdev.c | 48 ++++++++++++++++++++++++------------------------

+  1 file changed, 24 insertions(+), 24 deletions(-)

+ 

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index b9141be..327c260 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -26,11 +26,7 @@ static struct parameters {

+  	bool verbose;

+  } param;

+  

+ -#define fail(fmt, ...) \

+ -do { \

+ -	fprintf(stderr, "cxl-%s:%s:%d: " fmt, \

+ -			VERSION, __func__, __LINE__, ##__VA_ARGS__); \

+ -} while (0)

+ +static struct log_ctx ml;

+  

+  #define BASE_OPTIONS() \

+  OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug")

+ @@ -79,7 +75,7 @@ static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)

+  		size = cxl_memdev_get_label_size(memdev);

+  

+  	if (cxl_memdev_nvdimm_bridge_active(memdev)) {

+ -		fprintf(stderr,

+ +		log_err(&ml,

+  			"%s: has active nvdimm bridge, abort label write\n",

+  			cxl_memdev_get_devname(memdev));

+  		return -EBUSY;

+ @@ -87,7 +83,7 @@ static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)

+  

+  	rc = cxl_memdev_zero_label(memdev, size, param.offset);

+  	if (rc < 0)

+ -		fprintf(stderr, "%s: label zeroing failed: %s\n",

+ +		log_err(&ml, "%s: label zeroing failed: %s\n",

+  			cxl_memdev_get_devname(memdev), strerror(-rc));

+  

+  	return rc;

+ @@ -100,7 +96,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx)

+  	int rc;

+  

+  	if (cxl_memdev_nvdimm_bridge_active(memdev)) {

+ -		fprintf(stderr,

+ +		log_err(&ml,

+  			"%s: has active nvdimm bridge, abort label write\n",

+  			cxl_memdev_get_devname(memdev));

+  		return -EBUSY;

+ @@ -114,7 +110,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx)

+  		fseek(actx->f_in, 0L, SEEK_SET);

+  

+  		if (size > label_size) {

+ -			fprintf(stderr,

+ +			log_err(&ml,

+  				"File size (%zu) greater than label area size (%zu), aborting\n",

+  				size, label_size);

+  			return -EINVAL;

+ @@ -133,7 +129,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx)

+  

+  	rc = cxl_memdev_write_label(memdev, buf, size, param.offset);

+  	if (rc < 0)

+ -		fprintf(stderr, "%s: label write failed: %s\n",

+ +		log_err(&ml, "%s: label write failed: %s\n",

+  			cxl_memdev_get_devname(memdev), strerror(-rc));

+  

+  out:

+ @@ -158,7 +154,7 @@ static int action_read(struct cxl_memdev *memdev, struct action_context *actx)

+  

+  	rc = cxl_memdev_read_label(memdev, buf, size, param.offset);

+  	if (rc < 0) {

+ -		fprintf(stderr, "%s: label read failed: %s\n",

+ +		log_err(&ml, "%s: label read failed: %s\n",

+  			cxl_memdev_get_devname(memdev), strerror(-rc));

+  		goto out;

+  	}

+ @@ -188,6 +184,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	};

+  	unsigned long id;

+  

+ +	log_init(&ml, "cxl memdev", "CXL_MEMDEV_LOG");

+  	argc = parse_options(argc, argv, options, u, 0);

+  

+  	if (argc == 0)

+ @@ -200,8 +197,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  		}

+  

+  		if (sscanf(argv[i], "mem%lu", &id) != 1) {

+ -			fprintf(stderr, "'%s' is not a valid memdev name\n",

+ -					argv[i]);

+ +			log_err(&ml, "'%s' is not a valid memdev name\n",

+ +				argv[i]);

+  			err++;

+  		}

+  	}

+ @@ -216,8 +213,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	else {

+  		actx.f_out = fopen(param.outfile, "w+");

+  		if (!actx.f_out) {

+ -			fprintf(stderr, "failed to open: %s: (%s)\n",

+ -					param.outfile, strerror(errno));

+ +			log_err(&ml, "failed to open: %s: (%s)\n",

+ +				param.outfile, strerror(errno));

+  			rc = -errno;

+  			goto out;

+  		}

+ @@ -228,15 +225,18 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	} else {

+  		actx.f_in = fopen(param.infile, "r");

+  		if (!actx.f_in) {

+ -			fprintf(stderr, "failed to open: %s: (%s)\n",

+ -					param.infile, strerror(errno));

+ +			log_err(&ml, "failed to open: %s: (%s)\n", param.infile,

+ +				strerror(errno));

+  			rc = -errno;

+  			goto out_close_fout;

+  		}

+  	}

+  

+ -	if (param.verbose)

+ +	if (param.verbose) {

+  		cxl_set_log_priority(ctx, LOG_DEBUG);

+ +		ml.log_priority = LOG_DEBUG;

+ +	} else

+ +		ml.log_priority = LOG_INFO;

+  

+  	rc = 0;

+  	err = 0;

+ @@ -299,8 +299,8 @@ int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx)

+  	int count = memdev_action(argc, argv, ctx, action_write, write_options,

+  			"cxl write-labels <memdev> [-i <filename>]");

+  

+ -	fprintf(stderr, "wrote %d mem%s\n", count >= 0 ? count : 0,

+ -			count > 1 ? "s" : "");

+ +	log_info(&ml, "wrote %d mem%s\n", count >= 0 ? count : 0,

+ +		 count > 1 ? "s" : "");

+  	return count >= 0 ? 0 : EXIT_FAILURE;

+  }

+  

+ @@ -309,8 +309,8 @@ int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx)

+  	int count = memdev_action(argc, argv, ctx, action_read, read_options,

+  			"cxl read-labels <mem0> [<mem1>..<memN>] [-o <filename>]");

+  

+ -	fprintf(stderr, "read %d mem%s\n", count >= 0 ? count : 0,

+ -			count > 1 ? "s" : "");

+ +	log_info(&ml, "read %d mem%s\n", count >= 0 ? count : 0,

+ +		 count > 1 ? "s" : "");

+  	return count >= 0 ? 0 : EXIT_FAILURE;

+  }

+  

+ @@ -319,7 +319,7 @@ int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx)

+  	int count = memdev_action(argc, argv, ctx, action_zero, zero_options,

+  			"cxl zero-labels <mem0> [<mem1>..<memN>] [<options>]");

+  

+ -	fprintf(stderr, "zeroed %d mem%s\n", count >= 0 ? count : 0,

+ -			count > 1 ? "s" : "");

+ +	log_info(&ml, "zeroed %d mem%s\n", count >= 0 ? count : 0,

+ +		 count > 1 ? "s" : "");

+  	return count >= 0 ? 0 : EXIT_FAILURE;

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,64 @@ 

+ From 6cab8e0186e73af75f0a15ce87c4db20ef0089df Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:01 -0800

+ Subject: [PATCH 111/217] cxl/memdev: Cleanup memdev filter

+ 

+ util_cxl_memdev_filter() already handles the difference between 'mem%d',

+ '%d', and 'all' for the identifier format. Drop the duplicate / incomplete

+ format checking.

+ 

+ If the checking for bad formats was dropped too then this command could

+ support "0,1,2" syntax in addition to "0 1 2" like 'cxl list'. However, it is

+ not clear that's worthwhile since 'list' is ok to be imprecise, but memdev

+ commands need to be stricter.

+ 

+ Link: https://lore.kernel.org/r/164298564100.3021641.9410483964085163708.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/memdev.c | 18 +++++++-----------

+  1 file changed, 7 insertions(+), 11 deletions(-)

+ 

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index 327c260..4cca8b8 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -191,16 +191,16 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  		usage_with_options(u, options);

+  	for (i = 0; i < argc; i++) {

+  		if (strcmp(argv[i], "all") == 0) {

+ -			argv[0] = "all";

+  			argc = 1;

+  			break;

+  		}

+ +		if (sscanf(argv[i], "mem%lu", &id) == 1)

+ +			continue;

+ +		if (sscanf(argv[i], "%lu", &id) == 1)

+ +			continue;

+  

+ -		if (sscanf(argv[i], "mem%lu", &id) != 1) {

+ -			log_err(&ml, "'%s' is not a valid memdev name\n",

+ -				argv[i]);

+ -			err++;

+ -		}

+ +		log_err(&ml, "'%s' is not a valid memdev name\n", argv[i]);

+ +		err++;

+  	}

+  

+  	if (err == argc) {

+ @@ -243,11 +243,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	count = 0;

+  

+  	for (i = 0; i < argc; i++) {

+ -		if (sscanf(argv[i], "mem%lu", &id) != 1

+ -				&& strcmp(argv[i], "all") != 0)

+ -			continue;

+ -

+ -		cxl_memdev_foreach (ctx, memdev) {

+ +		cxl_memdev_foreach(ctx, memdev) {

+  			if (!util_cxl_memdev_filter(memdev, argv[i], NULL))

+  				continue;

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,133 @@ 

+ From c09c507e5a608718ac96af088fdc8cb441b09d0b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:06 -0800

+ Subject: [PATCH 112/217] cxl/memdev: Add serial support for memdev-related

+  commands

+ 

+ Allow for a "-s, --serial" option to turn the argument list into serial

+ identifiers.

+ 

+ Link: https://lore.kernel.org/r/164298564631.3021641.5552442288217413180.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/memdev-option.txt |  5 ++++

+  Documentation/cxl/meson.build       |  4 ++-

+  cxl/memdev.c                        | 45 +++++++++++++++++++++--------

+  3 files changed, 41 insertions(+), 13 deletions(-)

+ 

+ diff --git a/Documentation/cxl/memdev-option.txt b/Documentation/cxl/memdev-option.txt

+ index e778582..64348be 100644

+ --- a/Documentation/cxl/memdev-option.txt

+ +++ b/Documentation/cxl/memdev-option.txt

+ @@ -2,3 +2,8 @@

+  A 'memX' device name, or a memdev id number. Restrict the operation to

+  the specified memdev(s). The keyword 'all' can be specified to indicate

+  the lack of any restriction.

+ +

+ +-S::

+ +--serial::

+ +	Rather an a memdev id number, interpret the <memdev> argument(s)

+ +	as a list of serial numbers.

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index 64ce13f..0a6346b 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -19,7 +19,9 @@ else

+  endif

+  

+  filedeps = [

+ -        '../copyright.txt',

+ +  '../copyright.txt',

+ +  'memdev-option.txt',

+ +  'labels-options.txt',

+  ]

+  

+  cxl_manpages = [

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index 4cca8b8..ef5343a 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -24,12 +24,14 @@ static struct parameters {

+  	unsigned len;

+  	unsigned offset;

+  	bool verbose;

+ +	bool serial;

+  } param;

+  

+  static struct log_ctx ml;

+  

+  #define BASE_OPTIONS() \

+ -OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug")

+ +OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug"), \

+ +OPT_BOOLEAN('S', "serial", &param.serial, "user serials numbers to id memdevs")

+  

+  #define READ_OPTIONS() \

+  OPT_STRING('o', "output", &param.outfile, "output-file", \

+ @@ -172,8 +174,9 @@ out:

+  }

+  

+  static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+ -		int (*action)(struct cxl_memdev *memdev, struct action_context *actx),

+ -		const struct option *options, const char *usage)

+ +			 int (*action)(struct cxl_memdev *memdev,

+ +				       struct action_context *actx),

+ +			 const struct option *options, const char *usage)

+  {

+  	struct cxl_memdev *memdev, *single = NULL;

+  	struct action_context actx = { 0 };

+ @@ -190,16 +193,25 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	if (argc == 0)

+  		usage_with_options(u, options);

+  	for (i = 0; i < argc; i++) {

+ -		if (strcmp(argv[i], "all") == 0) {

+ -			argc = 1;

+ -			break;

+ +		if (param.serial) {

+ +			char *end;

+ +

+ +			strtoull(argv[i], &end, 0);

+ +			if (end[0] == 0)

+ +				continue;

+ +		} else {

+ +			if (strcmp(argv[i], "all") == 0) {

+ +				argc = 1;

+ +				break;

+ +			}

+ +			if (sscanf(argv[i], "mem%lu", &id) == 1)

+ +				continue;

+ +			if (sscanf(argv[i], "%lu", &id) == 1)

+ +				continue;

+  		}

+ -		if (sscanf(argv[i], "mem%lu", &id) == 1)

+ -			continue;

+ -		if (sscanf(argv[i], "%lu", &id) == 1)

+ -			continue;

+  

+ -		log_err(&ml, "'%s' is not a valid memdev name\n", argv[i]);

+ +		log_err(&ml, "'%s' is not a valid memdev %s\n", argv[i],

+ +			param.serial ? "serial number" : "name");

+  		err++;

+  	}

+  

+ @@ -244,7 +256,16 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  

+  	for (i = 0; i < argc; i++) {

+  		cxl_memdev_foreach(ctx, memdev) {

+ -			if (!util_cxl_memdev_filter(memdev, argv[i], NULL))

+ +			const char *memdev_filter = NULL;

+ +			const char *serial_filter = NULL;

+ +

+ +			if (param.serial)

+ +				serial_filter = argv[i];

+ +			else

+ +				memdev_filter = argv[i];

+ +

+ +			if (!util_cxl_memdev_filter(memdev, memdev_filter,

+ +						    serial_filter))

+  				continue;

+  

+  			if (action == action_write) {

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,136 @@ 

+ From ca582b2003a2335eafac382e71afdf0a6caaef18 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:11 -0800

+ Subject: [PATCH 113/217] cxl/list: Add 'numa_node' to memdev listings

+ 

+ If the kernel exports a valid numa_node, >= 0, include it in memdev objects

+ listings.

+ 

+ Link: https://lore.kernel.org/r/164298565156.3021641.14097226245654611710.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  4 ++++

+  cxl/json.c                       |  8 ++++++++

+  cxl/lib/libcxl.c                 | 11 +++++++++++

+  cxl/lib/libcxl.sym               |  1 +

+  cxl/lib/private.h                |  1 +

+  cxl/libcxl.h                     |  1 +

+  6 files changed, 26 insertions(+)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index b0253d7..de88d19 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -71,6 +71,7 @@ unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+  size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);

+  int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);

+ +int cxl_memdev_get_numa_node(struct cxl_memdev *memdev);

+  ----

+  

+  A memdev is given a kernel device name of the form "mem%d" where an id

+ @@ -89,6 +90,9 @@ The 'pmem_size' and 'ram_size' attributes return the current

+  provisioning of DPA (Device Physical Address / local capacity) in the

+  device.

+  

+ +cxl_memdev_get_numa_node() returns the affinitized CPU node number if

+ +available or -1 otherwise.

+ +

+  === MEMDEV: Commands

+  ----

+  struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ diff --git a/cxl/json.c b/cxl/json.c

+ index b809332..51918d6 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -190,6 +190,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  	const char *devname = cxl_memdev_get_devname(memdev);

+  	struct json_object *jdev, *jobj;

+  	unsigned long long serial;

+ +	int numa_node;

+  

+  	jdev = json_object_new_object();

+  	if (!jdev)

+ @@ -220,6 +221,13 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  			json_object_object_add(jdev, "serial", jobj);

+  	}

+  

+ +	numa_node = cxl_memdev_get_numa_node(memdev);

+ +	if (numa_node >= 0) {

+ +		jobj = json_object_new_int(numa_node);

+ +		if (jobj)

+ +			json_object_object_add(jdev, "numa_node", jobj);

+ +	}

+ +

+  	jobj = json_object_new_string(cxl_memdev_get_host(memdev));

+  	if (jobj)

+  		json_object_object_add(jdev, "host", jobj);

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 0065f6b..14c7db8 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -348,6 +348,12 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)

+  	else

+  		memdev->serial = strtoull(buf, NULL, 0);

+  

+ +	sprintf(path, "%s/numa_node", cxlmem_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		memdev->numa_node = -1;

+ +	else

+ +		memdev->numa_node = strtol(buf, NULL, 0);

+ +

+  	memdev->dev_path = strdup(cxlmem_base);

+  	if (!memdev->dev_path)

+  		goto err_read;

+ @@ -445,6 +451,11 @@ CXL_EXPORT unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev)

+  	return memdev->serial;

+  }

+  

+ +CXL_EXPORT int cxl_memdev_get_numa_node(struct cxl_memdev *memdev)

+ +{

+ +	return memdev->numa_node;

+ +}

+ +

+  CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)

+  {

+  	return devpath_to_devname(memdev->dev_path);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 29f3498..b13a2d6 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -77,6 +77,7 @@ local:

+  LIBCXL_2 {

+  global:

+  	cxl_memdev_get_serial;

+ +	cxl_memdev_get_numa_node;

+  	cxl_memdev_get_host;

+  	cxl_bus_get_first;

+  	cxl_bus_get_next;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index b097bdf..c00bb36 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -20,6 +20,7 @@ struct cxl_pmem {

+  struct cxl_endpoint;

+  struct cxl_memdev {

+  	int id, major, minor;

+ +	int numa_node;

+  	void *dev_buf;

+  	size_t buf_len;

+  	char *host;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index e7b675e..be656ed 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -37,6 +37,7 @@ struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);

+  struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);

+  int cxl_memdev_get_id(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);

+ +int cxl_memdev_get_numa_node(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_host(struct cxl_memdev *memdev);

+  struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,329 @@ 

+ From e31fc778998b4d02ffec68e61869aaeccfd99be8 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:17 -0800

+ Subject: [PATCH 114/217] util: Implement common bind/unbind helpers

+ 

+ Refactor ndctl_{bind,unbind}() into util_{bind,unbind}() for libcxl to

+ reuse.

+ 

+ daxctl can not join the party for now as it needs to play games with

+ 'new_id'.

+ 

+ Link: https://lore.kernel.org/r/164298565707.3021641.7763459936156744907.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 103 +++++--------------------------------------

+  util/sysfs.c         |  76 +++++++++++++++++++++++++++++++

+  util/sysfs.h         |   8 ++++

+  3 files changed, 96 insertions(+), 91 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 1374ad9..98d184b 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -1665,10 +1665,6 @@ static enum ndctl_fwa_result fwa_result_to_result(const char *result)

+  	return NDCTL_FWA_RESULT_INVALID;

+  }

+  

+ -static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,

+ -		const char *devname);

+ -static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath);

+ -

+  static int populate_dimm_attributes(struct ndctl_dimm *dimm,

+  				    const char *dimm_base,

+  				    const char *bus_prefix)

+ @@ -2305,7 +2301,7 @@ NDCTL_EXPORT int ndctl_dimm_disable(struct ndctl_dimm *dimm)

+  	if (!ndctl_dimm_is_enabled(dimm))

+  		return 0;

+  

+ -	ndctl_unbind(ctx, dimm->dimm_path);

+ +	util_unbind(dimm->dimm_path, ctx);

+  

+  	if (ndctl_dimm_is_enabled(dimm)) {

+  		err(ctx, "%s: failed to disable\n", devname);

+ @@ -2324,7 +2320,7 @@ NDCTL_EXPORT int ndctl_dimm_enable(struct ndctl_dimm *dimm)

+  	if (ndctl_dimm_is_enabled(dimm))

+  		return 0;

+  

+ -	ndctl_bind(ctx, dimm->module, devname);

+ +	util_bind(devname, dimm->module, "nd", ctx);

+  

+  	if (!ndctl_dimm_is_enabled(dimm)) {

+  		err(ctx, "%s: failed to enable\n", devname);

+ @@ -3573,7 +3569,7 @@ NDCTL_EXPORT int ndctl_region_enable(struct ndctl_region *region)

+  	if (ndctl_region_is_enabled(region))

+  		return 0;

+  

+ -	ndctl_bind(ctx, region->module, devname);

+ +	util_bind(devname, region->module, "nd", ctx);

+  

+  	if (!ndctl_region_is_enabled(region)) {

+  		err(ctx, "%s: failed to enable\n", devname);

+ @@ -3610,7 +3606,7 @@ static int ndctl_region_disable(struct ndctl_region *region, int cleanup)

+  	if (!ndctl_region_is_enabled(region))

+  		return 0;

+  

+ -	ndctl_unbind(ctx, region->region_path);

+ +	util_unbind(region->region_path, ctx);

+  

+  	if (ndctl_region_is_enabled(region)) {

+  		err(ctx, "%s: failed to disable\n", devname);

+ @@ -4373,81 +4369,6 @@ NDCTL_EXPORT struct badblock *ndctl_namespace_get_first_badblock(

+  	return badblocks_iter_first(&ndns->bb_iter, ctx, path);

+  }

+  

+ -static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,

+ -		const char *devname)

+ -{

+ -	DIR *dir;

+ -	int rc = 0;

+ -	char path[200];

+ -	struct dirent *de;

+ -	const int len = sizeof(path);

+ -

+ -	if (!devname) {

+ -		err(ctx, "missing devname\n");

+ -		return -EINVAL;

+ -	}

+ -

+ -	if (module) {

+ -		rc = kmod_module_probe_insert_module(module,

+ -				KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL,

+ -				NULL);

+ -		if (rc < 0) {

+ -			err(ctx, "%s: insert failure: %d\n", __func__, rc);

+ -			return rc;

+ -		}

+ -	}

+ -

+ -	if (snprintf(path, len, "/sys/bus/nd/drivers") >= len) {

+ -		err(ctx, "%s: buffer too small!\n", devname);

+ -		return -ENXIO;

+ -	}

+ -

+ -	dir = opendir(path);

+ -	if (!dir) {

+ -		err(ctx, "%s: opendir(\"%s\") failed\n", devname, path);

+ -		return -ENXIO;

+ -	}

+ -

+ -	while ((de = readdir(dir)) != NULL) {

+ -		char *drv_path;

+ -

+ -		if (de->d_ino == 0)

+ -			continue;

+ -		if (de->d_name[0] == '.')

+ -			continue;

+ -		if (asprintf(&drv_path, "%s/%s/bind", path, de->d_name) < 0) {

+ -			err(ctx, "%s: path allocation failure\n", devname);

+ -			continue;

+ -		}

+ -

+ -		rc = sysfs_write_attr_quiet(ctx, drv_path, devname);

+ -		free(drv_path);

+ -		if (rc == 0)

+ -			break;

+ -	}

+ -	closedir(dir);

+ -

+ -	if (rc) {

+ -		dbg(ctx, "%s: bind failed\n", devname);

+ -		return -ENXIO;

+ -	}

+ -	return 0;

+ -}

+ -

+ -static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath)

+ -{

+ -	const char *devname = devpath_to_devname(devpath);

+ -	char path[200];

+ -	const int len = sizeof(path);

+ -

+ -	if (snprintf(path, len, "%s/driver/unbind", devpath) >= len) {

+ -		err(ctx, "%s: buffer too small!\n", devname);

+ -		return -ENXIO;

+ -	}

+ -

+ -	return sysfs_write_attr(ctx, path, devname);

+ -}

+ -

+  static void *add_btt(void *parent, int id, const char *btt_base);

+  static void *add_pfn(void *parent, int id, const char *pfn_base);

+  static void *add_dax(void *parent, int id, const char *dax_base);

+ @@ -4533,7 +4454,7 @@ NDCTL_EXPORT int ndctl_namespace_enable(struct ndctl_namespace *ndns)

+  	if (ndctl_namespace_is_enabled(ndns))

+  		return 0;

+  

+ -	rc = ndctl_bind(ctx, ndns->module, devname);

+ +	rc = util_bind(devname, ndns->module, "nd", ctx);

+  

+  	/*

+  	 * Rescan now as successfully enabling a namespace device leads

+ @@ -4581,7 +4502,7 @@ NDCTL_EXPORT int ndctl_namespace_disable(struct ndctl_namespace *ndns)

+  	if (!ndctl_namespace_is_enabled(ndns))

+  		return 0;

+  

+ -	ndctl_unbind(ctx, ndns->ndns_path);

+ +	util_unbind(ndns->ndns_path, ctx);

+  

+  	if (ndctl_namespace_is_enabled(ndns)) {

+  		err(ctx, "%s: failed to disable\n", devname);

+ @@ -5420,7 +5341,7 @@ NDCTL_EXPORT int ndctl_btt_enable(struct ndctl_btt *btt)

+  	if (ndctl_btt_is_enabled(btt))

+  		return 0;

+  

+ -	ndctl_bind(ctx, btt->module, devname);

+ +	util_bind(devname, btt->module, "nd", ctx);

+  

+  	if (!ndctl_btt_is_enabled(btt)) {

+  		err(ctx, "%s: failed to enable\n", devname);

+ @@ -5457,7 +5378,7 @@ NDCTL_EXPORT int ndctl_btt_delete(struct ndctl_btt *btt)

+  		return 0;

+  	}

+  

+ -	ndctl_unbind(ctx, btt->btt_path);

+ +	util_unbind(btt->btt_path, ctx);

+  

+  	rc = ndctl_btt_set_namespace(btt, NULL);

+  	if (rc) {

+ @@ -5908,7 +5829,7 @@ NDCTL_EXPORT int ndctl_pfn_enable(struct ndctl_pfn *pfn)

+  	if (ndctl_pfn_is_enabled(pfn))

+  		return 0;

+  

+ -	ndctl_bind(ctx, pfn->module, devname);

+ +	util_bind(devname, pfn->module, "nd", ctx);

+  

+  	if (!ndctl_pfn_is_enabled(pfn)) {

+  		err(ctx, "%s: failed to enable\n", devname);

+ @@ -5945,7 +5866,7 @@ NDCTL_EXPORT int ndctl_pfn_delete(struct ndctl_pfn *pfn)

+  		return 0;

+  	}

+  

+ -	ndctl_unbind(ctx, pfn->pfn_path);

+ +	util_unbind(pfn->pfn_path, ctx);

+  

+  	rc = ndctl_pfn_set_namespace(pfn, NULL);

+  	if (rc) {

+ @@ -6101,7 +6022,7 @@ NDCTL_EXPORT int ndctl_dax_enable(struct ndctl_dax *dax)

+  	if (ndctl_dax_is_enabled(dax))

+  		return 0;

+  

+ -	ndctl_bind(ctx, pfn->module, devname);

+ +	util_bind(devname, pfn->module, "nd", ctx);

+  

+  	if (!ndctl_dax_is_enabled(dax)) {

+  		err(ctx, "%s: failed to enable\n", devname);

+ @@ -6132,7 +6053,7 @@ NDCTL_EXPORT int ndctl_dax_delete(struct ndctl_dax *dax)

+  		return 0;

+  	}

+  

+ -	ndctl_unbind(ctx, pfn->pfn_path);

+ +	util_unbind(pfn->pfn_path, ctx);

+  

+  	rc = ndctl_dax_set_namespace(dax, NULL);

+  	if (rc) {

+ diff --git a/util/sysfs.c b/util/sysfs.c

+ index 23330cb..968683b 100644

+ --- a/util/sysfs.c

+ +++ b/util/sysfs.c

+ @@ -145,3 +145,79 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,

+  

+  	return mod;

+  }

+ +

+ +int __util_bind(const char *devname, struct kmod_module *module,

+ +		const char *bus, struct log_ctx *ctx)

+ +{

+ +	DIR *dir;

+ +	int rc = 0;

+ +	char path[200];

+ +	struct dirent *de;

+ +	const int len = sizeof(path);

+ +

+ +	if (!devname) {

+ +		log_err(ctx, "missing devname\n");

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (module) {

+ +		rc = kmod_module_probe_insert_module(module,

+ +						     KMOD_PROBE_APPLY_BLACKLIST,

+ +						     NULL, NULL, NULL, NULL);

+ +		if (rc < 0) {

+ +			log_err(ctx, "%s: insert failure: %d\n", __func__, rc);

+ +			return rc;

+ +		}

+ +	}

+ +

+ +	if (snprintf(path, len, "/sys/bus/%s/drivers", bus) >= len) {

+ +		log_err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	dir = opendir(path);

+ +	if (!dir) {

+ +		log_err(ctx, "%s: opendir(\"%s\") failed\n", devname, path);

+ +		return -ENXIO;

+ +	}

+ +

+ +	while ((de = readdir(dir)) != NULL) {

+ +		char *drv_path;

+ +

+ +		if (de->d_ino == 0)

+ +			continue;

+ +		if (de->d_name[0] == '.')

+ +			continue;

+ +

+ +		if (asprintf(&drv_path, "%s/%s/bind", path, de->d_name) < 0) {

+ +			log_err(ctx, "%s: path allocation failure\n", devname);

+ +			continue;

+ +		}

+ +

+ +		rc = __sysfs_write_attr_quiet(ctx, drv_path, devname);

+ +		free(drv_path);

+ +		if (rc == 0)

+ +			break;

+ +	}

+ +	closedir(dir);

+ +

+ +	if (rc) {

+ +		log_dbg(ctx, "%s: bind failed\n", devname);

+ +		return -ENXIO;

+ +	}

+ +	return 0;

+ +}

+ +

+ +int __util_unbind(const char *devpath, struct log_ctx *ctx)

+ +{

+ +	const char *devname = devpath_to_devname(devpath);

+ +	char path[200];

+ +	const int len = sizeof(path);

+ +

+ +	if (snprintf(path, len, "%s/driver/unbind", devpath) >= len) {

+ +		log_err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	return __sysfs_write_attr(ctx, path, devname);

+ +}

+ diff --git a/util/sysfs.h b/util/sysfs.h

+ index bdee4f5..4c95c70 100644

+ --- a/util/sysfs.h

+ +++ b/util/sysfs.h

+ @@ -35,4 +35,12 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,

+  					      struct log_ctx *log);

+  #define util_modalias_to_module(ctx, buf)                                      \

+  	__util_modalias_to_module((ctx)->kmod_ctx, buf, &(ctx)->ctx)

+ +

+ +int __util_bind(const char *devname, struct kmod_module *module, const char *bus,

+ +	      struct log_ctx *ctx);

+ +#define util_bind(n, m, b, c) __util_bind(n, m, b, &(c)->ctx)

+ +

+ +int __util_unbind(const char *devpath, struct log_ctx *ctx);

+ +#define util_unbind(p, c) __util_unbind(p, &(c)->ctx)

+ +

+  #endif /* __UTIL_SYSFS_H__ */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,379 @@ 

+ From 782694f9aeff6e146cfd00b31822995790546175 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:22 -0800

+ Subject: [PATCH 115/217] cxl/memdev: Enable / disable support

+ 

+ Introduce the 'cxl {enable,disable}-memdev' commands. When a memdev is

+ disabled the ports in the topology may be unregistered. CXL memory regions

+ require each endpoint in the interleave to attach to the cxl_mem driver

+ before regions are activated.

+ 

+ Note that this starts out with the deliberate bug that it has false

+ positive detection of active memdevs. The fix for that bug requires kernel

+ support to detect the device's active participation in a region, until then

+ require all disable attempts to specify the --force override. This way

+ there are never any releases of cxl-cli that lack disable-memdev safety.

+ 

+ Link: https://lore.kernel.org/r/164298566245.3021641.12696907310209056878.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-disable-memdev.txt | 37 +++++++++++++++

+  Documentation/cxl/cxl-enable-memdev.txt  | 34 ++++++++++++++

+  Documentation/cxl/lib/libcxl.txt         | 23 +++++++++

+  Documentation/cxl/meson.build            |  2 +

+  cxl/builtin.h                            |  2 +

+  cxl/cxl.c                                |  2 +

+  cxl/lib/libcxl.c                         | 58 +++++++++++++++++++++++

+  cxl/lib/libcxl.sym                       |  2 +

+  cxl/libcxl.h                             |  2 +

+  cxl/memdev.c                             | 60 +++++++++++++++++++++++-

+  10 files changed, 221 insertions(+), 1 deletion(-)

+  create mode 100644 Documentation/cxl/cxl-disable-memdev.txt

+  create mode 100644 Documentation/cxl/cxl-enable-memdev.txt

+ 

+ diff --git a/Documentation/cxl/cxl-disable-memdev.txt b/Documentation/cxl/cxl-disable-memdev.txt

+ new file mode 100644

+ index 0000000..edd5385

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-disable-memdev.txt

+ @@ -0,0 +1,37 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-disable-memdev(1)

+ +=====================

+ +

+ +NAME

+ +----

+ +cxl-disable-memdev - deactivate / hot-remove a given CXL memdev

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl disable-memdev' <mem0> [<mem1>..<memN>] [<options>]

+ +

+ +

+ +OPTIONS

+ +-------

+ +<memory device(s)>::

+ +include::memdev-option.txt[]

+ +

+ +-f::

+ +--force::

+ +	DANGEROUS: Override the safety measure that blocks attempts to disable

+ +	a device if the tool determines the memdev is in active usage. Recall

+ +	that CXL memory ranges might have been established by platform

+ +	firmware and disabling an active device is akin to force removing

+ +	memory from a running system.

+ +

+ +-v::

+ +	Turn on verbose debug messages in the library (if libcxl was built with

+ +	logging and debug enabled).

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-enable-memdev[1]

+ diff --git a/Documentation/cxl/cxl-enable-memdev.txt b/Documentation/cxl/cxl-enable-memdev.txt

+ new file mode 100644

+ index 0000000..088d5e0

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-enable-memdev.txt

+ @@ -0,0 +1,34 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-enable-memdev(1)

+ +====================

+ +

+ +NAME

+ +----

+ +cxl-enable-memdev - activate / hot-add a given CXL memdev

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl enable-memdev' <mem0> [<mem1>..<memN>] [<options>]

+ +

+ +A memdev typically autoenables at initial device discovery. However, if

+ +it was manually disabled this command can trigger the kernel to activate

+ +it again. This involves detecting the state of the HDM (Host Managed

+ +Device Memory) Decoders and validating that CXL.mem is enabled for each

+ +port in the device's hierarchy.

+ +

+ +OPTIONS

+ +-------

+ +<memory device(s)>::

+ +include::memdev-option.txt[]

+ +

+ +-v::

+ +	Turn on verbose debug messages in the library (if libcxl was built with

+ +	logging and debug enabled).

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-disable-memdev[1]

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index de88d19..49edb71 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -93,6 +93,29 @@ device.

+  cxl_memdev_get_numa_node() returns the affinitized CPU node number if

+  available or -1 otherwise.

+  

+ +=== MEMDEV: Control

+ +----

+ +int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev);

+ +int cxl_memdev_enable(struct cxl_memdev *memdev);

+ +----

+ +When a memory device is disabled it unregisters its associated endpoints

+ +and potentially intervening switch ports if there are no other memdevs

+ +pinning that port active. That means that any existing port objects that

+ +the library has previously returned are in valid and need to be re-read.

+ +Callers must be careful to re-retrieve port objects after

+ +cxl_memdev_disable_invalidate(). Any usage of a previously obtained port

+ +object after a cxl_memdev_disable_invalidate() call is a use-after-free

+ +programming error. It follows that after cxl_memdev_enable() new ports

+ +may appear in the topology that were not previously enumerable.

+ +

+ +NOTE: cxl_memdev_disable_invalidate() will force disable the memdev

+ +regardless of whether the memory provided by the device is in active use

+ +by the operating system. Callers take responisbility for assuring that

+ +it is safe to disable the memory device. Otherwise, this call can be as

+ +destructive as ripping a DIMM out of a running system. Like all other

+ +libcxl calls that mutate the system state or divulge security sensitive

+ +information this call requires root / CAP_SYS_ADMIN.

+ +

+  === MEMDEV: Commands

+  ----

+  struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index 0a6346b..7618c97 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -30,6 +30,8 @@ cxl_manpages = [

+    'cxl-read-labels.txt',

+    'cxl-write-labels.txt',

+    'cxl-zero-labels.txt',

+ +  'cxl-enable-memdev.txt',

+ +  'cxl-disable-memdev.txt',

+  ]

+  

+  foreach man : cxl_manpages

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index 78eca6e..621c85c 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -10,4 +10,6 @@ int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+  #endif /* _CXL_BUILTIN_H_ */

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index 4b1661d..78d2e9a 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -64,6 +64,8 @@ static struct cmd_struct commands[] = {

+  	{ "zero-labels", .c_fn = cmd_zero_labels },

+  	{ "read-labels", .c_fn = cmd_read_labels },

+  	{ "write-labels", .c_fn = cmd_write_labels },

+ +	{ "disable-memdev", .c_fn = cmd_disable_memdev },

+ +	{ "enable-memdev", .c_fn = cmd_enable_memdev },

+  };

+  

+  int main(int argc, const char **argv)

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 14c7db8..2fdaf71 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -500,6 +500,64 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev

+  	return memdev->firmware_version;

+  }

+  

+ +CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	struct cxl_port *port, *_p, *bus_port;

+ +	struct cxl_bus *bus;

+ +

+ +	if (!cxl_memdev_is_enabled(memdev))

+ +		return 0;

+ +

+ +	bus = cxl_memdev_get_bus(memdev);

+ +	if (!bus) {

+ +		err(ctx, "%s: failed to invalidate\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	util_unbind(memdev->dev_path, ctx);

+ +

+ +	if (cxl_memdev_is_enabled(memdev)) {

+ +		err(ctx, "%s: failed to disable\n", devname);

+ +		return -EBUSY;

+ +	}

+ +

+ +	/*

+ +	 * The state of all ports is now indeterminate, delete them all

+ +	 * and start over.

+ +	 */

+ +	bus_port = cxl_bus_get_port(bus);

+ +	list_for_each_safe(&bus_port->child_ports, port, _p, list)

+ +		free_port(port, &bus_port->child_ports);

+ +	bus_port->ports_init = 0;

+ +	memdev->endpoint = NULL;

+ +

+ +	dbg(ctx, "%s: disabled\n", devname);

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_memdev_enable(struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +

+ +	if (cxl_memdev_is_enabled(memdev))

+ +		return 0;

+ +

+ +	util_bind(devname, memdev->module, "cxl", ctx);

+ +

+ +	if (!cxl_memdev_is_enabled(memdev)) {

+ +		err(ctx, "%s: failed to enable\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	dbg(ctx, "%s: enabled\n", devname);

+ +

+ +	return 0;

+ +}

+ +

+  static struct cxl_endpoint *cxl_port_find_endpoint(struct cxl_port *parent_port,

+  						   struct cxl_memdev *memdev)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index b13a2d6..f235e99 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -115,4 +115,6 @@ global:

+  	cxl_memdev_get_endpoint;

+  	cxl_memdev_is_enabled;

+  	cxl_memdev_get_bus;

+ +	cxl_memdev_disable_invalidate;

+ +	cxl_memdev_enable;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index be656ed..53f68dd 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -48,6 +48,8 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);

+  unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);

+  const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);

+  size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);

+ +int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev);

+ +int cxl_memdev_enable(struct cxl_memdev *memdev);

+  struct cxl_endpoint;

+  struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);

+  int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index ef5343a..90b33e1 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -25,13 +25,14 @@ static struct parameters {

+  	unsigned offset;

+  	bool verbose;

+  	bool serial;

+ +	bool force;

+  } param;

+  

+  static struct log_ctx ml;

+  

+  #define BASE_OPTIONS() \

+  OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug"), \

+ -OPT_BOOLEAN('S', "serial", &param.serial, "user serials numbers to id memdevs")

+ +OPT_BOOLEAN('S', "serial", &param.serial, "use serial numbers to id memdevs")

+  

+  #define READ_OPTIONS() \

+  OPT_STRING('o', "output", &param.outfile, "output-file", \

+ @@ -46,6 +47,10 @@ OPT_UINTEGER('s', "size", &param.len, "number of label bytes to operate"), \

+  OPT_UINTEGER('O', "offset", &param.offset, \

+  	"offset into the label area to start operation")

+  

+ +#define DISABLE_OPTIONS()                                              \

+ +OPT_BOOLEAN('f', "force", &param.force,                                \

+ +	    "DANGEROUS: override active memdev safety checks")

+ +

+  static const struct option read_options[] = {

+  	BASE_OPTIONS(),

+  	LABEL_OPTIONS(),

+ @@ -66,6 +71,37 @@ static const struct option zero_options[] = {

+  	OPT_END(),

+  };

+  

+ +static const struct option disable_options[] = {

+ +	BASE_OPTIONS(),

+ +	DISABLE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static const struct option enable_options[] = {

+ +	BASE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static int action_disable(struct cxl_memdev *memdev, struct action_context *actx)

+ +{

+ +	if (!cxl_memdev_is_enabled(memdev))

+ +		return 0;

+ +

+ +	if (!param.force) {

+ +		/* TODO: actually detect rather than assume active */

+ +		log_err(&ml, "%s is part of an active region\n",

+ +			cxl_memdev_get_devname(memdev));

+ +		return -EBUSY;

+ +	}

+ +

+ +	return cxl_memdev_disable_invalidate(memdev);

+ +}

+ +

+ +static int action_enable(struct cxl_memdev *memdev, struct action_context *actx)

+ +{

+ +	return cxl_memdev_enable(memdev);

+ +}

+ +

+  static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)

+  {

+  	size_t size;

+ @@ -340,3 +376,25 @@ int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx)

+  		 count > 1 ? "s" : "");

+  	return count >= 0 ? 0 : EXIT_FAILURE;

+  }

+ +

+ +int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(

+ +		argc, argv, ctx, action_disable, disable_options,

+ +		"cxl disable-memdev <mem0> [<mem1>..<memN>] [<options>]");

+ +

+ +	log_info(&ml, "disabled %d mem%s\n", count >= 0 ? count : 0,

+ +		 count > 1 ? "s" : "");

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ +

+ +int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(

+ +		argc, argv, ctx, action_enable, enable_options,

+ +		"cxl enable-memdev <mem0> [<mem1>..<memN>] [<options>]");

+ +

+ +	log_info(&ml, "enabled %d mem%s\n", count >= 0 ? count : 0,

+ +		 count > 1 ? "s" : "");

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ -- 

+ 2.27.0

+ 

The added file is too large to be shown here, see it at: SOURCES/0116-cxl-list-Add-decoder-support.patch
@@ -0,0 +1,537 @@ 

+ From 1279d1989ef77085d214a193c1458b624039c612 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:34 -0800

+ Subject: [PATCH 117/217] cxl/list: Extend decoder objects with target

+  information

+ 

+ A target combines information about a dport along with its position in the

+ intereleave order. With targets enumerated decoders can also be filtered be

+ memory devices by seeing which decoders have a dport in the memory-device's

+ ancestry.

+ 

+ $ cxl list -D -d 3.1 -T -u

+ {

+   "decoder":"decoder3.1",

+   "resource":"0x8030000000",

+   "size":"512.00 MiB (536.87 MB)",

+   "volatile_capable":true,

+   "nr_targets":2,

+   "targets":[

+     {

+       "target":"cxl_host_bridge.1",

+       "position":1,

+       "id":"0x1"

+     },

+     {

+       "target":"cxl_host_bridge.0",

+       "position":0,

+       "id":"0"

+     }

+   ]

+ }

+ 

+ Link: https://lore.kernel.org/r/164298567435.3021641.3771899644901785666.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format                    |   1 +

+  Documentation/cxl/cxl-list.txt   |   8 ++-

+  Documentation/cxl/lib/libcxl.txt |  58 ++++++++++++++++

+  cxl/filter.c                     |  25 +++++++

+  cxl/filter.h                     |   1 +

+  cxl/json.c                       |  46 +++++++++++++

+  cxl/lib/libcxl.c                 | 115 +++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |  10 +++

+  cxl/libcxl.h                     |  19 +++++

+  cxl/list.c                       |   2 +

+  10 files changed, 283 insertions(+), 2 deletions(-)

+ 

+ diff --git a/.clang-format b/.clang-format

+ index 16e28ac..47fb657 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -81,6 +81,7 @@ ForEachMacros:

+    - 'cxl_bus_foreach'

+    - 'cxl_port_foreach'

+    - 'cxl_decoder_foreach'

+ +  - 'cxl_target_foreach'

+    - 'cxl_endpoint_foreach'

+    - 'daxctl_dev_foreach'

+    - 'daxctl_mapping_foreach'

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 84872b9..20ff2cb 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -44,8 +44,8 @@ would only list objects that are beneath port10 AND map mem0, mem1, OR

+  mem2.

+  

+  Given that many topology queries seek to answer questions relative to a

+ -given memdev, buses, ports, and endpoints can be filtered by one or more

+ -memdevs. For example:

+ +given memdev, buses, ports, endpoints, and decoders can be filtered by

+ +one or more memdevs. For example:

+  ----

+  # cxl list -P -p switch,endpoint -m mem0

+  [

+ @@ -270,6 +270,10 @@ OPTIONS

+  	"decoder<port_id>.<instance_id>". The possible decoder type names are

+  	"root", "switch", or "endpoint", similar to the port filter syntax.

+  

+ +-T::

+ +--targets::

+ +	Extend decoder listings with downstream port target information.

+ +

+  --debug::

+  	If the cxl tool was built with debug enabled, turn on debug

+  	messages.

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 73af3d0..bd92fef 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -300,6 +300,7 @@ device-local-physical-address).

+  struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);

+  struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);

+  struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder);

+ +struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target);

+  

+  #define cxl_decoder_foreach(port, decoder)                                  \

+         for (decoder = cxl_decoder_get_first(port); decoder != NULL;         \

+ @@ -314,6 +315,7 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+  int cxl_decoder_get_id(struct cxl_decoder *decoder);

+ +int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);

+  

+  enum cxl_decoder_target_type {

+         CXL_DECODER_TTYPE_UNKNOWN,

+ @@ -352,6 +354,62 @@ Platform firmware may setup the CXL decode hierarchy before the OS

+  boots, and may additionally require that the OS not change the decode

+  settings. This property is indicated by the cxl_decoder_is_locked() API.

+  

+ +==== TARGETS

+ +A root or switch level decoder takes an SPA (system-physical-address) as

+ +input and routes it to a downstream port. Which downstream port depends

+ +on the downstream port's position in the interleave. A 'struct

+ +cxl_target' object represents the properties of a given downstream port

+ +relative to its interleave configuration.

+ +

+ +===== TARGET: Enumeration

+ +----

+ +struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,

+ +                                                   struct cxl_memdev *memdev);

+ +struct cxl_target *

+ +cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position);

+ +struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder);

+ +struct cxl_target *cxl_target_get_next(struct cxl_target *target);

+ +

+ +#define cxl_target_foreach(decoder, target)                                   \

+ +       for (target = cxl_target_get_first(decoder); target != NULL;           \

+ +            target = cxl_target_get_next(target))

+ +----

+ +Target objects can only be enumerated if the decoder has been

+ +configured, for switch decoders. For root decoders they are always

+ +available since the root decoder target mapping is static. The

+ +cxl_decoder_get_target_by_memdev() helper walks the topology to validate

+ +if the given memory device is capable of receiving cycles from this

+ +upstream decoder. It does not validate if the memory device is currently

+ +configured to participate in that decode.

+ +

+ +===== TARGET: Attributes

+ +----

+ +int cxl_target_get_position(struct cxl_target *target);

+ +unsigned long cxl_target_get_id(struct cxl_target *target);

+ +const char *cxl_target_get_devname(struct cxl_target *target);

+ +bool cxl_target_maps_memdev(struct cxl_target *target,

+ +                           struct cxl_memdev *memdev);

+ +----

+ +The position of a decoder along with the interleave granularity dictate

+ +which address in the decoder's resource range map to which port.

+ +

+ +The target id is an identifier that the CXL port uses to reference this

+ +downstream port. For CXL / PCIe downstream switch ports the id is

+ +defined by the PCIe Link Capability Port Number field. For root decoders

+ +the id is specified by platform firmware specific mechanism. For

+ +ACPI.CXL defined root ports the id comes from the CEDT.CHBS / ACPI0016

+ +_UID.

+ +

+ +The device name of a target is the name of the host device for the

+ +downstream port. For CXL / PCIe downstream ports the devname is

+ +downstream switch port PCI device. For CXL root ports the devname is a

+ +platform firmware object for the host bridge like a ACPI0016 device

+ +instance.

+ +

+ +The cxl_target_maps_memdev() helper is the companion of

+ +cxl_decoder_get_target_by_memdev() to determine which downstream ports /

+ +targets are capable of mapping which memdevs.

+ +

+  include::../../copyright.txt[]

+  

+  SEE ALSO

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index dc052f6..05ede91 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -421,6 +421,26 @@ static struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder,

+  	return NULL;

+  }

+  

+ +static struct cxl_decoder *

+ +util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,

+ +				  const char *ident, const char *serial)

+ +{

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (!ident && !serial)

+ +		return decoder;

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		if (!util_cxl_memdev_filter(memdev, ident, serial))

+ +			continue;

+ +		if (cxl_decoder_get_target_by_memdev(decoder, memdev))

+ +			return decoder;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+  static unsigned long params_to_flags(struct cxl_filter_params *param)

+  {

+  	unsigned long flags = 0;

+ @@ -431,6 +451,8 @@ static unsigned long params_to_flags(struct cxl_filter_params *param)

+  		flags |= UTIL_JSON_HUMAN;

+  	if (param->health)

+  		flags |= UTIL_JSON_HEALTH;

+ +	if (param->targets)

+ +		flags |= UTIL_JSON_TARGETS;

+  	return flags;

+  }

+  

+ @@ -521,6 +543,9 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,

+  		if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter,

+  						     pf_mode(p)))

+  			continue;

+ +		if (!util_cxl_decoder_filter_by_memdev(

+ +			    decoder, p->memdev_filter, p->serial_filter))

+ +			continue;

+  		if (!p->idle && cxl_decoder_get_size(decoder) == 0)

+  			continue;

+  		jdecoder = util_cxl_decoder_to_json(decoder, flags);

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 5d7bf45..6fd469f 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -16,6 +16,7 @@ struct cxl_filter_params {

+  	bool single;

+  	bool endpoints;

+  	bool decoders;

+ +	bool targets;

+  	bool memdevs;

+  	bool ports;

+  	bool buses;

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 548bc52..3a37909 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -268,6 +268,8 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	const char *devname = cxl_decoder_get_devname(decoder);

+  	struct cxl_port *port = cxl_decoder_get_port(decoder);

+  	struct json_object *jdecoder, *jobj;

+ +	struct json_object *jtargets;

+ +	struct cxl_target *target;

+  	u64 val;

+  

+  	jdecoder = json_object_new_object();

+ @@ -321,7 +323,51 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  					       jobj);

+  	}

+  

+ +	/* Endpoints don't have targets, they *are* targets */

+ +	if (cxl_port_is_endpoint(port))

+ +		return jdecoder;

+ +

+ +	val = cxl_decoder_get_nr_targets(decoder);

+ +	jobj = json_object_new_int(val);

+ +	if (jobj)

+ +		json_object_object_add(jdecoder, "nr_targets", jobj);

+ +

+ +	if (!(flags & UTIL_JSON_TARGETS) ||

+ +	    !cxl_decoder_get_nr_targets(decoder))

+ +		return jdecoder;

+ +

+ +	jtargets = json_object_new_array();

+ +	if (!jtargets)

+ +		return jdecoder;

+ +

+ +	cxl_target_foreach(decoder, target) {

+ +		struct json_object *jtarget = json_object_new_object();

+ +

+ +		if (!jtarget)

+ +			continue;

+ +

+ +		devname = cxl_target_get_devname(target);

+ +		jobj = json_object_new_string(devname);

+ +		if (jobj)

+ +			json_object_object_add(jtarget, "target", jobj);

+ +

+ +		val = cxl_target_get_position(target);

+ +		jobj = json_object_new_int(val);

+ +		if (jobj)

+ +			json_object_object_add(jtarget, "position", jobj);

+ +

+ +		val = cxl_target_get_id(target);

+ +		jobj = util_json_object_hex(val, flags);

+ +		if (jobj)

+ +			json_object_object_add(jtarget, "id", jobj);

+ +

+ +		json_object_array_add(jtargets, jtarget);

+ +	}

+ +

+ +	json_object_object_add(jdecoder, "targets", jtargets);

+ +

+  	return jdecoder;

+ +

+  }

+  

+  static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 5e30923..877f42c 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -67,10 +67,22 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+  	free(memdev);

+  }

+  

+ +static void free_target(struct cxl_target *target, struct list_head *head)

+ +{

+ +	if (head)

+ +		list_del_from(head, &target->list);

+ +	free(target->dev_path);

+ +	free(target);

+ +}

+ +

+  static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)

+  {

+ +	struct cxl_target *target, *_t;

+ +

+  	if (head)

+  		list_del_from(head, &decoder->list);

+ +	list_for_each_safe(&decoder->targets, target, _t, list)

+ +		free_target(target, &decoder->targets);

+  	free(decoder->dev_buf);

+  	free(decoder->dev_path);

+  	free(decoder);

+ @@ -856,6 +868,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	struct cxl_port *port = parent;

+  	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+  	char buf[SYSFS_ATTR_SIZE];

+ +	char *target_id, *save;

+  	size_t i;

+  

+  	dbg(ctx, "%s: base: \'%s\'\n", devname, cxldecoder_base);

+ @@ -870,6 +883,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	decoder->id = id;

+  	decoder->ctx = ctx;

+  	decoder->port = port;

+ +	list_head_init(&decoder->targets);

+  

+  	decoder->dev_path = strdup(cxldecoder_base);

+  	if (!decoder->dev_path)

+ @@ -935,6 +949,36 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	}

+  	}

+  

+ +	sprintf(path, "%s/target_list", cxldecoder_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		buf[0] = '\0';

+ +

+ +	for (i = 0, target_id = strtok_r(buf, ",", &save); target_id;

+ +	     target_id = strtok_r(NULL, ",", &save), i++) {

+ +		int did = strtoul(target_id, NULL, 0);

+ +		struct cxl_target *target = calloc(1, sizeof(*target));

+ +

+ +		if (!target)

+ +			break;

+ +

+ +		target->id = did;

+ +		target->position = i;

+ +		target->decoder = decoder;

+ +		sprintf(port->dev_buf, "%s/dport%d", port->dev_path, did);

+ +		target->dev_path = realpath(port->dev_buf, NULL);

+ +		if (!target->dev_path) {

+ +			free(target);

+ +			break;

+ +		}

+ +		dbg(ctx, "%s: target%ld %s\n", devname, i, target->dev_path);

+ +		list_add(&decoder->targets, &target->list);

+ +	}

+ +

+ +	if (target_id)

+ +		err(ctx, "%s: failed to parse target%ld\n",

+ +		    devpath_to_devname(cxldecoder_base), i);

+ +	decoder->nr_targets = i;

+ +

+  	cxl_decoder_foreach(port, decoder_dup)

+  		if (decoder_dup->id == decoder->id) {

+  			free_decoder(decoder, NULL);

+ @@ -1044,11 +1088,82 @@ CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder)

+  	return decoder->locked;

+  }

+  

+ +CXL_EXPORT int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder)

+ +{

+ +	return decoder->nr_targets;

+ +}

+ +

+  CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder)

+  {

+  	return devpath_to_devname(decoder->dev_path);

+  }

+  

+ +CXL_EXPORT struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder)

+ +{

+ +	return list_top(&decoder->targets, struct cxl_target, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target)

+ +{

+ +	return target->decoder;

+ +}

+ +

+ +CXL_EXPORT struct cxl_target *cxl_target_get_next(struct cxl_target *target)

+ +{

+ +	struct cxl_decoder *decoder = cxl_target_get_decoder(target);

+ +

+ +	return list_next(&decoder->targets, target, list);

+ +}

+ +

+ +CXL_EXPORT const char *cxl_target_get_devname(struct cxl_target *target)

+ +{

+ +	return devpath_to_devname(target->dev_path);

+ +}

+ +

+ +CXL_EXPORT unsigned long cxl_target_get_id(struct cxl_target *target)

+ +{

+ +	return target->id;

+ +}

+ +

+ +CXL_EXPORT int cxl_target_get_position(struct cxl_target *target)

+ +{

+ +	return target->position;

+ +}

+ +

+ +CXL_EXPORT bool cxl_target_maps_memdev(struct cxl_target *target,

+ +					struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +

+ +	dbg(ctx, "memdev: %s target: %s\n", memdev->host_path,

+ +	    target->dev_path);

+ +

+ +	return !!strstr(memdev->host_path, target->dev_path);

+ +}

+ +

+ +CXL_EXPORT struct cxl_target *

+ +cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,

+ +				 struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_target *target;

+ +

+ +	cxl_target_foreach(decoder, target)

+ +		if (cxl_target_maps_memdev(target, memdev))

+ +			return target;

+ +	return NULL;

+ +}

+ +

+ +CXL_EXPORT struct cxl_target *

+ +cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position)

+ +{

+ +	struct cxl_target *target;

+ +

+ +	cxl_target_foreach(decoder, target)

+ +		if (target->position == position)

+ +			return target;

+ +	return NULL;

+ +}

+ +

+  static void *add_cxl_port(void *parent, int id, const char *cxlport_base)

+  {

+  	const char *devname = devpath_to_devname(cxlport_base);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 22babb7..cb33180 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -125,10 +125,20 @@ global:

+  	cxl_decoder_get_resource;

+  	cxl_decoder_get_size;

+  	cxl_decoder_get_devname;

+ +	cxl_decoder_get_target_by_memdev;

+ +	cxl_decoder_get_target_by_position;

+ +	cxl_decoder_get_nr_targets;

+  	cxl_decoder_get_target_type;

+  	cxl_decoder_is_pmem_capable;

+  	cxl_decoder_is_volatile_capable;

+  	cxl_decoder_is_mem_capable;

+  	cxl_decoder_is_accelmem_capable;

+  	cxl_decoder_is_locked;

+ +	cxl_target_get_first;

+ +	cxl_target_get_next;

+ +	cxl_target_get_decoder;

+ +	cxl_target_get_position;

+ +	cxl_target_get_id;

+ +	cxl_target_get_devname;

+ +	cxl_target_maps_memdev;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 439ed93..abda0e5 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -104,6 +104,11 @@ struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+ +struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,

+ +						    struct cxl_memdev *memdev);

+ +struct cxl_target *

+ +cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position);

+ +int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);

+  struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder);

+  int cxl_decoder_get_id(struct cxl_decoder *decoder);

+  struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder);

+ @@ -126,6 +131,20 @@ bool cxl_decoder_is_locked(struct cxl_decoder *decoder);

+  	for (decoder = cxl_decoder_get_first(port); decoder != NULL;           \

+  	     decoder = cxl_decoder_get_next(decoder))

+  

+ +struct cxl_target;

+ +struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder);

+ +struct cxl_target *cxl_target_get_next(struct cxl_target *target);

+ +struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target);

+ +int cxl_target_get_position(struct cxl_target *target);

+ +unsigned long cxl_target_get_id(struct cxl_target *target);

+ +const char *cxl_target_get_devname(struct cxl_target *target);

+ +bool cxl_target_maps_memdev(struct cxl_target *target,

+ +			    struct cxl_memdev *memdev);

+ +

+ +#define cxl_target_foreach(decoder, target)                                    \

+ +	for (target = cxl_target_get_first(decoder); target != NULL;           \

+ +	     target = cxl_target_get_next(target))

+ +

+  struct cxl_endpoint;

+  struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent);

+  struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);

+ diff --git a/cxl/list.c b/cxl/list.c

+ index d70192a..27c963a 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -41,6 +41,8 @@ static const struct option options[] = {

+  		   "filter by CXL decoder device name(s) / class"),

+  	OPT_BOOLEAN('D', "decoders", &param.decoders,

+  		    "include CXL decoder info"),

+ +	OPT_BOOLEAN('T', "targets", &param.targets,

+ +		    "include CXL target data with decoders"),

+  	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+  	OPT_BOOLEAN('u', "human", &param.human,

+  		    "use human friendly number formats "),

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,156 @@ 

+ From 5fb1b8a1630115f3aa3cd6bb7bc9ba5122867f66 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:39 -0800

+ Subject: [PATCH 118/217] cxl/list: Use 'physical_node' for root port

+  attachment detection

+ 

+ Platform firmware objects like ACPI0016 link from /sys/bus/acpi to

+ /sys/bus/pci via a 'physical_node' attribute. Consider that link when

+ attempting to link memdevs to root ports.

+ 

+ Emit it in the the target listing as the 'alias' for the listed target

+ device.

+ 

+ Link: https://lore.kernel.org/r/164298567943.3021641.12696733268157328279.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  6 ++++++

+  cxl/json.c                       |  8 ++++++++

+  cxl/lib/libcxl.c                 | 16 +++++++++++++++-

+  cxl/lib/libcxl.sym               |  1 +

+  cxl/lib/private.h                |  1 +

+  cxl/libcxl.h                     |  1 +

+  6 files changed, 32 insertions(+), 1 deletion(-)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index bd92fef..a68a58b 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -389,6 +389,7 @@ unsigned long cxl_target_get_id(struct cxl_target *target);

+  const char *cxl_target_get_devname(struct cxl_target *target);

+  bool cxl_target_maps_memdev(struct cxl_target *target,

+                             struct cxl_memdev *memdev);

+ +const char *cxl_target_get_physical_node(struct cxl_target *target);

+  ----

+  The position of a decoder along with the interleave granularity dictate

+  which address in the decoder's resource range map to which port.

+ @@ -410,6 +411,11 @@ The cxl_target_maps_memdev() helper is the companion of

+  cxl_decoder_get_target_by_memdev() to determine which downstream ports /

+  targets are capable of mapping which memdevs.

+  

+ +Some platform firmware implementations define an alias / companion

+ +device to represent the root of a PCI device hierarchy. The

+ +cxl_target_get_physical_node() helper returns the device name of that

+ +companion object in the PCI hierarchy.

+ +

+  include::../../copyright.txt[]

+  

+  SEE ALSO

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 3a37909..d81aed8 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -342,6 +342,7 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  

+  	cxl_target_foreach(decoder, target) {

+  		struct json_object *jtarget = json_object_new_object();

+ +		const char *phys_node;

+  

+  		if (!jtarget)

+  			continue;

+ @@ -351,6 +352,13 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  		if (jobj)

+  			json_object_object_add(jtarget, "target", jobj);

+  

+ +		phys_node = cxl_target_get_physical_node(target);

+ +		if (phys_node) {

+ +			jobj = json_object_new_string(phys_node);

+ +			if (jobj)

+ +				json_object_object_add(jtarget, "alias", jobj);

+ +		}

+ +

+  		val = cxl_target_get_position(target);

+  		jobj = json_object_new_int(val);

+  		if (jobj)

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 877f42c..7bf7949 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -72,6 +72,7 @@ static void free_target(struct cxl_target *target, struct list_head *head)

+  	if (head)

+  		list_del_from(head, &target->list);

+  	free(target->dev_path);

+ +	free(target->phys_path);

+  	free(target);

+  }

+  

+ @@ -970,7 +971,11 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  			free(target);

+  			break;

+  		}

+ -		dbg(ctx, "%s: target%ld %s\n", devname, i, target->dev_path);

+ +		sprintf(port->dev_buf, "%s/dport%d/physical_node", port->dev_path, did);

+ +		target->phys_path = realpath(port->dev_buf, NULL);

+ +		dbg(ctx, "%s: target%ld %s phys_path: %s\n", devname, i,

+ +		    target->dev_path,

+ +		    target->phys_path ? target->phys_path : "none");

+  		list_add(&decoder->targets, &target->list);

+  	}

+  

+ @@ -1138,9 +1143,18 @@ CXL_EXPORT bool cxl_target_maps_memdev(struct cxl_target *target,

+  	dbg(ctx, "memdev: %s target: %s\n", memdev->host_path,

+  	    target->dev_path);

+  

+ +	if (target->phys_path)

+ +		return !!strstr(memdev->host_path, target->phys_path);

+  	return !!strstr(memdev->host_path, target->dev_path);

+  }

+  

+ +CXL_EXPORT const char *cxl_target_get_physical_node(struct cxl_target *target)

+ +{

+ +	if (!target->phys_path)

+ +		return NULL;

+ +	return devpath_to_devname(target->phys_path);

+ +}

+ +

+  CXL_EXPORT struct cxl_target *

+  cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,

+  				 struct cxl_memdev *memdev)

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index cb33180..ce01298 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -141,4 +141,5 @@ global:

+  	cxl_target_get_id;

+  	cxl_target_get_devname;

+  	cxl_target_maps_memdev;

+ +	cxl_target_get_physical_node;

+  } LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 1743a24..7e7742d 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -77,6 +77,7 @@ struct cxl_target {

+  	struct list_node list;

+  	struct cxl_decoder *decoder;

+  	char *dev_path;

+ +	char *phys_path;

+  	int id, position;

+  };

+  

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index abda0e5..0e484cc 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -140,6 +140,7 @@ unsigned long cxl_target_get_id(struct cxl_target *target);

+  const char *cxl_target_get_devname(struct cxl_target *target);

+  bool cxl_target_maps_memdev(struct cxl_target *target,

+  			    struct cxl_memdev *memdev);

+ +const char *cxl_target_get_physical_node(struct cxl_target *target);

+  

+  #define cxl_target_foreach(decoder, target)                                    \

+  	for (target = cxl_target_get_first(decoder); target != NULL;           \

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,457 @@ 

+ From d87cee2dd4756f7e067bdadc78a0632dd666cc64 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:44 -0800

+ Subject: [PATCH 119/217] cxl/list: Reuse the --target option for ports

+ 

+ It is useful to be able to dump the dport-id to host-device-name. Rather

+ than introduce a new option, just interpret --target as "list dports" for

+ port objects.

+ 

+ $ cxl list -BTu -b ACPI.CXL

+ {

+   "bus":"root0",

+   "provider":"ACPI.CXL",

+   "nr_dports":1,

+   "dports":[

+     {

+       "dport":"ACPI0016:00",

+       "alias":"pci0000:34",

+       "id":"0"

+     }

+   ]

+ }

+ 

+ Link: https://lore.kernel.org/r/164298568481.3021641.4632086646702812643.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format                    |   1 +

+  Documentation/cxl/cxl-list.txt   |  18 ++++-

+  Documentation/cxl/lib/libcxl.txt |  27 ++++++++

+  cxl/json.c                       |  56 +++++++++++++++-

+  cxl/lib/libcxl.c                 | 109 ++++++++++++++++++++++++++++++-

+  cxl/lib/libcxl.sym               |   7 ++

+  cxl/lib/private.h                |  13 ++++

+  cxl/libcxl.h                     |  12 ++++

+  cxl/list.c                       |   2 +-

+  9 files changed, 240 insertions(+), 5 deletions(-)

+ 

+ diff --git a/.clang-format b/.clang-format

+ index 47fb657..c753487 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -82,6 +82,7 @@ ForEachMacros:

+    - 'cxl_port_foreach'

+    - 'cxl_decoder_foreach'

+    - 'cxl_target_foreach'

+ +  - 'cxl_dport_foreach'

+    - 'cxl_endpoint_foreach'

+    - 'daxctl_dev_foreach'

+    - 'daxctl_mapping_foreach'

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 20ff2cb..e1299d9 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -272,7 +272,23 @@ OPTIONS

+  

+  -T::

+  --targets::

+ -	Extend decoder listings with downstream port target information.

+ +	Extend decoder listings with downstream port target information, and /

+ +	or port and bus listings with the downstream port information.

+ +----

+ +# cxl list -BTu -b ACPI.CXL

+ +{

+ +  "bus":"root0",

+ +  "provider":"ACPI.CXL",

+ +  "nr_dports":1,

+ +  "dports":[

+ +    {

+ +      "dport":"ACPI0016:00",

+ +      "alias":"pci0000:34",

+ +      "id":"0"

+ +    }

+ +  ]

+ +}

+ +----

+  

+  --debug::

+  	If the cxl tool was built with debug enabled, turn on debug

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index a68a58b..2e8570d 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -245,6 +245,7 @@ bool cxl_port_is_root(struct cxl_port *port);

+  bool cxl_port_is_switch(struct cxl_port *port);

+  bool cxl_port_is_endpoint(struct cxl_port *port);

+  bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);

+ +int cxl_port_get_nr_dports(struct cxl_port *port);

+  ----

+  The port type is communicated via cxl_port_is_<type>(). An 'enabled' port

+  is one that has succeeded in discovering the CXL component registers in

+ @@ -256,6 +257,32 @@ of intervening switch ports, and a terminal endpoint port.

+  cxl_port_hosts_memdev() returns true if the port's host appears in the

+  memdev host's device topology ancestry.

+  

+ +==== DPORTS

+ +A CXL dport object represents a CXL / PCIe Switch Downstream Port, or a

+ +CXL / PCIe host bridge.

+ +

+ +===== DPORT: Enumeration

+ +----

+ +struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);

+ +struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);

+ +

+ +#define cxl_dport_foreach(port, dport)                                     \

+ +       for (dport = cxl_dport_get_first(port); dport != NULL;              \

+ +            dport = cxl_dport_get_next(dport))

+ +

+ +----

+ +

+ +===== DPORT: Attributes

+ +----

+ +const char *cxl_dport_get_devname(struct cxl_dport *dport);

+ +const char *cxl_dport_get_physical_node(struct cxl_dport *dport);

+ +int cxl_dport_get_id(struct cxl_dport *dport);

+ +----

+ +The id of a dport is the hardware idenfifier used by an upstream port to

+ +reference a downstream port. The physical node of a dport is only

+ +available for platform firmware defined downstream ports and alias the

+ +companion object, like a PCI host bridge, in the PCI device hierarchy.

+ +

+  ENDPOINTS

+  ---------

+  CXL endpoint objects encapsulate the set of host-managed device-memory

+ diff --git a/cxl/json.c b/cxl/json.c

+ index d81aed8..4fb5eec 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -241,6 +241,58 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  	return jdev;

+  }

+  

+ +static struct json_object *util_cxl_dports_to_json(struct json_object *jport,

+ +						   struct cxl_port *port,

+ +						   unsigned long flags)

+ +{

+ +	struct json_object *jobj, *jdports;

+ +	struct cxl_dport *dport;

+ +	int val;

+ +

+ +	val = cxl_port_get_nr_dports(port);

+ +	if (!val || !(flags & UTIL_JSON_TARGETS))

+ +		return jport;

+ +

+ +	jobj = json_object_new_int(val);

+ +	if (jobj)

+ +		json_object_object_add(jport, "nr_dports", jobj);

+ +

+ +	jdports = json_object_new_array();

+ +	if (!jdports)

+ +		return jport;

+ +

+ +	cxl_dport_foreach(port, dport) {

+ +		struct json_object *jdport;

+ +		const char *phys_node;

+ +

+ +		jdport = json_object_new_object();

+ +		if (!jdport)

+ +			continue;

+ +

+ +		jobj = json_object_new_string(cxl_dport_get_devname(dport));

+ +		if (jobj)

+ +			json_object_object_add(jdport, "dport", jobj);

+ +

+ +		phys_node = cxl_dport_get_physical_node(dport);

+ +		if (phys_node) {

+ +			jobj = json_object_new_string(phys_node);

+ +			if (jobj)

+ +				json_object_object_add(jdport, "alias", jobj);

+ +		}

+ +

+ +		val = cxl_dport_get_id(dport);

+ +		jobj = util_json_object_hex(val, flags);

+ +		if (jobj)

+ +			json_object_object_add(jdport, "id", jobj);

+ +

+ +		json_object_array_add(jdports, jdport);

+ +	}

+ +

+ +	json_object_object_add(jport, "dports", jdports);

+ +

+ +	return jport;

+ +}

+ +

+  struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+  					 unsigned long flags)

+  {

+ @@ -259,7 +311,7 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+  	if (jobj)

+  		json_object_object_add(jbus, "provider", jobj);

+  

+ -	return jbus;

+ +	return util_cxl_dports_to_json(jbus, cxl_bus_get_port(bus), flags);

+  }

+  

+  struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+ @@ -403,7 +455,7 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,

+  			json_object_object_add(jport, "state", jobj);

+  	}

+  

+ -	return jport;

+ +	return util_cxl_dports_to_json(jport, port, flags);

+  }

+  

+  struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 7bf7949..d7a3f10 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -89,13 +89,24 @@ static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)

+  	free(decoder);

+  }

+  

+ +static void free_dport(struct cxl_dport *dport, struct list_head *head)

+ +{

+ +	if (head)

+ +		list_del_from(head, &dport->list);

+ +	free(dport->dev_buf);

+ +	free(dport->dev_path);

+ +	free(dport->phys_path);

+ +	free(dport);

+ +}

+ +

+  static void free_port(struct cxl_port *port, struct list_head *head);

+  static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head);

+  static void __free_port(struct cxl_port *port, struct list_head *head)

+  {

+ -	struct cxl_port *child, *_c;

+  	struct cxl_endpoint *endpoint, *_e;

+  	struct cxl_decoder *decoder, *_d;

+ +	struct cxl_dport *dport, *_dp;

+ +	struct cxl_port *child, *_c;

+  

+  	if (head)

+  		list_del_from(head, &port->list);

+ @@ -105,6 +116,8 @@ static void __free_port(struct cxl_port *port, struct list_head *head)

+  		free_endpoint(endpoint, &port->endpoints);

+  	list_for_each_safe(&port->decoders, decoder, _d, list)

+  		free_decoder(decoder, &port->decoders);

+ +	list_for_each_safe(&port->dports, dport, _dp, list)

+ +		free_dport(dport , &port->dports);

+  	kmod_module_unref(port->module);

+  	free(port->dev_buf);

+  	free(port->dev_path);

+ @@ -701,6 +714,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,

+  	list_head_init(&port->child_ports);

+  	list_head_init(&port->endpoints);

+  	list_head_init(&port->decoders);

+ +	list_head_init(&port->dports);

+  

+  	port->dev_path = strdup(cxlport_base);

+  	if (!port->dev_path)

+ @@ -1332,6 +1346,99 @@ CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)

+  	return container_of(port, struct cxl_bus, port);

+  }

+  

+ +static void *add_cxl_dport(void *parent, int id, const char *cxldport_base)

+ +{

+ +	const char *devname = devpath_to_devname(cxldport_base);

+ +	struct cxl_dport *dport, *dport_dup;

+ +	struct cxl_port *port = parent;

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +

+ +	dbg(ctx, "%s: base: \'%s\'\n", devname, cxldport_base);

+ +

+ +	dport = calloc(1, sizeof(*dport));

+ +	if (!dport)

+ +		return NULL;

+ +

+ +	dport->id = id;

+ +	dport->port = port;

+ +

+ +	dport->dev_path = realpath(cxldport_base, NULL);

+ +	if (!dport->dev_path)

+ +		goto err;

+ +

+ +	dport->dev_buf = calloc(1, strlen(cxldport_base) + 50);

+ +	if (!dport->dev_buf)

+ +		goto err;

+ +	dport->buf_len = strlen(cxldport_base) + 50;

+ +

+ +	sprintf(dport->dev_buf, "%s/physical_node", cxldport_base);

+ +	dport->phys_path = realpath(dport->dev_buf, NULL);

+ +

+ +	cxl_dport_foreach(port, dport_dup)

+ +		if (dport_dup->id == dport->id) {

+ +			free_dport(dport, NULL);

+ +			return dport_dup;

+ +		}

+ +

+ +	port->nr_dports++;

+ +	list_add(&port->dports, &dport->list);

+ +	return dport;

+ +

+ +err:

+ +	free_dport(dport, NULL);

+ +	return NULL;

+ +}

+ +

+ +static void cxl_dports_init(struct cxl_port *port)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +

+ +	if (port->dports_init)

+ +		return;

+ +

+ +	port->dports_init = 1;

+ +

+ +	sysfs_device_parse(ctx, port->dev_path, "dport", port, add_cxl_dport);

+ +}

+ +

+ +CXL_EXPORT int cxl_port_get_nr_dports(struct cxl_port *port)

+ +{

+ +	if (!port->dports_init)

+ +		cxl_dports_init(port);

+ +	return port->nr_dports;

+ +}

+ +

+ +CXL_EXPORT struct cxl_dport *cxl_dport_get_first(struct cxl_port *port)

+ +{

+ +	cxl_dports_init(port);

+ +

+ +	return list_top(&port->dports, struct cxl_dport, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport)

+ +{

+ +	struct cxl_port *port = dport->port;

+ +

+ +	return list_next(&port->dports, dport, list);

+ +}

+ +

+ +CXL_EXPORT const char *cxl_dport_get_devname(struct cxl_dport *dport)

+ +{

+ +	return devpath_to_devname(dport->dev_path);

+ +}

+ +

+ +CXL_EXPORT const char *cxl_dport_get_physical_node(struct cxl_dport *dport)

+ +{

+ +	if (!dport->phys_path)

+ +		return NULL;

+ +	return devpath_to_devname(dport->phys_path);

+ +}

+ +

+ +CXL_EXPORT int cxl_dport_get_id(struct cxl_dport *dport)

+ +{

+ +	return dport->id;

+ +}

+ +

+  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 ce01298..0190b13 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -101,6 +101,8 @@ global:

+  	cxl_port_get_host;

+  	cxl_port_get_bus;

+  	cxl_port_hosts_memdev;

+ +	cxl_port_get_nr_dports;

+ +	cxl_port_get_next_all;

+  	cxl_endpoint_get_first;

+  	cxl_endpoint_get_next;

+  	cxl_endpoint_get_devname;

+ @@ -142,4 +144,9 @@ global:

+  	cxl_target_get_devname;

+  	cxl_target_maps_memdev;

+  	cxl_target_get_physical_node;

+ +	cxl_dport_get_first;

+ +	cxl_dport_get_next;

+ +	cxl_dport_get_devname;

+ +	cxl_dport_get_physical_node;

+ +	cxl_dport_get_id;

+  } LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 7e7742d..f483c30 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -38,6 +38,16 @@ struct cxl_memdev {

+  	struct cxl_endpoint *endpoint;

+  };

+  

+ +struct cxl_dport {

+ +	int id;

+ +	void *dev_buf;

+ +	size_t buf_len;

+ +	char *dev_path;

+ +	char *phys_path;

+ +	struct cxl_port *port;

+ +	struct list_node list;

+ +};

+ +

+  enum cxl_port_type {

+  	CXL_PORT_ROOT,

+  	CXL_PORT_SWITCH,

+ @@ -53,6 +63,8 @@ struct cxl_port {

+  	int ports_init;

+  	int endpoints_init;

+  	int decoders_init;

+ +	int dports_init;

+ +	int nr_dports;

+  	struct cxl_ctx *ctx;

+  	struct cxl_bus *bus;

+  	enum cxl_port_type type;

+ @@ -62,6 +74,7 @@ struct cxl_port {

+  	struct list_head child_ports;

+  	struct list_head endpoints;

+  	struct list_head decoders;

+ +	struct list_head dports;

+  };

+  

+  struct cxl_bus {

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 0e484cc..07f4a31 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -93,11 +93,23 @@ bool cxl_port_is_endpoint(struct cxl_port *port);

+  struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+  const char *cxl_port_get_host(struct cxl_port *port);

+  bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);

+ +int cxl_port_get_nr_dports(struct cxl_port *port);

+  

+  #define cxl_port_foreach(parent, port)                                         \

+  	for (port = cxl_port_get_first(parent); port != NULL;                  \

+  	     port = cxl_port_get_next(port))

+  

+ +struct cxl_dport;

+ +struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);

+ +struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);

+ +const char *cxl_dport_get_devname(struct cxl_dport *dport);

+ +const char *cxl_dport_get_physical_node(struct cxl_dport *dport);

+ +int cxl_dport_get_id(struct cxl_dport *dport);

+ +

+ +#define cxl_dport_foreach(port, dport)                                         \

+ +	for (dport = cxl_dport_get_first(port); dport != NULL;                 \

+ +	     dport = cxl_dport_get_next(dport))

+ +

+  struct cxl_decoder;

+  struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);

+  struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 27c963a..de96ff9 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -42,7 +42,7 @@ static const struct option options[] = {

+  	OPT_BOOLEAN('D', "decoders", &param.decoders,

+  		    "include CXL decoder info"),

+  	OPT_BOOLEAN('T', "targets", &param.targets,

+ -		    "include CXL target data with decoders"),

+ +		    "include CXL target data with decoders or ports"),

+  	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+  	OPT_BOOLEAN('u', "human", &param.human,

+  		    "use human friendly number formats "),

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,205 @@ 

+ From aa022d33418021da81a51bc9656931c54043b10b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:50 -0800

+ Subject: [PATCH 120/217] cxl/list: Support filtering memdevs by decoders

+ 

+ In order to filter memdevs by decoders all the ports in the hierarchy need

+ to be iterated, so introduce cxl_port_foreach_all() that starts at the bus

+ and does a depth first iteration of all the descendant ports.

+ 

+ Link: https://lore.kernel.org/r/164298569017.3021641.15558596583530530035.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format                    |  1 +

+  Documentation/cxl/cxl-list.txt   | 13 +++++++++

+  Documentation/cxl/lib/libcxl.txt | 11 ++++++++

+  cxl/filter.c                     | 48 ++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.c                 | 13 +++++++++

+  cxl/libcxl.h                     |  6 ++++

+  6 files changed, 92 insertions(+)

+ 

+ diff --git a/.clang-format b/.clang-format

+ index c753487..6aabcb6 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -84,6 +84,7 @@ ForEachMacros:

+    - 'cxl_target_foreach'

+    - 'cxl_dport_foreach'

+    - 'cxl_endpoint_foreach'

+ +  - 'cxl_port_foreach_all'

+    - 'daxctl_dev_foreach'

+    - 'daxctl_mapping_foreach'

+    - 'daxctl_region_foreach'

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index e1299d9..04e831e 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -61,6 +61,19 @@ one or more memdevs. For example:

+    }

+  ]

+  ----

+ +Additionally, when provisioning new interleave configurations it is

+ +useful to know which memdevs can be referenced by a given decoder like a

+ +root decoder:

+ +----

+ +# cxl list -Mu -d decoder0.0

+ +{

+ +  "memdev":"mem0",

+ +  "pmem_size":"256.00 MiB (268.44 MB)",

+ +  "ram_size":0,

+ +  "serial":"0",

+ +  "host":"0000:35:00.0"

+ +}

+ +----

+  

+  The --human option in addition to reformatting some fields to more human

+  friendly strings also unwraps the array to reduce the number of lines of

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 2e8570d..5ad3027 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -219,10 +219,18 @@ struct cxl_port *cxl_port_get_parent(struct cxl_port *port);

+  struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);

+  const char *cxl_port_get_host(struct cxl_port *port);

+  struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder);

+ +struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,

+ +                                       const struct cxl_port *top);

+  

+  #define cxl_port_foreach(parent, port)                                      \

+         for (port = cxl_port_get_first(parent); port != NULL;                \

+              port = cxl_port_get_next(port))

+ +

+ +#define cxl_port_foreach_all(top, port)                                        \

+ +       for (port = cxl_port_get_first(top); port != NULL;                     \

+ +            port = cxl_port_get_next_all(port, top))

+ +

+ +

+  ----

+  A bus object encapsulates a CXL port object. Use cxl_bus_get_port() to

+  use generic port APIs on root objects.

+ @@ -236,6 +244,9 @@ that hierarchy via cxl_port_get_bus().

+  The host of a port is the corresponding device name of the PCIe Root

+  Port, or Switch Upstream Port with CXL capabilities.

+  

+ +The cxl_port_foreach_all() helper does a depth first iteration of all

+ +ports beneath the 'top' port argument.

+ +

+  === PORT: Attributes

+  ----

+  const char *cxl_port_get_devname(struct cxl_port *port);

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 05ede91..c972545 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -441,6 +441,51 @@ util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,

+  	return NULL;

+  }

+  

+ +static bool __memdev_filter_by_decoder(struct cxl_memdev *memdev,

+ +				       struct cxl_port *port, const char *ident)

+ +{

+ +	struct cxl_decoder *decoder;

+ +	struct cxl_endpoint *endpoint;

+ +

+ +	cxl_decoder_foreach(port, decoder) {

+ +		if (!util_cxl_decoder_filter(decoder, ident))

+ +			continue;

+ +		if (cxl_decoder_get_target_by_memdev(decoder, memdev))

+ +			return true;

+ +	}

+ +

+ +	cxl_endpoint_foreach(port, endpoint)

+ +		if (__memdev_filter_by_decoder(

+ +			    memdev, cxl_endpoint_get_port(endpoint), ident))

+ +			return true;

+ +	return false;

+ +}

+ +

+ +static struct cxl_memdev *

+ +util_cxl_memdev_filter_by_decoder(struct cxl_memdev *memdev, const char *ident)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	struct cxl_bus *bus;

+ +

+ +	if (!ident)

+ +		return memdev;

+ +

+ +	cxl_bus_foreach(ctx, bus) {

+ +		struct cxl_port *port, *top;

+ +

+ +		port = cxl_bus_get_port(bus);

+ +		if (__memdev_filter_by_decoder(memdev, port, ident))

+ +			return memdev;

+ +

+ +		top = port;

+ +		cxl_port_foreach_all(top, port)

+ +			if (__memdev_filter_by_decoder(memdev, port, ident))

+ +				return memdev;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+  static unsigned long params_to_flags(struct cxl_filter_params *param)

+  {

+  	unsigned long flags = 0;

+ @@ -599,6 +644,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,

+  			if (!util_cxl_memdev_filter(memdev, p->memdev_filter,

+  						    p->serial_filter))

+  				continue;

+ +			if (!util_cxl_memdev_filter_by_decoder(

+ +				    memdev, p->decoder_filter))

+ +				continue;

+  			if (!p->idle && !cxl_memdev_is_enabled(memdev))

+  				continue;

+  			jobj = util_cxl_memdev_to_json(memdev, flags);

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index d7a3f10..4ebb8b9 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1257,6 +1257,19 @@ CXL_EXPORT struct cxl_port *cxl_port_get_next(struct cxl_port *port)

+  	return list_next(&parent_port->child_ports, port, list);

+  }

+  

+ +CXL_EXPORT struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,

+ +						  const struct cxl_port *top)

+ +{

+ +	struct cxl_port *child, *iter = port;

+ +

+ +	child = cxl_port_get_first(iter);

+ +	if (child)

+ +		return child;

+ +	while (!cxl_port_get_next(iter) && iter->parent && iter->parent != top)

+ +		iter = iter->parent;

+ +	return cxl_port_get_next(iter);

+ +}

+ +

+  CXL_EXPORT const char *cxl_port_get_devname(struct cxl_port *port)

+  {

+  	return devpath_to_devname(port->dev_path);

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 07f4a31..874c381 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -94,11 +94,17 @@ struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+  const char *cxl_port_get_host(struct cxl_port *port);

+  bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);

+  int cxl_port_get_nr_dports(struct cxl_port *port);

+ +struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,

+ +				       const struct cxl_port *top);

+  

+  #define cxl_port_foreach(parent, port)                                         \

+  	for (port = cxl_port_get_first(parent); port != NULL;                  \

+  	     port = cxl_port_get_next(port))

+  

+ +#define cxl_port_foreach_all(top, port)                                        \

+ +	for (port = cxl_port_get_first(top); port != NULL;                     \

+ +	     port = cxl_port_get_next_all(port, top))

+ +

+  struct cxl_dport;

+  struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);

+  struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,200 @@ 

+ From 15cae420681c5e8efad2b4cbaf0470960e2eba52 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:54:55 -0800

+ Subject: [PATCH 121/217] cxl/list: Support filtering memdevs by ports

+ 

+ The ability to filter memdevs by decoders falls short when the decoder does

+ not have its target list programmed. So, introduce a by port filter to show

+ the potential memdevs that can be targeted by the decoder.

+ 

+ Link: https://lore.kernel.org/r/164298569568.3021641.888802471376117408.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt   |  3 +-

+  Documentation/cxl/lib/libcxl.txt |  7 ++++-

+  cxl/filter.c                     | 50 ++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.c                 | 23 +++++++++++++++

+  cxl/lib/libcxl.sym               |  2 ++

+  cxl/libcxl.h                     |  3 ++

+  6 files changed, 86 insertions(+), 2 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 04e831e..90e6d9f 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -63,7 +63,8 @@ one or more memdevs. For example:

+  ----

+  Additionally, when provisioning new interleave configurations it is

+  useful to know which memdevs can be referenced by a given decoder like a

+ -root decoder:

+ +root decoder, or mapped by a given port if the decoders are not

+ +configured.

+  ----

+  # cxl list -Mu -d decoder0.0

+  {

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 5ad3027..a0fcee9 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -276,11 +276,12 @@ CXL / PCIe host bridge.

+  ----

+  struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);

+  struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);

+ +struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port,

+ +                                               struct cxl_memdev *memdev);

+  

+  #define cxl_dport_foreach(port, dport)                                     \

+         for (dport = cxl_dport_get_first(port); dport != NULL;              \

+              dport = cxl_dport_get_next(dport))

+ -

+  ----

+  

+  ===== DPORT: Attributes

+ @@ -288,12 +289,16 @@ struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);

+  const char *cxl_dport_get_devname(struct cxl_dport *dport);

+  const char *cxl_dport_get_physical_node(struct cxl_dport *dport);

+  int cxl_dport_get_id(struct cxl_dport *dport);

+ +bool cxl_dport_maps_memdev(struct cxl_dport *dport, struct cxl_memdev *memdev);

+  ----

+  The id of a dport is the hardware idenfifier used by an upstream port to

+  reference a downstream port. The physical node of a dport is only

+  available for platform firmware defined downstream ports and alias the

+  companion object, like a PCI host bridge, in the PCI device hierarchy.

+  

+ +The cxl_dport_maps_memdev() helper checks if a dport is an ancestor of a

+ +given memdev.

+ +

+  ENDPOINTS

+  ---------

+  CXL endpoint objects encapsulate the set of host-managed device-memory

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index c972545..c691edf 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -486,6 +486,53 @@ util_cxl_memdev_filter_by_decoder(struct cxl_memdev *memdev, const char *ident)

+  	return NULL;

+  }

+  

+ +static bool __memdev_filter_by_port(struct cxl_memdev *memdev,

+ +				    struct cxl_port *port,

+ +				    const char *port_ident)

+ +{

+ +	struct cxl_endpoint *endpoint;

+ +

+ +	if (util_cxl_port_filter(port, port_ident, CXL_PF_SINGLE) &&

+ +	    cxl_port_get_dport_by_memdev(port, memdev))

+ +		return true;

+ +

+ +	cxl_endpoint_foreach(port, endpoint)

+ +		if (__memdev_filter_by_port(memdev,

+ +					    cxl_endpoint_get_port(endpoint),

+ +					    port_ident))

+ +			return true;

+ +	return false;

+ +}

+ +

+ +static struct cxl_memdev *

+ +util_cxl_memdev_filter_by_port(struct cxl_memdev *memdev, const char *bus_ident,

+ +			       const char *port_ident)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +	struct cxl_bus *bus;

+ +

+ +	if (!bus_ident && !port_ident)

+ +		return memdev;

+ +

+ +	cxl_bus_foreach(ctx, bus) {

+ +		struct cxl_port *port, *top;

+ +

+ +		port = cxl_bus_get_port(bus);

+ +		if (util_cxl_bus_filter(bus, bus_ident))

+ +			if (__memdev_filter_by_port(memdev, port,

+ +						    cxl_bus_get_devname(bus)))

+ +				return memdev;

+ +		if (__memdev_filter_by_port(memdev, port, port_ident))

+ +				return memdev;

+ +		top = port;

+ +		cxl_port_foreach_all(top, port)

+ +			if (__memdev_filter_by_port(memdev, port, port_ident))

+ +				return memdev;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+  static unsigned long params_to_flags(struct cxl_filter_params *param)

+  {

+  	unsigned long flags = 0;

+ @@ -647,6 +694,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,

+  			if (!util_cxl_memdev_filter_by_decoder(

+  				    memdev, p->decoder_filter))

+  				continue;

+ +			if (!util_cxl_memdev_filter_by_port(

+ +				    memdev, p->bus_filter, p->port_filter))

+ +				continue;

+  			if (!p->idle && !cxl_memdev_is_enabled(memdev))

+  				continue;

+  			jobj = util_cxl_memdev_to_json(memdev, flags);

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 4ebb8b9..dcfc826 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1452,6 +1452,29 @@ CXL_EXPORT int cxl_dport_get_id(struct cxl_dport *dport)

+  	return dport->id;

+  }

+  

+ +CXL_EXPORT bool cxl_dport_maps_memdev(struct cxl_dport *dport,

+ +				      struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ +

+ +	dbg(ctx, "memdev: %s dport: %s\n", memdev->host_path, dport->dev_path);

+ +

+ +	if (dport->phys_path)

+ +		return !!strstr(memdev->host_path, dport->phys_path);

+ +	return !!strstr(memdev->host_path, dport->dev_path);

+ +}

+ +

+ +CXL_EXPORT struct cxl_dport *

+ +cxl_port_get_dport_by_memdev(struct cxl_port *port, struct cxl_memdev *memdev)

+ +{

+ +	struct cxl_dport *dport;

+ +

+ +	cxl_dport_foreach(port, dport)

+ +		if (cxl_dport_maps_memdev(dport, memdev))

+ +			return dport;

+ +	return NULL;

+ +}

+ +

+  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 0190b13..2c8358e 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -149,4 +149,6 @@ global:

+  	cxl_dport_get_devname;

+  	cxl_dport_get_physical_node;

+  	cxl_dport_get_id;

+ +	cxl_port_get_dport_by_memdev;

+ +	cxl_dport_maps_memdev;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 874c381..c8d07bb 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -111,6 +111,9 @@ struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);

+  const char *cxl_dport_get_devname(struct cxl_dport *dport);

+  const char *cxl_dport_get_physical_node(struct cxl_dport *dport);

+  int cxl_dport_get_id(struct cxl_dport *dport);

+ +bool cxl_dport_maps_memdev(struct cxl_dport *dport, struct cxl_memdev *memdev);

+ +struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port,

+ +					       struct cxl_memdev *memdev);

+  

+  #define cxl_dport_foreach(port, dport)                                         \

+  	for (dport = cxl_dport_get_first(port); dport != NULL;                 \

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,734 @@ 

+ From 1cfb7570369ae6bed832bde908435d38fa990f9d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:55:01 -0800

+ Subject: [PATCH 122/217] cxl/port: Add {disable,enable}-port command

+ 

+ The {disable,enable}-port commands are used for debugging port enumeration

+ corner cases and testing the kernel CXL device hotplug implementation.

+ 

+ In addition to unbinding the port from its driver, which also kicks of

+ unregistration of descendent ports, the disable operation also flushes the

+ kernels delayed workqueue for memory device removal.

+ 

+ Link: https://lore.kernel.org/r/164298570117.3021641.14546710754812021284.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-disable-port.txt |  46 +++++

+  Documentation/cxl/cxl-enable-port.txt  |  43 +++++

+  Documentation/cxl/lib/libcxl.txt       |  11 ++

+  Documentation/cxl/meson.build          |   2 +

+  cxl/builtin.h                          |   2 +

+  cxl/cxl.c                              |   2 +

+  cxl/filter.c                           |  21 +-

+  cxl/filter.h                           |  13 ++

+  cxl/lib/libcxl.c                       |  95 +++++++++-

+  cxl/lib/libcxl.sym                     |   3 +

+  cxl/libcxl.h                           |   3 +

+  cxl/meson.build                        |   1 +

+  cxl/port.c                             | 253 +++++++++++++++++++++++++

+  13 files changed, 471 insertions(+), 24 deletions(-)

+  create mode 100644 Documentation/cxl/cxl-disable-port.txt

+  create mode 100644 Documentation/cxl/cxl-enable-port.txt

+  create mode 100644 cxl/port.c

+ 

+ diff --git a/Documentation/cxl/cxl-disable-port.txt b/Documentation/cxl/cxl-disable-port.txt

+ new file mode 100644

+ index 0000000..de13c07

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-disable-port.txt

+ @@ -0,0 +1,46 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-disable-port(1)

+ +===================

+ +

+ +NAME

+ +----

+ +cxl-disable-port - activate / hot-add a given CXL port

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl disable-port' <port0> [<port1>..<portN>] [<options>]

+ +

+ +For test and debug scenarios, disable a CXL port and any memory devices

+ +dependent on this port being active for CXL.mem operation.

+ +

+ +OPTIONS

+ +-------

+ +-e::

+ +--endpoint::

+ +	Toggle from treating the port arguments as Switch Port identifiers to

+ +	Endpoint Port identifiers.

+ +

+ +

+ +-f::

+ +--force::

+ +	DANGEROUS: Override the safety measure that blocks attempts to disable a

+ +	port if the tool determines a descendent memdev is in active usage.

+ +	Recall that CXL memory ranges might have been established by platform

+ +	firmware and disabling an active device is akin to force removing memory

+ +	from a running system.

+ +

+ +	Toggle from treating the port arguments as Switch Port identifiers to

+ +	Endpoint Port identifiers.

+ +

+ +--debug::

+ +	If the cxl tool was built with debug disabled, turn on debug

+ +	messages.

+ +

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-disable-port[1]

+ diff --git a/Documentation/cxl/cxl-enable-port.txt b/Documentation/cxl/cxl-enable-port.txt

+ new file mode 100644

+ index 0000000..9a37cef

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-enable-port.txt

+ @@ -0,0 +1,43 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-enable-port(1)

+ +==================

+ +

+ +NAME

+ +----

+ +cxl-enable-port - activate / hot-add a given CXL port

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl enable-port' <port0> [<port1>..<portN>] [<options>]

+ +

+ +A port typically autoenables at initial device discovery. However, if it

+ +was manually disabled this command can trigger the kernel to activate it

+ +again. This involves detecting the state of the HDM (Host Managed Device

+ +Memory) Decoders and validating that CXL.mem is enabled for each port in

+ +the device's hierarchy.

+ +

+ +OPTIONS

+ +-------

+ +-e::

+ +--endpoint::

+ +	Toggle from treating the port arguments as Switch Port identifiers to

+ +	Endpoint Port identifiers.

+ +

+ +-m::

+ +--enable-memdevs::

+ +	Try to enable descendant memdevs after enabling the port. Recall that a

+ +	memdev is only enabled after all CXL ports in its device topology

+ +	ancestry are enabled.

+ +

+ +--debug::

+ +	If the cxl tool was built with debug enabled, turn on debug

+ +	messages.

+ +

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-disable-port[1]

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index a0fcee9..27eb29e 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -247,6 +247,16 @@ Port, or Switch Upstream Port with CXL capabilities.

+  The cxl_port_foreach_all() helper does a depth first iteration of all

+  ports beneath the 'top' port argument.

+  

+ +=== PORT: Control

+ +---

+ +int cxl_port_disable_invalidate(struct cxl_port *port);

+ +int cxl_port_enable(struct cxl_port *port);

+ +---

+ +cxl_port_disable_invalidate() is a violent operation that disables

+ +entire sub-tree of CXL Memory Device and Ports, only use it for test /

+ +debug scenarios, or ensuring that all impacted devices are deactivated

+ +first.

+ +

+  === PORT: Attributes

+  ----

+  const char *cxl_port_get_devname(struct cxl_port *port);

+ @@ -315,6 +325,7 @@ struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);

+  struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);

+  const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);

+  struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);

+ +struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port);

+  

+  #define cxl_endpoint_foreach(port, endpoint)                                 \

+         for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;       \

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index 7618c97..96f4666 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -32,6 +32,8 @@ cxl_manpages = [

+    'cxl-zero-labels.txt',

+    'cxl-enable-memdev.txt',

+    'cxl-disable-memdev.txt',

+ +  'cxl-enable-port.txt',

+ +  'cxl-disable-port.txt',

+  ]

+  

+  foreach man : cxl_manpages

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index 621c85c..3123d5e 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -12,4 +12,6 @@ int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  #endif /* _CXL_BUILTIN_H_ */

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index 78d2e9a..c20c569 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -66,6 +66,8 @@ static struct cmd_struct commands[] = {

+  	{ "write-labels", .c_fn = cmd_write_labels },

+  	{ "disable-memdev", .c_fn = cmd_disable_memdev },

+  	{ "enable-memdev", .c_fn = cmd_enable_memdev },

+ +	{ "disable-port", .c_fn = cmd_disable_port },

+ +	{ "enable-port", .c_fn = cmd_enable_port },

+  };

+  

+  int main(int argc, const char **argv)

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index c691edf..f6a23b7 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -47,8 +47,8 @@ bool cxl_filter_has(const char *__filter, const char *needle)

+  	return false;

+  }

+  

+ -static struct cxl_endpoint *

+ -util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident)

+ +struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,

+ +					      const char *__ident)

+  {

+  	char *ident, *save;

+  	const char *arg;

+ @@ -124,11 +124,6 @@ static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,

+  	return NULL;

+  }

+  

+ -enum cxl_port_filter_mode {

+ -	CXL_PF_SINGLE,

+ -	CXL_PF_ANCESTRY,

+ -};

+ -

+  static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p)

+  {

+  	if (p->single)

+ @@ -136,9 +131,8 @@ static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p)

+  	return CXL_PF_ANCESTRY;

+  }

+  

+ -static struct cxl_port *util_cxl_port_filter(struct cxl_port *port,

+ -					     const char *ident,

+ -					     enum cxl_port_filter_mode mode)

+ +struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident,

+ +				      enum cxl_port_filter_mode mode)

+  {

+  	struct cxl_port *iter = port;

+  

+ @@ -358,9 +352,9 @@ util_cxl_endpoint_filter_by_memdev(struct cxl_endpoint *endpoint,

+  	return NULL;

+  }

+  

+ -static struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,

+ -						       const char *ident,

+ -						       const char *serial)

+ +struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,

+ +						const char *ident,

+ +						const char *serial)

+  {

+  	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+  	struct cxl_memdev *memdev;

+ @@ -958,7 +952,6 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  					continue;

+  				}

+  			}

+ -

+  		}

+  walk_children:

+  		dbg(p, "walk decoders\n");

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 6fd469f..850df70 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -29,6 +29,19 @@ struct cxl_filter_params {

+  struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  					  const char *__ident,

+  					  const char *serials);

+ +struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,

+ +						const char *ident,

+ +						const char *serial);

+ +

+ +enum cxl_port_filter_mode {

+ +	CXL_PF_SINGLE,

+ +	CXL_PF_ANCESTRY,

+ +};

+ +

+ +struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident,

+ +				      enum cxl_port_filter_mode mode);

+ +struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,

+ +					      const char *__ident);

+  int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);

+  bool cxl_filter_has(const char *needle, const char *__filter);

+  #endif /* _CXL_UTIL_FILTER_H_ */

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index dcfc826..1a7dccb 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -258,6 +258,11 @@ CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)

+  	free(ctx);

+  }

+  

+ +static int cxl_flush(struct cxl_ctx *ctx)

+ +{

+ +	return sysfs_write_attr(ctx, "/sys/bus/cxl/flush", "1\n");

+ +}

+ +

+  /**

+   * cxl_set_log_fn - override default log routine

+   * @ctx: cxl library context

+ @@ -530,11 +535,31 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev

+  	return memdev->firmware_version;

+  }

+  

+ +static void bus_invalidate(struct cxl_bus *bus)

+ +{

+ +	struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);

+ +	struct cxl_port *bus_port, *port, *_p;

+ +	struct cxl_memdev *memdev;

+ +

+ +	/*

+ +	 * Something happend to cause the state of all ports to be

+ +	 * indeterminate, delete them all and start over.

+ +	 */

+ +	cxl_memdev_foreach(ctx, memdev)

+ +		if (cxl_memdev_get_bus(memdev) == bus)

+ +			memdev->endpoint = NULL;

+ +

+ +	bus_port = cxl_bus_get_port(bus);

+ +	list_for_each_safe(&bus_port->child_ports, port, _p, list)

+ +		free_port(port, &bus_port->child_ports);

+ +	bus_port->ports_init = 0;

+ +	cxl_flush(ctx);

+ +}

+ +

+  CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)

+  {

+  	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+  	const char *devname = cxl_memdev_get_devname(memdev);

+ -	struct cxl_port *port, *_p, *bus_port;

+  	struct cxl_bus *bus;

+  

+  	if (!cxl_memdev_is_enabled(memdev))

+ @@ -553,15 +578,7 @@ CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)

+  		return -EBUSY;

+  	}

+  

+ -	/*

+ -	 * The state of all ports is now indeterminate, delete them all

+ -	 * and start over.

+ -	 */

+ -	bus_port = cxl_bus_get_port(bus);

+ -	list_for_each_safe(&bus_port->child_ports, port, _p, list)

+ -		free_port(port, &bus_port->child_ports);

+ -	bus_port->ports_init = 0;

+ -	memdev->endpoint = NULL;

+ +	bus_invalidate(bus);

+  

+  	dbg(ctx, "%s: disabled\n", devname);

+  

+ @@ -1352,6 +1369,57 @@ CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)

+  	return is_enabled(path);

+  }

+  

+ +CXL_EXPORT int cxl_port_disable_invalidate(struct cxl_port *port)

+ +{

+ +	const char *devname = cxl_port_get_devname(port);

+ +	struct cxl_bus *bus = cxl_port_get_bus(port);

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +

+ +	if (cxl_port_is_root(port)) {

+ +		err(ctx, "%s: can not be disabled through this interface\n",

+ +		    devname);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (!bus) {

+ +		err(ctx, "%s: failed to invalidate\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	util_unbind(port->dev_path, ctx);

+ +

+ +	if (cxl_port_is_enabled(port)) {

+ +		err(ctx, "%s: failed to disable\n", devname);

+ +		return -EBUSY;

+ +	}

+ +

+ +	dbg(ctx, "%s: disabled\n", devname);

+ +

+ +	bus_invalidate(bus);

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_port_enable(struct cxl_port *port)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	const char *devname = cxl_port_get_devname(port);

+ +

+ +	if (cxl_port_is_enabled(port))

+ +		return 0;

+ +

+ +	util_bind(devname, port->module, "cxl", ctx);

+ +

+ +	if (!cxl_port_is_enabled(port)) {

+ +		err(ctx, "%s: failed to enable\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	dbg(ctx, "%s: enabled\n", devname);

+ +

+ +	return 0;

+ +}

+ +

+  CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)

+  {

+  	if (!cxl_port_is_root(port))

+ @@ -1359,6 +1427,13 @@ CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)

+  	return container_of(port, struct cxl_bus, port);

+  }

+  

+ +CXL_EXPORT struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port)

+ +{

+ +	if (!cxl_port_is_endpoint(port))

+ +		return NULL;

+ +	return container_of(port, struct cxl_endpoint, port);

+ +}

+ +

+  static void *add_cxl_dport(void *parent, int id, const char *cxldport_base)

+  {

+  	const char *devname = devpath_to_devname(cxldport_base);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 2c8358e..67c7fd5 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -97,11 +97,14 @@ global:

+  	cxl_port_is_switch;

+  	cxl_port_to_bus;

+  	cxl_port_is_endpoint;

+ +	cxl_port_to_endpoint;

+  	cxl_port_get_bus;

+  	cxl_port_get_host;

+  	cxl_port_get_bus;

+  	cxl_port_hosts_memdev;

+  	cxl_port_get_nr_dports;

+ +	cxl_port_disable_invalidate;

+ +	cxl_port_enable;

+  	cxl_port_get_next_all;

+  	cxl_endpoint_get_first;

+  	cxl_endpoint_get_next;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index c8d07bb..1aac396 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -90,10 +90,13 @@ bool cxl_port_is_root(struct cxl_port *port);

+  bool cxl_port_is_switch(struct cxl_port *port);

+  struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);

+  bool cxl_port_is_endpoint(struct cxl_port *port);

+ +struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port);

+  struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);

+  const char *cxl_port_get_host(struct cxl_port *port);

+  bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);

+  int cxl_port_get_nr_dports(struct cxl_port *port);

+ +int cxl_port_disable_invalidate(struct cxl_port *port);

+ +int cxl_port_enable(struct cxl_port *port);

+  struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,

+  				       const struct cxl_port *top);

+  

+ diff --git a/cxl/meson.build b/cxl/meson.build

+ index fc7ee71..87cfea7 100644

+ --- a/cxl/meson.build

+ +++ b/cxl/meson.build

+ @@ -1,6 +1,7 @@

+  cxl_src = [

+    'cxl.c',

+    'list.c',

+ +  'port.c',

+    'memdev.c',

+    '../util/json.c',

+    '../util/log.c',

+ diff --git a/cxl/port.c b/cxl/port.c

+ new file mode 100644

+ index 0000000..46a8f32

+ --- /dev/null

+ +++ b/cxl/port.c

+ @@ -0,0 +1,253 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */

+ +#include <stdio.h>

+ +#include <errno.h>

+ +#include <stdlib.h>

+ +#include <unistd.h>

+ +#include <limits.h>

+ +#include <util/log.h>

+ +#include <cxl/libcxl.h>

+ +#include <util/parse-options.h>

+ +#include <ccan/minmax/minmax.h>

+ +#include <ccan/array_size/array_size.h>

+ +

+ +#include "filter.h"

+ +

+ +static struct parameters {

+ +	bool debug;

+ +	bool force;

+ +	bool memdevs;

+ +	bool endpoint;

+ +} param;

+ +

+ +static struct log_ctx pl;

+ +

+ +#define BASE_OPTIONS()                                                 \

+ +OPT_BOOLEAN(0, "debug", &param.debug, "turn on debug"),                \

+ +OPT_BOOLEAN('e', "endpoint", &param.endpoint,                          \

+ +	    "target endpoints instead of switch ports")

+ +

+ +#define ENABLE_OPTIONS()                                               \

+ +OPT_BOOLEAN('m', "enable-memdevs", &param.memdevs,                   \

+ +	    "enable downstream memdev(s)")

+ +

+ +#define DISABLE_OPTIONS()                                              \

+ +OPT_BOOLEAN('f', "force", &param.force,                                \

+ +	    "DANGEROUS: override active memdev safety checks")

+ +

+ +static const struct option disable_options[] = {

+ +	BASE_OPTIONS(),

+ +	DISABLE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static const struct option enable_options[] = {

+ +	BASE_OPTIONS(),

+ +	ENABLE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static int action_disable(struct cxl_port *port)

+ +{

+ +	const char *devname = cxl_port_get_devname(port);

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	struct cxl_memdev *memdev;

+ +	int active_memdevs = 0;

+ +

+ +	if (!cxl_port_is_enabled(port)) {

+ +		log_dbg(&pl, "%s already disabled\n", devname);

+ +		return 0;

+ +	}

+ +

+ +	if (param.endpoint) {

+ +		struct cxl_endpoint *endpoint = cxl_port_to_endpoint(port);

+ +

+ +		if (cxl_endpoint_get_memdev(endpoint))

+ +			active_memdevs++;

+ +	}

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		if (!cxl_port_get_dport_by_memdev(port, memdev))

+ +			continue;

+ +		if (cxl_memdev_is_enabled(memdev))

+ +			active_memdevs++;

+ +	}

+ +

+ +	if (active_memdevs && !param.force) {

+ +		/*

+ +		 * TODO: actually detect rather than assume active just

+ +		 * because the memdev is enabled

+ +		 */

+ +		log_err(&pl,

+ +			"%s hosts %d memdev%s which %s part of an active region\n",

+ +			devname, active_memdevs, active_memdevs > 1 ? "s" : "",

+ +			active_memdevs > 1 ? "are" : "is");

+ +		log_err(&pl,

+ +			"See 'cxl list -M -p %s' to see impacted device%s\n",

+ +			devname, active_memdevs > 1 ? "s" : "");

+ +		return -EBUSY;

+ +	}

+ +

+ +	return cxl_port_disable_invalidate(port);

+ +}

+ +

+ +static int action_enable(struct cxl_port *port)

+ +{

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	struct cxl_memdev *memdev;

+ +	int rc;

+ +

+ +	rc = cxl_port_enable(port);

+ +	if (rc || !param.memdevs)

+ +		return rc;

+ +

+ +	cxl_memdev_foreach(ctx, memdev)

+ +		if (cxl_port_get_dport_by_memdev(port, memdev))

+ +			cxl_memdev_enable(memdev);

+ +	return 0;

+ +}

+ +

+ +static struct cxl_port *find_cxl_port(struct cxl_ctx *ctx, const char *ident)

+ +{

+ +	struct cxl_bus *bus;

+ +	struct cxl_port *port;

+ +

+ +	cxl_bus_foreach(ctx, bus)

+ +		cxl_port_foreach_all(cxl_bus_get_port(bus), port)

+ +			if (util_cxl_port_filter(port, ident, CXL_PF_SINGLE))

+ +				return port;

+ +	return NULL;

+ +}

+ +

+ +static struct cxl_endpoint *find_cxl_endpoint(struct cxl_ctx *ctx,

+ +					      const char *ident)

+ +{

+ +	struct cxl_bus *bus;

+ +	struct cxl_port *port;

+ +	struct cxl_endpoint *endpoint;

+ +

+ +	cxl_bus_foreach(ctx, bus)

+ +		cxl_port_foreach_all(cxl_bus_get_port(bus), port)

+ +			cxl_endpoint_foreach(port, endpoint)

+ +				if (util_cxl_endpoint_filter(endpoint, ident))

+ +					return endpoint;

+ +	return NULL;

+ +}

+ +

+ +

+ +

+ +static int port_action(int argc, const char **argv, struct cxl_ctx *ctx,

+ +		       int (*action)(struct cxl_port *port),

+ +		       const struct option *options, const char *usage)

+ +{

+ +	int i, rc = 0, count = 0, err = 0;

+ +	const char * const u[] = {

+ +		usage,

+ +		NULL

+ +	};

+ +	unsigned long id;

+ +

+ +	log_init(&pl, "cxl port", "CXL_PORT_LOG");

+ +	argc = parse_options(argc, argv, options, u, 0);

+ +

+ +	if (argc == 0)

+ +		usage_with_options(u, options);

+ +	for (i = 0; i < argc; i++) {

+ +		const char *fmt;

+ +

+ +		if (strcmp(argv[i], "all") == 0) {

+ +			argc = 1;

+ +			break;

+ +		}

+ +

+ +		if (param.endpoint)

+ +			fmt = "endpoint%lu";

+ +		else

+ +			fmt = "port%lu";

+ +

+ +		if (sscanf(argv[i], fmt, &id) == 1)

+ +			continue;

+ +		if (sscanf(argv[i], "%lu", &id) == 1)

+ +			continue;

+ +

+ +		log_err(&pl, "'%s' is not a valid %s identifer\n", argv[i],

+ +			param.endpoint ? "endpoint" : "port");

+ +		err++;

+ +	}

+ +

+ +	if (err == argc) {

+ +		usage_with_options(u, options);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (param.debug) {

+ +		cxl_set_log_priority(ctx, LOG_DEBUG);

+ +		pl.log_priority = LOG_DEBUG;

+ +	} else

+ +		pl.log_priority = LOG_INFO;

+ +

+ +	rc = 0;

+ +	err = 0;

+ +	count = 0;

+ +

+ +	for (i = 0; i < argc; i++) {

+ +		struct cxl_port *port;

+ +

+ +		if (param.endpoint) {

+ +			struct cxl_endpoint *endpoint;

+ +

+ +			endpoint = find_cxl_endpoint(ctx, argv[i]);

+ +			if (!endpoint) {

+ +				log_dbg(&pl, "endpoint: %s not found\n",

+ +					argv[i]);

+ +				continue;

+ +			}

+ +			port = cxl_endpoint_get_port(endpoint);

+ +		} else {

+ +			port = find_cxl_port(ctx, argv[i]);

+ +			if (!port) {

+ +				log_dbg(&pl, "port: %s not found\n", argv[i]);

+ +				continue;

+ +			}

+ +		}

+ +

+ +		log_dbg(&pl, "run action on port: %s\n",

+ +			cxl_port_get_devname(port));

+ +		rc = action(port);

+ +		if (rc == 0)

+ +			count++;

+ +		else if (rc && !err)

+ +			err = rc;

+ +	}

+ +	rc = err;

+ +

+ +	/*

+ +	 * count if some actions succeeded, 0 if none were attempted,

+ +	 * negative error code otherwise.

+ +	 */

+ +	if (count > 0)

+ +		return count;

+ +	return rc;

+ + }

+ +

+ + int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx)

+ + {

+ +	 int count = port_action(

+ +		 argc, argv, ctx, action_disable, disable_options,

+ +		 "cxl disable-port <port0> [<port1>..<portN>] [<options>]");

+ +

+ +	 log_info(&pl, "disabled %d port%s\n", count >= 0 ? count : 0,

+ +		  count > 1 ? "s" : "");

+ +	 return count >= 0 ? 0 : EXIT_FAILURE;

+ + }

+ +

+ + int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx)

+ + {

+ +	 int count = port_action(

+ +		 argc, argv, ctx, action_enable, enable_options,

+ +		 "cxl enable-port <port0> [<port1>..<portN>] [<options>]");

+ +

+ +	 log_info(&pl, "enabled %d port%s\n", count >= 0 ? count : 0,

+ +		  count > 1 ? "s" : "");

+ +	 return count >= 0 ? 0 : EXIT_FAILURE;

+ + }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,340 @@ 

+ From f9ebf984e7eb93a044f48c4089485051751face8 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Sun, 23 Jan 2022 16:55:06 -0800

+ Subject: [PATCH 123/217] cxl/list: Filter dports and targets by memdevs

+ 

+ Trim dport / target information by the memdev filter. This is useful when

+ validating connectivity and decoder programming.

+ 

+ Link: https://lore.kernel.org/r/164298570626.3021641.18034728333613142555.stgit@dwillia2-desk3.amr.corp.intel.com

+ Reported-by: Ben Widawsky <ben.widawsky@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  1 +

+  cxl/filter.c                     | 51 ++++++++++++++++++++++++++++++++

+  cxl/filter.h                     |  6 ++++

+  cxl/json.c                       | 51 +++++++++++++++++++++-----------

+  cxl/json.h                       |  7 +++++

+  cxl/lib/libcxl.c                 |  5 ++++

+  cxl/lib/libcxl.sym               |  1 +

+  cxl/libcxl.h                     |  1 +

+  8 files changed, 105 insertions(+), 18 deletions(-)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 27eb29e..4392b47 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -221,6 +221,7 @@ const char *cxl_port_get_host(struct cxl_port *port);

+  struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder);

+  struct cxl_port *cxl_port_get_next_all(struct cxl_port *port,

+                                         const struct cxl_port *top);

+ +struct cxl_port *cxl_dport_get_port(struct cxl_dport *dport);

+  

+  #define cxl_port_foreach(parent, port)                                      \

+         for (port = cxl_port_get_first(parent); port != NULL;                \

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index f6a23b7..925bf3a 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -435,6 +435,48 @@ util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,

+  	return NULL;

+  }

+  

+ +struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target,

+ +						    const char *ident,

+ +						    const char *serial)

+ +{

+ +	struct cxl_decoder *decoder = cxl_target_get_decoder(target);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (!ident && !serial)

+ +		return target;

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		if (!util_cxl_memdev_filter(memdev, ident, serial))

+ +			continue;

+ +		if (cxl_target_maps_memdev(target, memdev))

+ +			return target;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+ +struct cxl_dport *util_cxl_dport_filter_by_memdev(struct cxl_dport *dport,

+ +						  const char *ident,

+ +						  const char *serial)

+ +{

+ +	struct cxl_port *port = cxl_dport_get_port(dport);

+ +	struct cxl_ctx *ctx = cxl_port_get_ctx(port);

+ +	struct cxl_memdev *memdev;

+ +

+ +	if (!ident && !serial)

+ +		return dport;

+ +

+ +	cxl_memdev_foreach (ctx, memdev) {

+ +		if (!util_cxl_memdev_filter(memdev, ident, serial))

+ +			continue;

+ +		if (cxl_dport_maps_memdev(dport, memdev))

+ +			return dport;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+  static bool __memdev_filter_by_decoder(struct cxl_memdev *memdev,

+  				       struct cxl_port *port, const char *ident)

+  {

+ @@ -639,6 +681,9 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,

+  			dbg(p, "decoder object allocation failure\n");

+  			continue;

+  		}

+ +		util_cxl_targets_append_json(jdecoder, decoder,

+ +					     p->memdev_filter, p->serial_filter,

+ +					     flags);

+  		json_object_array_add(jdecoders, jdecoder);

+  	}

+  }

+ @@ -756,6 +801,9 @@ walk_child_ports(struct cxl_port *parent_port, struct cxl_filter_params *p,

+  				err(p, "%s: failed to list\n", devname);

+  				continue;

+  			}

+ +			util_cxl_dports_append_json(jport, port,

+ +						    p->memdev_filter,

+ +						    p->serial_filter, flags);

+  			json_object_array_add(jports, jport);

+  			jchildports = json_object_new_array();

+  			if (!jchildports) {

+ @@ -914,6 +962,9 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  				dbg(p, "bus object allocation failure\n");

+  				continue;

+  			}

+ +			util_cxl_dports_append_json(jbus, port,

+ +						    p->memdev_filter,

+ +						    p->serial_filter, flags);

+  			json_object_array_add(jbuses, jbus);

+  			if (p->ports) {

+  				jchildports = json_object_new_array();

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 850df70..5deabb3 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -42,6 +42,12 @@ struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident,

+  				      enum cxl_port_filter_mode mode);

+  struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,

+  					      const char *__ident);

+ +struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target,

+ +						    const char *ident,

+ +						    const char *serial);

+ +struct cxl_dport *util_cxl_dport_filter_by_memdev(struct cxl_dport *dport,

+ +						  const char *ident,

+ +						  const char *serial);

+  int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);

+  bool cxl_filter_has(const char *needle, const char *__filter);

+  #endif /* _CXL_UTIL_FILTER_H_ */

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 4fb5eec..f3b536e 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -8,6 +8,7 @@

+  #include <json-c/printbuf.h>

+  #include <ccan/short_types/short_types.h>

+  

+ +#include "filter.h"

+  #include "json.h"

+  

+  static struct json_object *util_cxl_memdev_health_to_json(

+ @@ -241,9 +242,9 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  	return jdev;

+  }

+  

+ -static struct json_object *util_cxl_dports_to_json(struct json_object *jport,

+ -						   struct cxl_port *port,

+ -						   unsigned long flags)

+ +void util_cxl_dports_append_json(struct json_object *jport,

+ +				 struct cxl_port *port, const char *ident,

+ +				 const char *serial, unsigned long flags)

+  {

+  	struct json_object *jobj, *jdports;

+  	struct cxl_dport *dport;

+ @@ -251,7 +252,7 @@ static struct json_object *util_cxl_dports_to_json(struct json_object *jport,

+  

+  	val = cxl_port_get_nr_dports(port);

+  	if (!val || !(flags & UTIL_JSON_TARGETS))

+ -		return jport;

+ +		return;

+  

+  	jobj = json_object_new_int(val);

+  	if (jobj)

+ @@ -259,12 +260,15 @@ static struct json_object *util_cxl_dports_to_json(struct json_object *jport,

+  

+  	jdports = json_object_new_array();

+  	if (!jdports)

+ -		return jport;

+ +		return;

+  

+  	cxl_dport_foreach(port, dport) {

+  		struct json_object *jdport;

+  		const char *phys_node;

+  

+ +		if (!util_cxl_dport_filter_by_memdev(dport, ident, serial))

+ +			continue;

+ +

+  		jdport = json_object_new_object();

+  		if (!jdport)

+  			continue;

+ @@ -289,8 +293,6 @@ static struct json_object *util_cxl_dports_to_json(struct json_object *jport,

+  	}

+  

+  	json_object_object_add(jport, "dports", jdports);

+ -

+ -	return jport;

+  }

+  

+  struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+ @@ -311,7 +313,7 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,

+  	if (jobj)

+  		json_object_object_add(jbus, "provider", jobj);

+  

+ -	return util_cxl_dports_to_json(jbus, cxl_bus_get_port(bus), flags);

+ +	return jbus;

+  }

+  

+  struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+ @@ -320,8 +322,6 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	const char *devname = cxl_decoder_get_devname(decoder);

+  	struct cxl_port *port = cxl_decoder_get_port(decoder);

+  	struct json_object *jdecoder, *jobj;

+ -	struct json_object *jtargets;

+ -	struct cxl_target *target;

+  	u64 val;

+  

+  	jdecoder = json_object_new_object();

+ @@ -375,9 +375,22 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  					       jobj);

+  	}

+  

+ +	return jdecoder;

+ +}

+ +

+ +void util_cxl_targets_append_json(struct json_object *jdecoder,

+ +				  struct cxl_decoder *decoder,

+ +				  const char *ident, const char *serial,

+ +				  unsigned long flags)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct json_object *jobj, *jtargets;

+ +	struct cxl_target *target;

+ +	int val;

+ +

+  	/* Endpoints don't have targets, they *are* targets */

+  	if (cxl_port_is_endpoint(port))

+ -		return jdecoder;

+ +		return;

+  

+  	val = cxl_decoder_get_nr_targets(decoder);

+  	jobj = json_object_new_int(val);

+ @@ -386,16 +399,21 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  

+  	if (!(flags & UTIL_JSON_TARGETS) ||

+  	    !cxl_decoder_get_nr_targets(decoder))

+ -		return jdecoder;

+ +		return;

+  

+  	jtargets = json_object_new_array();

+  	if (!jtargets)

+ -		return jdecoder;

+ +		return;

+  

+  	cxl_target_foreach(decoder, target) {

+ -		struct json_object *jtarget = json_object_new_object();

+ +		struct json_object *jtarget;

+  		const char *phys_node;

+ +		const char *devname;

+ +

+ +		if (!util_cxl_target_filter_by_memdev(target, ident, serial))

+ +			continue;

+  

+ +		jtarget = json_object_new_object();

+  		if (!jtarget)

+  			continue;

+  

+ @@ -425,9 +443,6 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	}

+  

+  	json_object_object_add(jdecoder, "targets", jtargets);

+ -

+ -	return jdecoder;

+ -

+  }

+  

+  static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,

+ @@ -455,7 +470,7 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,

+  			json_object_object_add(jport, "state", jobj);

+  	}

+  

+ -	return util_cxl_dports_to_json(jport, port, flags);

+ +	return jport;

+  }

+  

+  struct json_object *util_cxl_port_to_json(struct cxl_port *port,

+ diff --git a/cxl/json.h b/cxl/json.h

+ index fcca2e6..9a5a845 100644

+ --- a/cxl/json.h

+ +++ b/cxl/json.h

+ @@ -15,4 +15,11 @@ struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint,

+  					      unsigned long flags);

+  struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  					     unsigned long flags);

+ +void util_cxl_targets_append_json(struct json_object *jdecoder,

+ +				  struct cxl_decoder *decoder,

+ +				  const char *ident, const char *serial,

+ +				  unsigned long flags);

+ +void util_cxl_dports_append_json(struct json_object *jport,

+ +				 struct cxl_port *port, const char *ident,

+ +				 const char *serial, unsigned long flags);

+  #endif /* __CXL_UTIL_JSON_H__ */

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 1a7dccb..e0b443f 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1527,6 +1527,11 @@ CXL_EXPORT int cxl_dport_get_id(struct cxl_dport *dport)

+  	return dport->id;

+  }

+  

+ +CXL_EXPORT struct cxl_port *cxl_dport_get_port(struct cxl_dport *dport)

+ +{

+ +	return dport->port;

+ +}

+ +

+  CXL_EXPORT bool cxl_dport_maps_memdev(struct cxl_dport *dport,

+  				      struct cxl_memdev *memdev)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 67c7fd5..e56a2bf 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -152,6 +152,7 @@ global:

+  	cxl_dport_get_devname;

+  	cxl_dport_get_physical_node;

+  	cxl_dport_get_id;

+ +	cxl_dport_get_port;

+  	cxl_port_get_dport_by_memdev;

+  	cxl_dport_maps_memdev;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 1aac396..3b2293b 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -113,6 +113,7 @@ struct cxl_dport *cxl_dport_get_first(struct cxl_port *port);

+  struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport);

+  const char *cxl_dport_get_devname(struct cxl_dport *dport);

+  const char *cxl_dport_get_physical_node(struct cxl_dport *dport);

+ +struct cxl_port *cxl_dport_get_port(struct cxl_dport *dport);

+  int cxl_dport_get_id(struct cxl_dport *dport);

+  bool cxl_dport_maps_memdev(struct cxl_dport *dport, struct cxl_memdev *memdev);

+  struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port,

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,46 @@ 

+ From 4921c0c2040ffbe10facd320f6a718a3d42ad815 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 17 Feb 2022 22:42:29 -0700

+ Subject: [PATCH 124/217] ndctl/test: make inject-smart.sh more tolerant of

+  decimal fields

+ 

+ Some combinations of json-c/jq/other libraries seem to produce differing

+ outputs for the final jq-filtered smart fields, in that some have a

+ decimal "42.0" numeric field, where as in other combinations it is a

+ simple "42" (still a numeric field, not string).

+ 

+ This shouldn't matter in practice, but for this contrived test case, we

+ need to make sure that "42" is treated the same as "42.0"

+ 

+ Normalize all fields before comparing them to "%0.0f" so that the

+ comparison doesn't result in superfluous failures.

+ 

+ Reported-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/inject-smart.sh | 4 ++--

+  1 file changed, 2 insertions(+), 2 deletions(-)

+ 

+ diff --git a/test/inject-smart.sh b/test/inject-smart.sh

+ index 8b91360..046322b 100755

+ --- a/test/inject-smart.sh

+ +++ b/test/inject-smart.sh

+ @@ -105,13 +105,13 @@ get_field()

+  	json="$($NDCTL list -b $bus -d $dimm -H)"

+  	val="$(jq -r ".[].dimms[].health.$smart_listing" <<< $json)"

+  	val="$(translate_val $val)"

+ -	echo $val

+ +	printf "%0.0f\n" "$val"

+  }

+  

+  verify()

+  {

+  	local field="$1"

+ -	local val="$2"

+ +	local val="$(printf "%0.0f\n" "$2")"

+  

+  	[[ "$val" == "$(get_field $field)" ]]

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,136 @@ 

+ From aa990008f48f21121474a411d829f24e832c89a2 Mon Sep 17 00:00:00 2001

+ From: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Date: Tue, 25 Jan 2022 00:26:05 +0530

+ Subject: [PATCH 125/217] libndctl/papr: Add support for reporting

+  shutdown-count

+ 

+ Add support for reporting dirty-shutdown-count (DSC) for PAPR based

+ NVDIMMs. The sysfs attribute exposing this value is located at

+ nmemX/papr/dirty_shutdown.

+ 

+ This counter is also returned in payload for PAPR_PDSM_HEALTH as newly

+ introduced member 'dimm_dsc' in 'struct nd_papr_pdsm_health'. Presence

+ of 'DSC' is indicated by the PDSM_DIMM_DSC_VALID extension flag.

+ 

+ The patch implements 'ndctl_dimm_ops.smart_get_shutdown_count'

+ callback in implemented as papr_smart_get_shutdown_count().

+ 

+ Kernel side changes to support reporting DSC have been merged to linux kernel

+ via patch proposed at [1]. With updated kernel 'ndctl list -DH' reports

+ following output on PPC64:

+ 

+ $ sudo ndctl list -DH

+ [

+   {

+     "dev":"nmem0",

+     "health":{

+       "health_state":"ok",

+       "life_used_percentage":50,

+       "shutdown_state":"clean",

+       "shutdown_count":10

+     }

+   }

+ ]

+ 

+ [1] http://patchwork.ozlabs.org/project/linuxppc-dev/patch/20210624080621.252038-1-vaibhav@linux.ibm.com

+ 

+ Link: https://lore.kernel.org/r/20220124185605.1465681-1-vaibhav@linux.ibm.com

+ Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c  |  6 +++++-

+  ndctl/lib/papr.c      | 23 +++++++++++++++++++++++

+  ndctl/lib/papr_pdsm.h |  6 ++++++

+  3 files changed, 34 insertions(+), 1 deletion(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 47a234c..5979a92 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -1819,8 +1819,12 @@ static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base)

+  

+  		/* Allocate monitor mode fd */

+  		dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);

+ -		rc = 0;

+ +		/* Get the dirty shutdown counter value */

+ +		sprintf(path, "%s/papr/dirty_shutdown", dimm_base);

+ +		if (sysfs_read_attr(ctx, path, buf) == 0)

+ +			dimm->dirty_shutdown = strtoll(buf, NULL, 0);

+  

+ +		rc = 0;

+  	} else if (strcmp(buf, "nvdimm_test") == 0) {

+  		/* probe via common populate_dimm_attributes() */

+  		rc = populate_dimm_attributes(dimm, dimm_base, "papr");

+ diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c

+ index 43b8412..46cf9c1 100644

+ --- a/ndctl/lib/papr.c

+ +++ b/ndctl/lib/papr.c

+ @@ -165,6 +165,9 @@ static unsigned int papr_smart_get_flags(struct ndctl_cmd *cmd)

+  		if (health.extension_flags & PDSM_DIMM_HEALTH_RUN_GAUGE_VALID)

+  			flags |= ND_SMART_USED_VALID;

+  

+ +		if (health.extension_flags &  PDSM_DIMM_DSC_VALID)

+ +			flags |= ND_SMART_SHUTDOWN_COUNT_VALID;

+ +

+  		return flags;

+  	}

+  

+ @@ -236,6 +239,25 @@ static unsigned int papr_smart_get_life_used(struct ndctl_cmd *cmd)

+  		(100 - health.dimm_fuel_gauge) : 0;

+  }

+  

+ +static unsigned int papr_smart_get_shutdown_count(struct ndctl_cmd *cmd)

+ +{

+ +

+ +	struct nd_papr_pdsm_health health;

+ +

+ +	/* Ignore in case of error or invalid pdsm */

+ +	if (!cmd_is_valid(cmd) ||

+ +	    to_pdsm(cmd)->cmd_status != 0 ||

+ +	    to_pdsm_cmd(cmd) != PAPR_PDSM_HEALTH)

+ +		return 0;

+ +

+ +	/* get the payload from command */

+ +	health = to_payload(cmd)->health;

+ +

+ +	return (health.extension_flags & PDSM_DIMM_DSC_VALID) ?

+ +		(health.dimm_dsc) : 0;

+ +

+ +}

+ +

+  struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) {

+  	.cmd_is_supported = papr_cmd_is_supported,

+  	.smart_get_flags = papr_smart_get_flags,

+ @@ -245,4 +267,5 @@ struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) {

+  	.smart_get_health = papr_smart_get_health,

+  	.smart_get_shutdown_state = papr_smart_get_shutdown_state,

+  	.smart_get_life_used = papr_smart_get_life_used,

+ +	.smart_get_shutdown_count = papr_smart_get_shutdown_count,

+  };

+ diff --git a/ndctl/lib/papr_pdsm.h b/ndctl/lib/papr_pdsm.h

+ index 1bac8a7..f45b1e4 100644

+ --- a/ndctl/lib/papr_pdsm.h

+ +++ b/ndctl/lib/papr_pdsm.h

+ @@ -75,6 +75,9 @@

+  /* Indicate that the 'dimm_fuel_gauge' field is valid */

+  #define PDSM_DIMM_HEALTH_RUN_GAUGE_VALID 1

+  

+ +/* Indicate that the 'dimm_dsc' field is valid */

+ +#define PDSM_DIMM_DSC_VALID 2

+ +

+  /*

+   * Struct exchanged between kernel & ndctl in for PAPR_PDSM_HEALTH

+   * Various flags indicate the health status of the dimm.

+ @@ -103,6 +106,9 @@ struct nd_papr_pdsm_health {

+  

+  			/* Extension flag PDSM_DIMM_HEALTH_RUN_GAUGE_VALID */

+  			__u16 dimm_fuel_gauge;

+ +

+ +			/* Extension flag PDSM_DIMM_DSC_VALID */

+ +			__u64 dimm_dsc;

+  		};

+  		__u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];

+  	};

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,161 @@ 

+ From edcd9b7e10b3b33a9660e412a2db1beab30936d3 Mon Sep 17 00:00:00 2001

+ From: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Date: Tue, 25 Jan 2022 02:07:35 +0530

+ Subject: [PATCH 126/217] libndctl, intel: Indicate supported smart-inject

+  types

+ 

+ Presently the inject-smart code assumes support for injecting all

+ smart-errors namely media-temperature, controller-temperature,

+ spares-remaining, fatal-health and unsafe-shutdown. This assumption

+ may break in case of other non-Intel NVDIMM types namely PAPR NVDIMMs

+ which presently only have support for injecting unsafe-shutdown and

+ fatal health events.

+ 

+ Trying to inject-smart errors on PAPR NVDIMMs causes problems as

+ smart_inject() prematurely exits when trying to inject

+ media-temperature smart-error errors out.

+ 

+ To fix this issue the patch proposes extending the definition of

+ dimm_op 'smart_inject_supported' to return bitmap of flags indicating

+ the type of smart-error injections supported by an NVDIMM. These types

+ are indicated by the newly introduced defines ND_SMART_INJECT_* . A

+ dimm-ops provide can return an bitmap composed of these flags back

+ from its implementation of 'smart_inject_supported' to indicate to

+ dimm_inject_smart() which type of smart-error injection it

+ supports. In case of an error the dimm-op is still expected to return

+ a negative error code back to the caller.

+ 

+ The patch updates intel_dimm_smart_inject_supported() to return a

+ bitmap composed of all ND_SMART_INJECT_* flags to indicate support for

+ all smart-error types.

+ 

+ Finally the patch also updates smart_inject() to test for specific

+ ND_START_INJECT_* flags before sending a smart-inject command via

+ dimm-provider.

+ 

+ Link: https://lore.kernel.org/r/20220124203735.1490186-1-vaibhav@linux.ibm.com

+ Reviewed-by: Ira Weiny <ira.weiny@intel.com>

+ Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/inject-smart.c | 31 ++++++++++++++++++++++++-------

+  ndctl/lib/intel.c    |  7 ++++++-

+  ndctl/libndctl.h     |  8 ++++++++

+  3 files changed, 38 insertions(+), 8 deletions(-)

+ 

+ diff --git a/ndctl/inject-smart.c b/ndctl/inject-smart.c

+ index 2b9d7e8..bd8c01e 100644

+ --- a/ndctl/inject-smart.c

+ +++ b/ndctl/inject-smart.c

+ @@ -395,18 +395,26 @@ out:

+  	} \

+  }

+  

+ -static int smart_inject(struct ndctl_dimm *dimm)

+ +static int smart_inject(struct ndctl_dimm *dimm, unsigned int inject_types)

+  {

+  	const char *name = ndctl_dimm_get_devname(dimm);

+  	struct ndctl_cmd *si_cmd = NULL;

+  	int rc = -EOPNOTSUPP;

+  

+ -	send_inject_val(media_temperature)

+ -	send_inject_val(ctrl_temperature)

+ -	send_inject_val(spares)

+ -	send_inject_bool(fatal)

+ -	send_inject_bool(unsafe_shutdown)

+ +	if (inject_types & ND_SMART_INJECT_MEDIA_TEMPERATURE)

+ +		send_inject_val(media_temperature);

+  

+ +	if (inject_types & ND_SMART_INJECT_CTRL_TEMPERATURE)

+ +		send_inject_val(ctrl_temperature);

+ +

+ +	if (inject_types & ND_SMART_INJECT_SPARES_REMAINING)

+ +		send_inject_val(spares);

+ +

+ +	if (inject_types & ND_SMART_INJECT_HEALTH_STATE)

+ +		send_inject_bool(fatal);

+ +

+ +	if (inject_types & ND_SMART_INJECT_UNCLEAN_SHUTDOWN)

+ +		send_inject_bool(unsafe_shutdown);

+  out:

+  	ndctl_cmd_unref(si_cmd);

+  	return rc;

+ @@ -417,6 +425,7 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm)

+  	struct json_object *jhealth;

+  	struct json_object *jdimms;

+  	struct json_object *jdimm;

+ +	unsigned int supported_types;

+  	int rc;

+  

+  	rc = ndctl_dimm_smart_inject_supported(dimm);

+ @@ -433,6 +442,14 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm)

+  		error("%s: smart injection not supported by either platform firmware or the kernel.",

+  			ndctl_dimm_get_devname(dimm));

+  		return rc;

+ +	default:

+ +		if (rc < 0) {

+ +			error("%s: Unknown error %d while checking for smart injection support",

+ +			      ndctl_dimm_get_devname(dimm), rc);

+ +			return rc;

+ +		}

+ +		supported_types = rc;

+ +		break;

+  	}

+  

+  	if (sctx.op_mask & (1 << OP_SET)) {

+ @@ -441,7 +458,7 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm)

+  			goto out;

+  	}

+  	if (sctx.op_mask & (1 << OP_INJECT)) {

+ -		rc = smart_inject(dimm);

+ +		rc = smart_inject(dimm, supported_types);

+  		if (rc)

+  			goto out;

+  	}

+ diff --git a/ndctl/lib/intel.c b/ndctl/lib/intel.c

+ index a3df26e..1314854 100644

+ --- a/ndctl/lib/intel.c

+ +++ b/ndctl/lib/intel.c

+ @@ -455,7 +455,12 @@ static int intel_dimm_smart_inject_supported(struct ndctl_dimm *dimm)

+  		return -EIO;

+  	}

+  

+ -	return 0;

+ +	/* Indicate all smart injection types are supported */

+ +	return ND_SMART_INJECT_SPARES_REMAINING |

+ +		ND_SMART_INJECT_MEDIA_TEMPERATURE |

+ +		ND_SMART_INJECT_CTRL_TEMPERATURE |

+ +		ND_SMART_INJECT_HEALTH_STATE |

+ +		ND_SMART_INJECT_UNCLEAN_SHUTDOWN;

+  }

+  

+  static const char *intel_cmd_desc(int fn)

+ diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h

+ index b59026c..4d5cdbf 100644

+ --- a/ndctl/libndctl.h

+ +++ b/ndctl/libndctl.h

+ @@ -69,6 +69,13 @@ extern "C" {

+  #define ND_EVENT_HEALTH_STATE		(1 << 3)

+  #define ND_EVENT_UNCLEAN_SHUTDOWN	(1 << 4)

+  

+ +/* Flags indicating support for various smart injection types */

+ +#define ND_SMART_INJECT_SPARES_REMAINING	(1 << 0)

+ +#define ND_SMART_INJECT_MEDIA_TEMPERATURE	(1 << 1)

+ +#define ND_SMART_INJECT_CTRL_TEMPERATURE	(1 << 2)

+ +#define ND_SMART_INJECT_HEALTH_STATE		(1 << 3)

+ +#define ND_SMART_INJECT_UNCLEAN_SHUTDOWN	(1 << 4)

+ +

+  size_t ndctl_min_namespace_size(void);

+  size_t ndctl_sizeof_namespace_index(void);

+  size_t ndctl_sizeof_namespace_label(void);

+ @@ -311,6 +318,7 @@ int ndctl_cmd_smart_inject_spares(struct ndctl_cmd *cmd, bool enable,

+  		unsigned int spares);

+  int ndctl_cmd_smart_inject_fatal(struct ndctl_cmd *cmd, bool enable);

+  int ndctl_cmd_smart_inject_unsafe_shutdown(struct ndctl_cmd *cmd, bool enable);

+ +/* Returns a bitmap of ND_SMART_INJECT_* supported */

+  int ndctl_dimm_smart_inject_supported(struct ndctl_dimm *dimm);

+  

+  struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(struct ndctl_dimm *dimm,

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,180 @@ 

+ From 9ef460eb7fd1b1f286955b18db8c18cd1a640e77 Mon Sep 17 00:00:00 2001

+ From: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Date: Tue, 25 Jan 2022 02:08:04 +0530

+ Subject: [PATCH 127/217] libndctl/papr: Add limited support for inject-smart

+ 

+ Implements support for ndctl inject-smart command by providing an

+ implementation of 'smart_inject*' dimm-ops callbacks. Presently only

+ support for injecting unsafe-shutdown and fatal-health states is

+ available.

+ 

+ The patch also introduce various PAPR PDSM structures that are used to

+ communicate the inject-smart errors to the papr_scm kernel

+ module. This is done via SMART_INJECT PDSM which sends a payload of

+ type 'struct nd_papr_pdsm_smart_inject'.

+ 

+ With the patch following output from ndctl inject-smart command is

+ expected for PAPR NVDIMMs:

+ 

+ $ sudo ndctl inject-smart -fU nmem0

+ [

+   {

+     "dev":"nmem0",

+     "flag_failed_flush":true,

+     "flag_smart_event":true,

+     "health":{

+       "health_state":"fatal",

+       "shutdown_state":"dirty",

+       "shutdown_count":0

+     }

+   }

+ ]

+ 

+ $ sudo ndctl inject-smart -N nmem0

+ [

+   {

+     "dev":"nmem0",

+     "health":{

+       "health_state":"ok",

+       "shutdown_state":"clean",

+       "shutdown_count":0

+     }

+   }

+ ]

+ 

+ The patch depends on the kernel PAPR PDSM implementation for

+ PDSM_SMART_INJECT posted at [1].

+ 

+ [1] : https://lore.kernel.org/nvdimm/20220124202204.1488346-1-vaibhav@linux.ibm.com/

+ 

+ Link: https://lore.kernel.org/r/20220124203804.1490254-1-vaibhav@linux.ibm.com

+ Reviewed-by: Ira Weiny <ira.weiny@intel.com>

+ Signed-off-by: Shivaprasad G Bhat <sbhat@linux.ibm.com>

+ Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/papr.c      | 61 +++++++++++++++++++++++++++++++++++++++++++

+  ndctl/lib/papr_pdsm.h | 17 ++++++++++++

+  2 files changed, 78 insertions(+)

+ 

+ diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c

+ index 46cf9c1..7a1d559 100644

+ --- a/ndctl/lib/papr.c

+ +++ b/ndctl/lib/papr.c

+ @@ -221,6 +221,41 @@ static unsigned int papr_smart_get_shutdown_state(struct ndctl_cmd *cmd)

+  	return health.dimm_bad_shutdown;

+  }

+  

+ +static int papr_smart_inject_supported(struct ndctl_dimm *dimm)

+ +{

+ +	if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_CALL))

+ +		return -EOPNOTSUPP;

+ +

+ +	if (!test_dimm_dsm(dimm, PAPR_PDSM_SMART_INJECT))

+ +		return -EIO;

+ +

+ +	return ND_SMART_INJECT_HEALTH_STATE | ND_SMART_INJECT_UNCLEAN_SHUTDOWN;

+ +}

+ +

+ +static int papr_smart_inject_valid(struct ndctl_cmd *cmd)

+ +{

+ +	if (cmd->type != ND_CMD_CALL ||

+ +	    to_pdsm(cmd)->cmd_status != 0 ||

+ +	    to_pdsm_cmd(cmd) != PAPR_PDSM_SMART_INJECT)

+ +		return -EINVAL;

+ +

+ +	return 0;

+ +}

+ +

+ +static struct ndctl_cmd *papr_new_smart_inject(struct ndctl_dimm *dimm)

+ +{

+ +	struct ndctl_cmd *cmd;

+ +

+ +	cmd = allocate_cmd(dimm, PAPR_PDSM_SMART_INJECT,

+ +			sizeof(struct nd_papr_pdsm_smart_inject));

+ +	if (!cmd)

+ +		return NULL;

+ +	/* Set the input payload size */

+ +	to_ndcmd(cmd)->nd_size_in = ND_PDSM_HDR_SIZE +

+ +		sizeof(struct nd_papr_pdsm_smart_inject);

+ +	return cmd;

+ +}

+ +

+  static unsigned int papr_smart_get_life_used(struct ndctl_cmd *cmd)

+  {

+  	struct nd_papr_pdsm_health health;

+ @@ -255,11 +290,37 @@ static unsigned int papr_smart_get_shutdown_count(struct ndctl_cmd *cmd)

+  

+  	return (health.extension_flags & PDSM_DIMM_DSC_VALID) ?

+  		(health.dimm_dsc) : 0;

+ +}

+ +

+ +static int papr_cmd_smart_inject_fatal(struct ndctl_cmd *cmd, bool enable)

+ +{

+ +	if (papr_smart_inject_valid(cmd) < 0)

+ +		return -EINVAL;

+ +

+ +	to_payload(cmd)->inject.flags |= PDSM_SMART_INJECT_HEALTH_FATAL;

+ +	to_payload(cmd)->inject.fatal_enable = enable;

+  

+ +	return 0;

+ +}

+ +

+ +static int papr_cmd_smart_inject_unsafe_shutdown(struct ndctl_cmd *cmd,

+ +						 bool enable)

+ +{

+ +	if (papr_smart_inject_valid(cmd) < 0)

+ +		return -EINVAL;

+ +

+ +	to_payload(cmd)->inject.flags |= PDSM_SMART_INJECT_BAD_SHUTDOWN;

+ +	to_payload(cmd)->inject.unsafe_shutdown_enable = enable;

+ +

+ +	return 0;

+  }

+  

+  struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) {

+  	.cmd_is_supported = papr_cmd_is_supported,

+ +	.new_smart_inject = papr_new_smart_inject,

+ +	.smart_inject_supported = papr_smart_inject_supported,

+ +	.smart_inject_fatal = papr_cmd_smart_inject_fatal,

+ +	.smart_inject_unsafe_shutdown = papr_cmd_smart_inject_unsafe_shutdown,

+  	.smart_get_flags = papr_smart_get_flags,

+  	.get_firmware_status =  papr_get_firmware_status,

+  	.xlat_firmware_status = papr_xlat_firmware_status,

+ diff --git a/ndctl/lib/papr_pdsm.h b/ndctl/lib/papr_pdsm.h

+ index f45b1e4..20ac20f 100644

+ --- a/ndctl/lib/papr_pdsm.h

+ +++ b/ndctl/lib/papr_pdsm.h

+ @@ -121,12 +121,29 @@ struct nd_papr_pdsm_health {

+  enum papr_pdsm {

+  	PAPR_PDSM_MIN = 0x0,

+  	PAPR_PDSM_HEALTH,

+ +	PAPR_PDSM_SMART_INJECT,

+  	PAPR_PDSM_MAX,

+  };

+ +/* Flags for injecting specific smart errors */

+ +#define PDSM_SMART_INJECT_HEALTH_FATAL		(1 << 0)

+ +#define PDSM_SMART_INJECT_BAD_SHUTDOWN		(1 << 1)

+ +

+ +struct nd_papr_pdsm_smart_inject {

+ +	union {

+ +		struct {

+ +			/* One or more of PDSM_SMART_INJECT_ */

+ +			__u32 flags;

+ +			__u8 fatal_enable;

+ +			__u8 unsafe_shutdown_enable;

+ +		};

+ +		__u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];

+ +	};

+ +};

+  

+  /* Maximal union that can hold all possible payload types */

+  union nd_pdsm_payload {

+  	struct nd_papr_pdsm_health health;

+ +	struct nd_papr_pdsm_smart_inject inject;

+  	__u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];

+  } __attribute__((packed));

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,41 @@ 

+ From 6e85cac1958f920f231b94ff570ac0e434595b7d Mon Sep 17 00:00:00 2001

+ From: Shivaprasad G Bhat <sbhat@linux.ibm.com>

+ Date: Tue, 25 Jan 2022 02:34:25 +0530

+ Subject: [PATCH 128/217] ndtest/ack-shutdown-count: Skip the test on ndtest

+ 

+ The PAPR has non-latched dirty shutdown implementation.

+ The test is enabling/disabling the LSS latch which is

+ irrelavent from PAPR pov. Skip the test.

+ 

+ Link: https://lore.kernel.org/r/20220124210425.1493410-1-vaibhav@linux.ibm.com

+ Signed-off-by: Shivaprasad G Bhat <sbhat@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/ack-shutdown-count-set.c | 4 ++++

+  1 file changed, 4 insertions(+)

+ 

+ diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c

+ index a9e95c6..f091a40 100644

+ --- a/test/ack-shutdown-count-set.c

+ +++ b/test/ack-shutdown-count-set.c

+ @@ -117,6 +117,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test,

+  

+  int main(int argc, char *argv[])

+  {

+ +	char *test_env = getenv("NDCTL_TEST_FAMILY");

+  	struct ndctl_test *test = ndctl_test_new(0);

+  	struct ndctl_ctx *ctx;

+  	int rc;

+ @@ -126,6 +127,9 @@ int main(int argc, char *argv[])

+  		return EXIT_FAILURE;

+  	}

+  

+ +	if (test_env && strcmp(test_env, "PAPR") == 0)

+ +		return ndctl_test_result(test, 77);

+ +

+  	rc = ndctl_new(&ctx);

+  	if (rc)

+  		return ndctl_test_result(test, rc);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,218 @@ 

+ From c5ccbf29c54b5a3d9cb1c138c06c8d5ac3ee80c2 Mon Sep 17 00:00:00 2001

+ From: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Date: Tue, 22 Feb 2022 17:45:19 +0530

+ Subject: [PATCH 129/217] ndctl,libndctl: Update nvdimm flags after

+  smart-inject

+ 

+ Presently after performing an inject-smart command the nvdimm flags reported are

+ out of date as shown below where no 'smart_notify' or 'flush_fail' flags were

+ reported even though they are set after injecting the smart error:

+ 

+ $ sudo ndctl inject-smart -fU nmem0

+ [

+   {

+     "dev":"nmem0",

+     "health":{

+       "health_state":"fatal",

+       "shutdown_state":"dirty",

+       "shutdown_count":0

+     }

+   }

+ ]

+ $ sudo cat /sys/class/nd/ndctl0/device/nmem0/papr/flags

+ flush_fail smart_notify

+ 

+ This happens because nvdimm flags are only parsed once during its probe

+ and not refreshed even after a inject-smart operation makes them out of

+ date. To fix this the patch forces an update of nvdimm flags via newly

+ introduced export from libndctl named ndctl_dimm_refresh_flags() thats called

+ from dimm_inject_smart() after inject-smart command is successfully

+ submitted. This ensures that correct nvdimm flags are displayed later in that

+ function. With this implemented correct nvdimm flags are reported after a

+ inject-smart operation:

+ 

+ $ sudo ndctl inject-smart -fU nmem0

+ [

+   {

+     "dev":"nmem0",

+     "flag_failed_flush":true,

+     "flag_smart_event":true,

+     "health":{

+       "health_state":"fatal",

+       "shutdown_state":"dirty",

+       "shutdown_count":0

+     }

+   }

+ ]

+ 

+ The patch refactors populate_dimm_attributes() to move the nvdimm flags

+ parsing code to the newly introduced ndctl_dimm_refresh_flags()

+ export. Since reading nvdimm flags requires constructing path using

+ 'bus_prefix' which is only available during add_dimm(), the patch

+ introduces a new member 'struct ndctl_dimm.bus_prefix' to cache its

+ value. During ndctl_dimm_refresh_flags() the cached bus_prefix is used to

+ read the contents of the nvdimm flag file and pass it on to the appropriate

+ flag parsing function. Finally dimm_inject_smart() is updated to issue call to

+ ndctl_dimm_refresh_flags() before generating json output of the nvdimm status

+ 

+ Link: https://lore.kernel.org/r/20220222121519.1674117-1-vaibhav@linux.ibm.com

+ Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Shivaprasad G Bhat <sbhat@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/inject-smart.c   |  4 +++

+  ndctl/lib/libndctl.c   | 55 +++++++++++++++++++++++++++++++-----------

+  ndctl/lib/libndctl.sym |  4 +++

+  ndctl/lib/private.h    |  1 +

+  ndctl/libndctl.h       |  1 +

+  5 files changed, 51 insertions(+), 14 deletions(-)

+ 

+ diff -up ndctl-71.1/ndctl/inject-smart.c.orig ndctl-71.1/ndctl/inject-smart.c

+ --- ndctl-71.1/ndctl/inject-smart.c.orig	2022-10-07 16:40:24.610615979 -0400

+ +++ ndctl-71.1/ndctl/inject-smart.c	2022-10-07 16:40:35.031651459 -0400

+ @@ -467,6 +467,10 @@ static int dimm_inject_smart(struct ndct

+  		jdimms = json_object_new_array();

+  		if (!jdimms)

+  			goto out;

+ +

+ +		/* Ensure the dimm flags are upto date before reporting them */

+ +		ndctl_dimm_refresh_flags(dimm);

+ +

+  		jdimm = util_dimm_to_json(dimm, sctx.flags);

+  		if (!jdimm)

+  			goto out;

+ diff -up ndctl-71.1/ndctl/lib/libndctl.c.orig ndctl-71.1/ndctl/lib/libndctl.c

+ --- ndctl-71.1/ndctl/lib/libndctl.c.orig	2022-10-07 16:40:24.608615972 -0400

+ +++ ndctl-71.1/ndctl/lib/libndctl.c	2022-10-07 16:40:35.032651462 -0400

+ @@ -588,6 +588,7 @@ static void free_dimm(struct ndctl_dimm

+  	free(dimm->unique_id);

+  	free(dimm->dimm_buf);

+  	free(dimm->dimm_path);

+ +	free(dimm->bus_prefix);

+  	if (dimm->module)

+  		kmod_module_unref(dimm->module);

+  	if (dimm->health_eventfd > -1)

+ @@ -1645,14 +1646,34 @@ static enum ndctl_fwa_result fwa_result_

+  	return NDCTL_FWA_RESULT_INVALID;

+  }

+  

+ +NDCTL_EXPORT void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm)

+ +{

+ +	struct ndctl_ctx *ctx = dimm->bus->ctx;

+ +	char *path = dimm->dimm_buf;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	/* Construct path to dimm flags sysfs file */

+ +	sprintf(path, "%s/%s/flags", dimm->dimm_path, dimm->bus_prefix);

+ +

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		return;

+ +

+ +	/* Reset the flags */

+ +	dimm->flags.flags = 0;

+ +	if (ndctl_bus_has_nfit(dimm->bus))

+ +		parse_nfit_mem_flags(dimm, buf);

+ +	else if (ndctl_bus_is_papr_scm(dimm->bus))

+ +		parse_papr_flags(dimm, buf);

+ +}

+ +

+  static int populate_dimm_attributes(struct ndctl_dimm *dimm,

+ -				    const char *dimm_base,

+ -				    const char *bus_prefix)

+ +				    const char *dimm_base)

+  {

+  	int i, rc = -1;

+  	char buf[SYSFS_ATTR_SIZE];

+  	struct ndctl_ctx *ctx = dimm->bus->ctx;

+  	char *path = calloc(1, strlen(dimm_base) + 100);

+ +	const char *bus_prefix = dimm->bus_prefix;

+  

+  	if (!path)

+  		return -ENOMEM;

+ @@ -1736,16 +1757,10 @@ static int populate_dimm_attributes(stru

+  	}

+  

+  	sprintf(path, "%s/%s/flags", dimm_base, bus_prefix);

+ -	if (sysfs_read_attr(ctx, path, buf) == 0) {

+ -		if (ndctl_bus_has_nfit(dimm->bus))

+ -			parse_nfit_mem_flags(dimm, buf);

+ -		else if (ndctl_bus_is_papr_scm(dimm->bus)) {

+ -			dimm->cmd_family = NVDIMM_FAMILY_PAPR;

+ -			parse_papr_flags(dimm, buf);

+ -		}

+ -	}

+ -

+  	dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);

+ +

+ +	ndctl_dimm_refresh_flags(dimm);

+ +

+  	rc = 0;

+   err_read:

+  

+ @@ -1801,8 +1816,9 @@ static int add_papr_dimm(struct ndctl_di

+  

+  		rc = 0;

+  	} else if (strcmp(buf, "nvdimm_test") == 0) {

+ +		dimm->cmd_family = NVDIMM_FAMILY_PAPR;

+  		/* probe via common populate_dimm_attributes() */

+ -		rc = populate_dimm_attributes(dimm, dimm_base, "papr");

+ +		rc = populate_dimm_attributes(dimm, dimm_base);

+  	}

+  out:

+  	free(path);

+ @@ -1899,9 +1915,20 @@ static void *add_dimm(void *parent, int

+  	dimm->formats = formats;

+  	/* Check if the given dimm supports nfit */

+  	if (ndctl_bus_has_nfit(bus)) {

+ -		rc = populate_dimm_attributes(dimm, dimm_base, "nfit");

+ +		dimm->bus_prefix = strdup("nfit");

+ +		if (!dimm->bus_prefix) {

+ +			rc = -ENOMEM;

+ +			goto out;

+ +		}

+ +		rc =  populate_dimm_attributes(dimm, dimm_base);

+ +

+  	} else if (ndctl_bus_has_of_node(bus)) {

+ -		rc = add_papr_dimm(dimm, dimm_base);

+ +		dimm->bus_prefix = strdup("papr");

+ +		if (!dimm->bus_prefix) {

+ +			rc = -ENOMEM;

+ +			goto out;

+ +		}

+ +		rc =  add_papr_dimm(dimm, dimm_base);

+  	}

+  

+  	if (rc == -ENODEV) {

+ diff -up ndctl-71.1/ndctl/lib/libndctl.sym.orig ndctl-71.1/ndctl/lib/libndctl.sym

+ --- ndctl-71.1/ndctl/lib/libndctl.sym.orig	2022-10-07 16:40:24.344615073 -0400

+ +++ ndctl-71.1/ndctl/lib/libndctl.sym	2022-10-07 16:40:35.032651462 -0400

+ @@ -456,3 +456,7 @@ LIBNDCTL_26 {

+  	ndctl_bus_nfit_translate_spa;

+  	ndctl_dimm_sizeof_namespace_index;

+  } LIBNDCTL_25;

+ +

+ +LIBNDCTL_27 {

+ +	ndctl_dimm_refresh_flags;

+ +} LIBNDCTL_26;

+ diff -up ndctl-71.1/ndctl/lib/private.h.orig ndctl-71.1/ndctl/lib/private.h

+ --- ndctl-71.1/ndctl/lib/private.h.orig	2022-10-07 16:40:24.455615451 -0400

+ +++ ndctl-71.1/ndctl/lib/private.h	2022-10-07 16:40:35.032651462 -0400

+ @@ -75,6 +75,7 @@ struct ndctl_dimm {

+  	char *unique_id;

+  	char *dimm_path;

+  	char *dimm_buf;

+ +	char *bus_prefix;

+  	int health_eventfd;

+  	int buf_len;

+  	int id;

+ diff -up ndctl-71.1/ndctl/libndctl.h.orig ndctl-71.1/ndctl/libndctl.h

+ --- ndctl-71.1/ndctl/libndctl.h.orig	2022-10-07 16:40:24.611615982 -0400

+ +++ ndctl-71.1/ndctl/libndctl.h	2022-10-07 16:40:35.033651466 -0400

+ @@ -221,6 +221,7 @@ int ndctl_dimm_is_active(struct ndctl_di

+  int ndctl_dimm_is_enabled(struct ndctl_dimm *dimm);

+  int ndctl_dimm_disable(struct ndctl_dimm *dimm);

+  int ndctl_dimm_enable(struct ndctl_dimm *dimm);

+ +void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm);

+  

+  struct ndctl_cmd;

+  struct ndctl_cmd *ndctl_bus_cmd_new_ars_cap(struct ndctl_bus *bus,

@@ -0,0 +1,202 @@ 

+ From 4f588b964dccf72030b1c432ed5dd8e2856f9d38 Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Tue, 22 Feb 2022 11:56:03 -0800

+ Subject: [PATCH 132/217] libcxl: add GET_PARTITION_INFO mailbox command and

+  accessors

+ 

+ The CXL PMEM provisioning model depends upon the values reported

+ in the CXL GET_PARTITION_INFO mailbox command when changing the

+ partitioning between volatile and persistent capacity.

+ 

+ Add libcxl APIs to create a new GET_PARTITION_INFO mailbox command,

+ the command output data structure (privately), and accessor APIs to

+ return the fields in the partition info output.

+ 

+ Per the CXL 2.0 specification, devices report partition capacities

+ as multiples of 256MB. Define and use a capacity multiplier to

+ convert the raw data into bytes for user consumption. Use byte

+ format as the norm for all capacity values produced or consumed

+ using CXL Mailbox commands.

+ 

+ Link: https://lore.kernel.org/r/6cd7fffe1a95c9a1bc2239cb342067df564401a5.1645558189.git.alison.schofield@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  1 +

+  cxl/lib/libcxl.c                 | 66 ++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |  5 +++

+  cxl/lib/private.h                | 10 +++++

+  cxl/libcxl.h                     |  5 +++

+  util/size.h                      |  1 +

+  6 files changed, 88 insertions(+)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 4392b47..a6986ab 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -131,6 +131,7 @@ int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length,

+  			  size_t offset);

+  int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,

+  			   size_t offset);

+ +struct cxl_cmd *cxl_cmd_new_get_partition(struct cxl_memdev *memdev);

+  

+  ----

+  

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index e0b443f..4557a71 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1985,6 +1985,11 @@ static int cxl_cmd_validate_status(struct cxl_cmd *cmd, u32 id)

+  	return 0;

+  }

+  

+ +static uint64_t cxl_capacity_to_bytes(leint64_t size)

+ +{

+ +	return le64_to_cpu(size) * CXL_CAPACITY_MULTIPLIER;

+ +}

+ +

+  /* Helpers for health_info fields (no endian conversion) */

+  #define cmd_get_field_u8(cmd, n, N, field)				\

+  do {									\

+ @@ -2371,6 +2376,67 @@ CXL_EXPORT ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd,

+  	return length;

+  }

+  

+ +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_partition(struct cxl_memdev *memdev)

+ +{

+ +	return cxl_cmd_new_generic(memdev,

+ +				   CXL_MEM_COMMAND_ID_GET_PARTITION_INFO);

+ +}

+ +

+ +static struct cxl_cmd_get_partition *

+ +cmd_to_get_partition(struct cxl_cmd *cmd)

+ +{

+ +	if (cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_GET_PARTITION_INFO))

+ +		return NULL;

+ +

+ +	if (!cmd)

+ +		return NULL;

+ +	return cmd->output_payload;

+ +}

+ +

+ +CXL_EXPORT unsigned long long

+ +cxl_cmd_partition_get_active_volatile_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_get_partition *c;

+ +

+ +	c = cmd_to_get_partition(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->active_volatile);

+ +}

+ +

+ +CXL_EXPORT unsigned long long

+ +cxl_cmd_partition_get_active_persistent_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_get_partition *c;

+ +

+ +	c = cmd_to_get_partition(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->active_persistent);

+ +}

+ +

+ +CXL_EXPORT unsigned long long

+ +cxl_cmd_partition_get_next_volatile_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_get_partition *c;

+ +

+ +	c = cmd_to_get_partition(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->next_volatile);

+ +}

+ +

+ +CXL_EXPORT unsigned long long

+ +cxl_cmd_partition_get_next_persistent_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_get_partition *c;

+ +

+ +	c = cmd_to_get_partition(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->next_persistent);

+ +}

+ +

+  CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)

+  {

+  	struct cxl_memdev *memdev = cmd->memdev;

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index e56a2bf..509e62d 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -155,4 +155,9 @@ global:

+  	cxl_dport_get_port;

+  	cxl_port_get_dport_by_memdev;

+  	cxl_dport_maps_memdev;

+ +	cxl_cmd_new_get_partition;

+ +	cxl_cmd_partition_get_active_volatile_size;

+ +	cxl_cmd_partition_get_active_persistent_size;

+ +	cxl_cmd_partition_get_next_volatile_size;

+ +	cxl_cmd_partition_get_next_persistent_size;

+  } LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index f483c30..7f3a562 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -7,6 +7,7 @@

+  #include <cxl/cxl_mem.h>

+  #include <ccan/endian/endian.h>

+  #include <ccan/short_types/short_types.h>

+ +#include <util/size.h>

+  

+  #define CXL_EXPORT __attribute__ ((visibility("default")))

+  

+ @@ -185,6 +186,15 @@ struct cxl_cmd_get_health_info {

+  	le32 pmem_errors;

+  } __attribute__((packed));

+  

+ +struct cxl_cmd_get_partition {

+ +	le64 active_volatile;

+ +	le64 active_persistent;

+ +	le64 next_volatile;

+ +	le64 next_persistent;

+ +} __attribute__((packed));

+ +

+ +#define CXL_CAPACITY_MULTIPLIER		SZ_256M

+ +

+  /* CXL 2.0 8.2.9.5.3 Byte 0 Health Status */

+  #define CXL_CMD_HEALTH_INFO_STATUS_MAINTENANCE_NEEDED_MASK		BIT(0)

+  #define CXL_CMD_HEALTH_INFO_STATUS_PERFORMANCE_DEGRADED_MASK		BIT(1)

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 3b2293b..2c0a8d1 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -242,6 +242,11 @@ ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd, void *buf,

+  		unsigned int length);

+  struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev,

+  		void *buf, unsigned int offset, unsigned int length);

+ +struct cxl_cmd *cxl_cmd_new_get_partition(struct cxl_memdev *memdev);

+ +unsigned long long cxl_cmd_partition_get_active_volatile_size(struct cxl_cmd *cmd);

+ +unsigned long long cxl_cmd_partition_get_active_persistent_size(struct cxl_cmd *cmd);

+ +unsigned long long cxl_cmd_partition_get_next_volatile_size(struct cxl_cmd *cmd);

+ +unsigned long long cxl_cmd_partition_get_next_persistent_size(struct cxl_cmd *cmd);

+  

+  #ifdef __cplusplus

+  } /* extern "C" */

+ diff --git a/util/size.h b/util/size.h

+ index a0f3593..e72467f 100644

+ --- a/util/size.h

+ +++ b/util/size.h

+ @@ -15,6 +15,7 @@

+  #define SZ_4M     0x00400000

+  #define SZ_16M    0x01000000

+  #define SZ_64M    0x04000000

+ +#define SZ_256M	  0x10000000

+  #define SZ_1G     0x40000000

+  #define SZ_1T 0x10000000000ULL

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,118 @@ 

+ From 50b9d77232d41a33c2109894ae93ddad877c1747 Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Tue, 22 Feb 2022 11:56:04 -0800

+ Subject: [PATCH 133/217] libcxl: add accessors for capacity fields of the

+  IDENTIFY command

+ 

+ The CXL PMEM provisioning model depends upon the values reported

+ in the CXL IDENTIFY mailbox command when changing the partitioning

+ between volatile and persistent capacity.

+ 

+ Add accessors to the libcxl API to retrieve the total, volatile only,

+ and persistent only capacities from the IDENTIFY command.

+ 

+ The fields are specified in multiples of 256MB per the CXL 2.0 spec.

+ Use the capacity multiplier to convert the raw data into bytes for user

+ consumption.

+ 

+ Link: https://lore.kernel.org/r/58dec40b15a68f134466f61421751994735e55c1.1645558189.git.alison.schofield@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c   | 44 ++++++++++++++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym |  3 +++

+  cxl/libcxl.h       |  3 +++

+  3 files changed, 50 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 4557a71..9413384 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -2277,6 +2277,17 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)

+  	return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);

+  }

+  

+ +static struct cxl_cmd_identify *

+ +cmd_to_identify(struct cxl_cmd *cmd)

+ +{

+ +	if (cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_IDENTIFY))

+ +		return NULL;

+ +

+ +	if (!cmd)

+ +		return NULL;

+ +	return cmd->output_payload;

+ +}

+ +

+  CXL_EXPORT int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev,

+  		int fw_len)

+  {

+ @@ -2321,6 +2332,39 @@ CXL_EXPORT unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd)

+  	return le32_to_cpu(id->lsa_size);

+  }

+  

+ +CXL_EXPORT unsigned long long

+ +cxl_cmd_identify_get_total_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_identify *c;

+ +

+ +	c = cmd_to_identify(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->total_capacity);

+ +}

+ +

+ +CXL_EXPORT unsigned long long

+ +cxl_cmd_identify_get_volatile_only_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_identify *c;

+ +

+ +	c = cmd_to_identify(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->volatile_capacity);

+ +}

+ +

+ +CXL_EXPORT unsigned long long

+ +cxl_cmd_identify_get_persistent_only_size(struct cxl_cmd *cmd)

+ +{

+ +	struct cxl_cmd_identify *c;

+ +

+ +	c = cmd_to_identify(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->persistent_capacity);

+ +}

+ +

+  CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,

+  		int opcode)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 509e62d..5ac6e9b 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -160,4 +160,7 @@ global:

+  	cxl_cmd_partition_get_active_persistent_size;

+  	cxl_cmd_partition_get_next_volatile_size;

+  	cxl_cmd_partition_get_next_persistent_size;

+ +	cxl_cmd_identify_get_total_size;

+ +	cxl_cmd_identify_get_volatile_only_size;

+ +	cxl_cmd_identify_get_persistent_only_size;

+  } LIBCXL_1;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 2c0a8d1..6e18e84 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -201,6 +201,9 @@ int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);

+  int cxl_cmd_get_out_size(struct cxl_cmd *cmd);

+  struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);

+  int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);

+ +unsigned long long cxl_cmd_identify_get_total_size(struct cxl_cmd *cmd);

+ +unsigned long long cxl_cmd_identify_get_volatile_only_size(struct cxl_cmd *cmd);

+ +unsigned long long cxl_cmd_identify_get_persistent_only_size(struct cxl_cmd *cmd);

+  unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);

+  unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd);

+  struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,53 @@ 

+ From ac0066a6095e9ed0910fc560277ec693d3b507fa Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Tue, 22 Feb 2022 11:56:05 -0800

+ Subject: [PATCH 134/217] libcxl: return the partition alignment field in bytes

+ 

+ Per the CXL specification, the partition alignment field reports

+ the alignment value in multiples of 256MB. In the libcxl API, values

+ for all capacity fields are defined to return bytes.

+ 

+ Update the partition alignment accessor to return bytes so that it

+ is in sync with other capacity related fields.

+ 

+ Since this is early in the development cycle, the expectation is that

+ no third party consumers of this library have come to depend on the

+ encoded capacity field. If that is not the case, the original format

+ can be restored, and a new _bytes version introduced.

+ 

+ Link: https://lore.kernel.org/r/6b937b09b61ddf95e069fd7acfda0c5bbb845be8.1645558189.git.alison.schofield@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 13 +++++--------

+  1 file changed, 5 insertions(+), 8 deletions(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 9413384..c05c13c 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -2308,15 +2308,12 @@ CXL_EXPORT int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev,

+  CXL_EXPORT unsigned long long cxl_cmd_identify_get_partition_align(

+  		struct cxl_cmd *cmd)

+  {

+ -	struct cxl_cmd_identify *id =

+ -			(struct cxl_cmd_identify *)cmd->send_cmd->out.payload;

+ -

+ -	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)

+ -		return -EINVAL;

+ -	if (cmd->status < 0)

+ -		return cmd->status;

+ +	struct cxl_cmd_identify *c;

+  

+ -	return le64_to_cpu(id->partition_align);

+ +	c = cmd_to_identify(cmd);

+ +	if (!c)

+ +		return ULLONG_MAX;

+ +	return cxl_capacity_to_bytes(c->partition_align);

+  }

+  

+  CXL_EXPORT unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,267 @@ 

+ From 033b94ad7346a82504cffba3d87650b60945c1eb Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Tue, 22 Feb 2022 11:56:06 -0800

+ Subject: [PATCH 135/217] cxl: add memdev partition information to cxl-list

+ 

+ The CXL PMEM provisioning model depends upon the values reported in

+ both the CXL IDENTIFY and GET_PARTITION_INFO mailbox commands when

+ changing the partitioning between volatile and persistent capacity.

+ 

+ Add an option to the 'cxl list' command to display partition information.

+ 

+ Include the partitioning related fields from the IDENTIFY command:

+ total, volatile_only, persistent_only, and partition_alignment sizes.

+ When the partition_alignment size is greater than zero, indicating

+ partitionable capacity, include the active and next size fields of

+ GET_PARTITION_INFO.

+ 

+ Example:

+     "partition_info":{

+       "total_size":273535729664,

+       "volatile_only_size":0,

+       "persistent_only_size":0,

+       "partition_alignment_size":268435456

+       "active_volatile_size":273535729664,

+       "active_persistent_size":0,

+       "next_volatile_size":0,

+       "next_persistent_size":0,

+     }

+ 

+ Link: https://lore.kernel.org/r/70cc57379d2c49692036b1daa158a122aa19c126.1645558189.git.alison.schofield@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt |  23 +++++++

+  cxl/filter.c                   |   2 +

+  cxl/filter.h                   |   1 +

+  cxl/json.c                     | 120 +++++++++++++++++++++++++++++++++

+  cxl/list.c                     |   2 +

+  util/json.h                    |   1 +

+  6 files changed, 149 insertions(+)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 90e6d9f..f6aba0c 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -196,6 +196,29 @@ OPTIONS

+    }

+  ]

+  ----

+ +-I::

+ +--partition::

+ +	Include partition information in the memdev listing. Example listing:

+ +----

+ +# cxl list -m mem0 -I

+ +[

+ +  {

+ +    "memdev":"mem0",

+ +    "pmem_size":0,

+ +    "ram_size":273535729664,

+ +    "partition_info":{

+ +      "total_size":273535729664,

+ +      "volatile_only_size":0,

+ +      "persistent_only_size":0,

+ +      "partition_alignment_size":268435456

+ +      "active_volatile_size":273535729664,

+ +      "active_persistent_size":0,

+ +      "next_volatile_size":0,

+ +      "next_persistent_size":0,

+ +    }

+ +  }

+ +]

+ +----

+  

+  -B::

+  --buses::

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 925bf3a..b339642 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -581,6 +581,8 @@ static unsigned long params_to_flags(struct cxl_filter_params *param)

+  		flags |= UTIL_JSON_HEALTH;

+  	if (param->targets)

+  		flags |= UTIL_JSON_TARGETS;

+ +	if (param->partition)

+ +		flags |= UTIL_JSON_PARTITION;

+  	return flags;

+  }

+  

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 5deabb3..697b777 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -23,6 +23,7 @@ struct cxl_filter_params {

+  	bool idle;

+  	bool human;

+  	bool health;

+ +	bool partition;

+  	struct log_ctx ctx;

+  };

+  

+ diff --git a/cxl/json.c b/cxl/json.c

+ index f3b536e..fdc6f73 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -185,6 +185,121 @@ err_jobj:

+  	return NULL;

+  }

+  

+ +/*

+ + * Present complete view of memdev partition by presenting fields from

+ + * both GET_PARTITION_INFO and IDENTIFY mailbox commands.

+ + */

+ +static struct json_object *util_cxl_memdev_partition_to_json(struct cxl_memdev *memdev,

+ +		unsigned long flags)

+ +{

+ +	struct json_object *jobj = NULL;

+ +	struct json_object *jpart;

+ +	unsigned long long cap;

+ +	struct cxl_cmd *cmd;

+ +	int rc;

+ +

+ +	jpart = json_object_new_object();

+ +	if (!jpart)

+ +		return NULL;

+ +	if (!memdev)

+ +		goto err_jobj;

+ +

+ +	/* Retrieve partition info in the IDENTIFY mbox cmd */

+ +	cmd = cxl_cmd_new_identify(memdev);

+ +	if (!cmd)

+ +		goto err_jobj;

+ +

+ +	rc = cxl_cmd_submit(cmd);

+ +	if (rc < 0)

+ +		goto err_identify;

+ +	rc = cxl_cmd_get_mbox_status(cmd);

+ +	if (rc != 0)

+ +		goto err_identify;

+ +

+ +	cap = cxl_cmd_identify_get_total_size(cmd);

+ +	if (cap != ULLONG_MAX) {

+ +		jobj = util_json_object_size(cap, flags);

+ +		if (jobj)

+ +			json_object_object_add(jpart, "total_size", jobj);

+ +	}

+ +	cap = cxl_cmd_identify_get_volatile_only_size(cmd);

+ +	if (cap != ULLONG_MAX) {

+ +		jobj = util_json_object_size(cap, flags);

+ +		if (jobj)

+ +			json_object_object_add(jpart,

+ +					"volatile_only_size", jobj);

+ +	}

+ +	cap = cxl_cmd_identify_get_persistent_only_size(cmd);

+ +	if (cap != ULLONG_MAX) {

+ +		jobj = util_json_object_size(cap, flags);

+ +		if (jobj)

+ +			json_object_object_add(jpart,

+ +					"persistent_only_size", jobj);

+ +	}

+ +	cap = cxl_cmd_identify_get_partition_align(cmd);

+ +	jobj = util_json_object_size(cap, flags);

+ +	if (jobj)

+ +		json_object_object_add(jpart, "partition_alignment_size", jobj);

+ +

+ +	cxl_cmd_unref(cmd);

+ +

+ +	/* Return now if there is no partition info to get. */

+ +	if (!cap)

+ +		return jpart;

+ +

+ +	/* Retrieve partition info in GET_PARTITION_INFO mbox cmd */

+ +	cmd = cxl_cmd_new_get_partition(memdev);

+ +	if (!cmd)

+ +		return jpart;

+ +

+ +	rc = cxl_cmd_submit(cmd);

+ +	if (rc < 0)

+ +		goto err_get;

+ +	rc = cxl_cmd_get_mbox_status(cmd);

+ +	if (rc != 0)

+ +		goto err_get;

+ +

+ +	cap = cxl_cmd_partition_get_active_volatile_size(cmd);

+ +	if (cap != ULLONG_MAX) {

+ +		jobj = util_json_object_size(cap, flags);

+ +		if (jobj)

+ +			json_object_object_add(jpart,

+ +					"active_volatile_size", jobj);

+ +	}

+ +	cap = cxl_cmd_partition_get_active_persistent_size(cmd);

+ +	if (cap != ULLONG_MAX) {

+ +		jobj = util_json_object_size(cap, flags);

+ +		if (jobj)

+ +			json_object_object_add(jpart,

+ +					"active_persistent_size", jobj);

+ +	}

+ +	cap = cxl_cmd_partition_get_next_volatile_size(cmd);

+ +	if (cap != ULLONG_MAX) {

+ +		jobj = util_json_object_size(cap, flags);

+ +		if (jobj)

+ +			json_object_object_add(jpart,

+ +					"next_volatile_size", jobj);

+ +	}

+ +	cap = cxl_cmd_partition_get_next_persistent_size(cmd);

+ +	if (cap != ULLONG_MAX) {

+ +		jobj = util_json_object_size(cap, flags);

+ +		if (jobj)

+ +			json_object_object_add(jpart,

+ +					"next_persistent_size", jobj);

+ +	}

+ +

+ +err_get:

+ +	cxl_cmd_unref(cmd);

+ +	return jpart;

+ +

+ +err_identify:

+ +	cxl_cmd_unref(cmd);

+ +

+ +err_jobj:

+ +	json_object_put(jpart);

+ +	return NULL;

+ +}

+ +

+  struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  		unsigned long flags)

+  {

+ @@ -239,6 +354,11 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,

+  			json_object_object_add(jdev, "state", jobj);

+  	}

+  

+ +	if (flags & UTIL_JSON_PARTITION) {

+ +		jobj = util_cxl_memdev_partition_to_json(memdev, flags);

+ +		if (jobj)

+ +			json_object_object_add(jdev, "partition_info", jobj);

+ +	}

+  	return jdev;

+  }

+  

+ diff --git a/cxl/list.c b/cxl/list.c

+ index de96ff9..1e9d441 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -48,6 +48,8 @@ static const struct option options[] = {

+  		    "use human friendly number formats "),

+  	OPT_BOOLEAN('H', "health", &param.health,

+  		    "include memory device health information "),

+ +	OPT_BOOLEAN('I', "partition", &param.partition,

+ +		    "include memory device partition information "),

+  #ifdef ENABLE_DEBUG

+  	OPT_BOOLEAN(0, "debug", &debug, "debug list walk"),

+  #endif

+ diff --git a/util/json.h b/util/json.h

+ index e026df1..73bb9f0 100644

+ --- a/util/json.h

+ +++ b/util/json.h

+ @@ -19,6 +19,7 @@ enum util_json_flags {

+  	UTIL_JSON_DAX_MAPPINGS	= (1 << 9),

+  	UTIL_JSON_HEALTH	= (1 << 10),

+  	UTIL_JSON_TARGETS	= (1 << 11),

+ +	UTIL_JSON_PARTITION	= (1 << 12),

+  };

+  

+  void util_display_json_array(FILE *f_out, struct json_object *jarray,

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,154 @@ 

+ From b424b4bfd555654fc41996e964bdd0495f585793 Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Tue, 22 Feb 2022 11:56:07 -0800

+ Subject: [PATCH 136/217] libcxl: add interfaces for SET_PARTITION_INFO mailbox

+  command

+ 

+ The CXL PMEM provisioning model depends upon the CXL mailbox command

+ SET_PARTITION_INFO to change a device's partitioning between volatile

+ and persistent capacity.

+ 

+ Add interfaces to libcxl to allocate and send a SET_PARTITION_INFO

+ mailbox command as defined in the CXL 2.0 specification.

+ 

+ Link: https://lore.kernel.org/r/978c1cf78f3dd22f6070e51a241bc63cac9297de.1645558189.git.alison.schofield@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt | 11 +++++++++++

+  cxl/lib/libcxl.c                 | 28 ++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |  2 ++

+  cxl/lib/private.h                |  8 ++++++++

+  cxl/libcxl.h                     | 10 ++++++++++

+  5 files changed, 59 insertions(+)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index a6986ab..7b223cb 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -132,6 +132,8 @@ int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length,

+  int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,

+  			   size_t offset);

+  struct cxl_cmd *cxl_cmd_new_get_partition(struct cxl_memdev *memdev);

+ +struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,

+ +					  unsigned long long volatile_size);

+  

+  ----

+  

+ @@ -148,6 +150,8 @@ this sub-class of interfaces, there are:

+     a CXL standard opcode. See the potential command ids in

+     /usr/include/linux/cxl_mem.h.

+  

+ + * 'cxl_cmd_<name>_set_<field>' interfaces that set specific fields in a cxl_cmd

+ +

+   * 'cxl_cmd_submit' which submits the command via ioctl()

+  

+   * 'cxl_cmd_<name>_get_<field>' interfaces that get specific fields out of the

+ @@ -167,6 +171,13 @@ cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple

+  label access commands over an arbitrary extent of the device's label

+  area.

+  

+ +cxl_cmd_partition_set_mode() supports selecting NEXTBOOT or IMMEDIATE

+ +mode. When CXL_SETPART_IMMEDIATE mode is set, it is the caller’s

+ +responsibility to avoid immediate changes to partitioning when the

+ +device is in use. When CXL_SETPART_NEXTBOOT mode is set, the change

+ +in partitioning shall become the “next” configuration, to become

+ +active on the next device reset.

+ +

+  BUSES

+  -----

+  The CXL Memory space is CPU and Device coherent. The address ranges that

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index c05c13c..daa2bbc 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -2478,6 +2478,34 @@ cxl_cmd_partition_get_next_persistent_size(struct cxl_cmd *cmd)

+  	return cxl_capacity_to_bytes(c->next_persistent);

+  }

+  

+ +CXL_EXPORT int cxl_cmd_partition_set_mode(struct cxl_cmd *cmd,

+ +		enum cxl_setpartition_mode mode)

+ +{

+ +	struct cxl_cmd_set_partition *setpart = cmd->input_payload;

+ +

+ +	if (mode == CXL_SETPART_IMMEDIATE)

+ +		setpart->flags = CXL_CMD_SET_PARTITION_FLAG_IMMEDIATE;

+ +	else

+ +		setpart->flags = !CXL_CMD_SET_PARTITION_FLAG_IMMEDIATE;

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,

+ +		unsigned long long volatile_size)

+ +{

+ +	struct cxl_cmd_set_partition *setpart;

+ +	struct cxl_cmd *cmd;

+ +

+ +	cmd = cxl_cmd_new_generic(memdev,

+ +			CXL_MEM_COMMAND_ID_SET_PARTITION_INFO);

+ +

+ +	setpart = cmd->input_payload;

+ +	setpart->volatile_size = cpu_to_le64(volatile_size)

+ +					/ CXL_CAPACITY_MULTIPLIER;

+ +	return cmd;

+ +}

+ +

+  CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)

+  {

+  	struct cxl_memdev *memdev = cmd->memdev;

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 5ac6e9b..aab1112 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -163,4 +163,6 @@ global:

+  	cxl_cmd_identify_get_total_size;

+  	cxl_cmd_identify_get_volatile_only_size;

+  	cxl_cmd_identify_get_persistent_only_size;

+ +	cxl_cmd_new_set_partition;

+ +	cxl_cmd_partition_set_mode;

+  } LIBCXL_1;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 7f3a562..c6d88f7 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -195,6 +195,14 @@ struct cxl_cmd_get_partition {

+  

+  #define CXL_CAPACITY_MULTIPLIER		SZ_256M

+  

+ +struct cxl_cmd_set_partition {

+ +	le64 volatile_size;

+ +	u8 flags;

+ +} __attribute__((packed));

+ +

+ +/* CXL 2.0 8.2.9.5.2 Set Partition Info */

+ +#define CXL_CMD_SET_PARTITION_FLAG_IMMEDIATE				BIT(0)

+ +

+  /* CXL 2.0 8.2.9.5.3 Byte 0 Health Status */

+  #define CXL_CMD_HEALTH_INFO_STATUS_MAINTENANCE_NEEDED_MASK		BIT(0)

+  #define CXL_CMD_HEALTH_INFO_STATUS_PERFORMANCE_DEGRADED_MASK		BIT(1)

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 6e18e84..0063d31 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -250,6 +250,16 @@ unsigned long long cxl_cmd_partition_get_active_volatile_size(struct cxl_cmd *cm

+  unsigned long long cxl_cmd_partition_get_active_persistent_size(struct cxl_cmd *cmd);

+  unsigned long long cxl_cmd_partition_get_next_volatile_size(struct cxl_cmd *cmd);

+  unsigned long long cxl_cmd_partition_get_next_persistent_size(struct cxl_cmd *cmd);

+ +struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,

+ +		unsigned long long volatile_size);

+ +

+ +enum cxl_setpartition_mode {

+ +	CXL_SETPART_NEXTBOOT,

+ +	CXL_SETPART_IMMEDIATE,

+ +};

+ +

+ +int cxl_cmd_partition_set_mode(struct cxl_cmd *cmd,

+ +		enum cxl_setpartition_mode mode);

+  

+  #ifdef __cplusplus

+  } /* extern "C" */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,400 @@ 

+ From e2d5cbab4a4b530b679172ae7ca59cc506d1d4cc Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Tue, 22 Feb 2022 11:56:08 -0800

+ Subject: [PATCH 137/217] cxl: add command 'cxl set-partition'

+ 

+ CXL devices may support both volatile and persistent memory capacity.

+ The amount of device capacity set aside for each type is typically

+ established at the factory, but some devices also allow for dynamic

+ re-partitioning. Add a command for this purpose.

+ 

+  usage: cxl set-partition <mem0> [<mem1>..<memN>] [<options>]

+ 

+     -v, --verbose         turn on debug

+     -S, --serial          use serial numbers to id memdevs

+     -t, --type <type>     'pmem' or 'volatile' (Default: 'pmem')

+     -s, --size <size>     size in bytes (Default: all available capacity)

+     -a, --align           auto-align --size per device's requirement

+ 

+ Link: https://lore.kernel.org/r/e7accc7ba93def81b48304cf5fb483345757410d.1645558189.git.alison.schofield@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-set-partition.txt |  68 ++++++++

+  Documentation/cxl/meson.build           |   1 +

+  cxl/builtin.h                           |   1 +

+  cxl/cxl.c                               |   1 +

+  cxl/memdev.c                            | 206 ++++++++++++++++++++++++

+  5 files changed, 277 insertions(+)

+  create mode 100644 Documentation/cxl/cxl-set-partition.txt

+ 

+ diff --git a/Documentation/cxl/cxl-set-partition.txt b/Documentation/cxl/cxl-set-partition.txt

+ new file mode 100644

+ index 0000000..1e548af

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-set-partition.txt

+ @@ -0,0 +1,68 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-set-partition(1)

+ +====================

+ +

+ +NAME

+ +----

+ +cxl-set-partition - set the partitioning between volatile and persistent capacity on a CXL memdev

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl set-partition <mem0> [ [<mem1>..<memN>] [<options>]'

+ +

+ +DESCRIPTION

+ +-----------

+ +CXL devices may support both volatile and persistent memory capacity.

+ +The amount of device capacity set aside for each type is typically

+ +established at the factory, but some devices also allow for dynamic

+ +re-partitioning.

+ +

+ +Use this command to partition a device into volatile and persistent

+ +capacity. The change in partitioning becomes the “next” configuration,

+ +to become active on the next device reset.

+ +

+ +Use "cxl list -m <memdev> -I" to examine the partitioning capabilities

+ +of a device. A partition_alignment_size value of zero means there is

+ +no available capacity and therefore the partitions cannot be changed.

+ +

+ +Using this command to change the size of the persistent capacity shall

+ +result in the loss of data stored.

+ +

+ +OPTIONS

+ +-------

+ +<memory device(s)>::

+ +include::memdev-option.txt[]

+ +

+ +-t::

+ +--type=::

+ +	Type of partition, 'pmem' or 'volatile', to modify.

+ +	Default: 'pmem'

+ +

+ +-s::

+ +--size=::

+ +	Size of the <type> partition in bytes. Size must align to the

+ +	devices alignment requirement. Use 'cxl list -m <memdev> -I'

+ +	to find 'partition_alignment_size', or, use the --align option.

+ +	Default: All available capacity is assigned to <type>.

+ +

+ +-a::

+ +--align::

+ +	Select this option to allow the automatic alignment of --size

+ +	to meet device alignment requirements. When using this option,

+ +	specify the minimum --size of the --type partition needed. When

+ +	this option is omitted, the command fails if --size is not

+ +	properly aligned. Use 'cxl list -m <memdev> -I' to examine the

+ +	partition_alignment_size.

+ +

+ +-v::

+ +        Turn on verbose debug messages in the library (if libcxl was built with

+ +        logging and debug enabled).

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-list[1],

+ +CXL-2.0 8.2.9.5.2

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index 96f4666..e927644 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -34,6 +34,7 @@ cxl_manpages = [

+    'cxl-disable-memdev.txt',

+    'cxl-enable-port.txt',

+    'cxl-disable-port.txt',

+ +  'cxl-set-partition.txt',

+  ]

+  

+  foreach man : cxl_manpages

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index 3123d5e..7bbad98 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -14,4 +14,5 @@ int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx);

+  #endif /* _CXL_BUILTIN_H_ */

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index c20c569..ab4bbec 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -68,6 +68,7 @@ static struct cmd_struct commands[] = {

+  	{ "enable-memdev", .c_fn = cmd_enable_memdev },

+  	{ "disable-port", .c_fn = cmd_disable_port },

+  	{ "enable-port", .c_fn = cmd_enable_port },

+ +	{ "set-partition", .c_fn = cmd_set_partition },

+  };

+  

+  int main(int argc, const char **argv)

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index 90b33e1..91d914d 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -6,11 +6,14 @@

+  #include <unistd.h>

+  #include <limits.h>

+  #include <util/log.h>

+ +#include <util/json.h>

+ +#include <util/size.h>

+  #include <cxl/libcxl.h>

+  #include <util/parse-options.h>

+  #include <ccan/minmax/minmax.h>

+  #include <ccan/array_size/array_size.h>

+  

+ +#include "json.h"

+  #include "filter.h"

+  

+  struct action_context {

+ @@ -26,10 +29,18 @@ static struct parameters {

+  	bool verbose;

+  	bool serial;

+  	bool force;

+ +	bool align;

+ +	const char *type;

+ +	const char *size;

+  } param;

+  

+  static struct log_ctx ml;

+  

+ +enum cxl_setpart_type {

+ +	CXL_SETPART_PMEM,

+ +	CXL_SETPART_VOLATILE,

+ +};

+ +

+  #define BASE_OPTIONS() \

+  OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug"), \

+  OPT_BOOLEAN('S', "serial", &param.serial, "use serial numbers to id memdevs")

+ @@ -51,6 +62,14 @@ OPT_UINTEGER('O', "offset", &param.offset, \

+  OPT_BOOLEAN('f', "force", &param.force,                                \

+  	    "DANGEROUS: override active memdev safety checks")

+  

+ +#define SET_PARTITION_OPTIONS() \

+ +OPT_STRING('t', "type",  &param.type, "type",			\

+ +	"'pmem' or 'volatile' (Default: 'pmem')"),		\

+ +OPT_STRING('s', "size",  &param.size, "size",			\

+ +	"size in bytes (Default: all available capacity)"),	\

+ +OPT_BOOLEAN('a', "align",  &param.align,			\

+ +	"auto-align --size per device's requirement")

+ +

+  static const struct option read_options[] = {

+  	BASE_OPTIONS(),

+  	LABEL_OPTIONS(),

+ @@ -82,6 +101,12 @@ static const struct option enable_options[] = {

+  	OPT_END(),

+  };

+  

+ +static const struct option set_partition_options[] = {

+ +	BASE_OPTIONS(),

+ +	SET_PARTITION_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+  static int action_disable(struct cxl_memdev *memdev, struct action_context *actx)

+  {

+  	if (!cxl_memdev_is_enabled(memdev))

+ @@ -209,6 +234,176 @@ out:

+  	return rc;

+  }

+  

+ +static unsigned long long

+ +partition_align(const char *devname, enum cxl_setpart_type type,

+ +		unsigned long long volatile_size, unsigned long long alignment,

+ +		unsigned long long available)

+ +{

+ +	if (IS_ALIGNED(volatile_size, alignment))

+ +		return volatile_size;

+ +

+ +	if (!param.align) {

+ +		log_err(&ml, "%s: size %lld is not partition aligned %lld\n",

+ +			devname, volatile_size, alignment);

+ +		return ULLONG_MAX;

+ +	}

+ +

+ +	/* Align based on partition type to fulfill users size request */

+ +	if (type == CXL_SETPART_PMEM)

+ +		volatile_size = ALIGN_DOWN(volatile_size, alignment);

+ +	else

+ +		volatile_size = ALIGN(volatile_size, alignment);

+ +

+ +	/* Fail if the align pushes size over the available limit. */

+ +	if (volatile_size > available) {

+ +		log_err(&ml, "%s: aligned partition size %lld exceeds available size %lld\n",

+ +			devname, volatile_size, available);

+ +		volatile_size = ULLONG_MAX;

+ +	}

+ +

+ +	return volatile_size;

+ +}

+ +

+ +static unsigned long long

+ +param_size_to_volatile_size(const char *devname, enum cxl_setpart_type type,

+ +		unsigned long long size, unsigned long long available)

+ +{

+ +	/* User omits size option. Apply all available capacity to type. */

+ +	if (size == ULLONG_MAX) {

+ +		if (type == CXL_SETPART_PMEM)

+ +			return 0;

+ +		return available;

+ +	}

+ +

+ +	/* User includes a size option. Apply it to type */

+ +	if (size > available) {

+ +		log_err(&ml, "%s: %lld exceeds available capacity %lld\n",

+ +			devname, size, available);

+ +			return ULLONG_MAX;

+ +	}

+ +	if (type == CXL_SETPART_PMEM)

+ +		return available - size;

+ +	return size;

+ +}

+ +

+ +/*

+ + * Return the volatile_size to use in the CXL set paritition

+ + * command, or ULLONG_MAX if unable to validate the partition

+ + * request.

+ + */

+ +static unsigned long long

+ +validate_partition(struct cxl_memdev *memdev, enum cxl_setpart_type type,

+ +		unsigned long long size)

+ +{

+ +	unsigned long long total_cap, volatile_only, persistent_only;

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	unsigned long long volatile_size = ULLONG_MAX;

+ +	unsigned long long available, alignment;

+ +	struct cxl_cmd *cmd;

+ +	int rc;

+ +

+ +	cmd = cxl_cmd_new_identify(memdev);

+ +	if (!cmd)

+ +		return ULLONG_MAX;

+ +	rc = cxl_cmd_submit(cmd);

+ +	if (rc < 0)

+ +		goto out;

+ +	rc = cxl_cmd_get_mbox_status(cmd);

+ +	if (rc != 0)

+ +		goto out;

+ +

+ +	alignment = cxl_cmd_identify_get_partition_align(cmd);

+ +	if (alignment == 0) {

+ +		log_err(&ml, "%s: no available capacity\n", devname);

+ +		goto out;

+ +	}

+ +

+ +	/* Calculate the actual available capacity */

+ +	total_cap = cxl_cmd_identify_get_total_size(cmd);

+ +	volatile_only = cxl_cmd_identify_get_volatile_only_size(cmd);

+ +	persistent_only = cxl_cmd_identify_get_persistent_only_size(cmd);

+ +	available = total_cap - volatile_only - persistent_only;

+ +

+ +	/* Translate the users size request into an aligned volatile_size */

+ +	volatile_size = param_size_to_volatile_size(devname, type, size,

+ +				available);

+ +	if (volatile_size == ULLONG_MAX)

+ +		goto out;

+ +

+ +	volatile_size = partition_align(devname, type, volatile_size, alignment,

+ +				available);

+ +

+ +out:

+ +	cxl_cmd_unref(cmd);

+ +	return volatile_size;

+ +}

+ +

+ +static int action_setpartition(struct cxl_memdev *memdev,

+ +		struct action_context *actx)

+ +{

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	enum cxl_setpart_type type = CXL_SETPART_PMEM;

+ +	unsigned long long size = ULLONG_MAX;

+ +	struct json_object *jmemdev;

+ +	struct cxl_cmd *cmd;

+ +	int rc;

+ +

+ +	if (param.type) {

+ +		if (strcmp(param.type, "pmem") == 0)

+ +			/* default */;

+ +		else if (strcmp(param.type, "volatile") == 0)

+ +			type = CXL_SETPART_VOLATILE;

+ +		else {

+ +			log_err(&ml, "invalid type '%s'\n", param.type);

+ +			return -EINVAL;

+ +		}

+ +	}

+ +

+ +	if (param.size) {

+ +		size = parse_size64(param.size);

+ +		if (size == ULLONG_MAX) {

+ +			log_err(&ml, "%s: failed to parse size option '%s'\n",

+ +			devname, param.size);

+ +			return -EINVAL;

+ +		}

+ +	}

+ +

+ +	size = validate_partition(memdev, type, size);

+ +	if (size == ULLONG_MAX)

+ +		return -EINVAL;

+ +

+ +	cmd = cxl_cmd_new_set_partition(memdev, size);

+ +	if (!cmd) {

+ +		rc = -ENXIO;

+ +		goto out_err;

+ +	}

+ +

+ +	rc = cxl_cmd_submit(cmd);

+ +	if (rc < 0) {

+ +		log_err(&ml, "cmd submission failed: %s\n", strerror(-rc));

+ +		goto out_cmd;

+ +	}

+ +

+ +	rc = cxl_cmd_get_mbox_status(cmd);

+ +	if (rc != 0) {

+ +		log_err(&ml, "%s: mbox status: %d\n", __func__, rc);

+ +		rc = -ENXIO;

+ +	}

+ +

+ +out_cmd:

+ +	cxl_cmd_unref(cmd);

+ +out_err:

+ +	if (rc)

+ +		log_err(&ml, "%s error: %s\n", devname, strerror(-rc));

+ +

+ +	jmemdev = util_cxl_memdev_to_json(memdev, UTIL_JSON_PARTITION);

+ +	if (jmemdev)

+ +		printf("%s\n", json_object_to_json_string_ext(jmemdev,

+ +		       JSON_C_TO_STRING_PRETTY));

+ +

+ +	return rc;

+ +}

+ +

+  static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  			 int (*action)(struct cxl_memdev *memdev,

+  				       struct action_context *actx),

+ @@ -398,3 +593,14 @@ int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx)

+  		 count > 1 ? "s" : "");

+  	return count >= 0 ? 0 : EXIT_FAILURE;

+  }

+ +

+ +int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(argc, argv, ctx, action_setpartition,

+ +			set_partition_options,

+ +			"cxl set-partition <mem0> [<mem1>..<memN>] [<options>]");

+ +	log_info(&ml, "set_partition %d mem%s\n", count >= 0 ? count : 0,

+ +		 count > 1 ? "s" : "");

+ +

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,41 @@ 

+ From cd41a4dc6af9b48045b0aa46669d560faeb134e2 Mon Sep 17 00:00:00 2001

+ From: Jay W <git.jaydoubleu@gmail.com>

+ Date: Tue, 15 Feb 2022 00:45:00 +0000

+ Subject: [PATCH 138/217] Update ndctl.spec to allow flatpak builds

+ 

+ This will allow ndctl to be build as dependency for some flatpak builds

+ on fedora systems.

+ See also: https://docs.fedoraproject.org/en-US/flatpak/troubleshooting/#_uncompressed_manual_pages

+ 

+ Link: https://github.com/pmem/ndctl/pull/192

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl.spec.in | 5 ++++-

+  1 file changed, 4 insertions(+), 1 deletion(-)

+ 

+ diff --git a/ndctl.spec.in b/ndctl.spec.in

+ index 9ca831e..cfcafa2 100644

+ --- a/ndctl.spec.in

+ +++ b/ndctl.spec.in

+ @@ -38,6 +38,9 @@ subsystem defines a kernel device model and control message interface for

+  platform NVDIMM resources like those defined by the ACPI 6+ NFIT (NVDIMM

+  Firmware Interface Table).

+  

+ +%if 0%{?flatpak}

+ +%global _udevrulesdir %{_prefix}/lib/udev/rules.d

+ +%endif

+  

+  %package -n DNAME

+  Summary:	Development files for libndctl

+ @@ -231,7 +234,7 @@ fi

+  %{_libdir}/libcxl.so

+  %{_libdir}/pkgconfig/libcxl.pc

+  %{_mandir}/man3/cxl*

+ -%{_mandir}/man3/libcxl.3.gz

+ +%{_mandir}/man3/libcxl.3*

+  

+  

+  %changelog

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,47 @@ 

+ From 3e4a66f0dfb02046f6d3375d637840b6da9c71d1 Mon Sep 17 00:00:00 2001

+ From: michalbiesek <michal.biesek@intel.com>

+ Date: Mon, 2 Dec 2019 11:21:03 +0100

+ Subject: [PATCH 139/217] daxctl: provide safe versions of iteration API

+ 

+ Add support for safe iterate through regions and devices

+ 

+ Link: https://github.com/pmem/ndctl/pull/132

+ Signed-off-by: Michal Biesek <michal.biesek@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  daxctl/libdaxctl.h | 13 +++++++++++++

+  1 file changed, 13 insertions(+)

+ 

+ diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h

+ index 6b6c71f..6876037 100644

+ --- a/daxctl/libdaxctl.h

+ +++ b/daxctl/libdaxctl.h

+ @@ -93,12 +93,25 @@ int daxctl_memory_online_no_movable(struct daxctl_memory *mem);

+               dev != NULL; \

+               dev = daxctl_dev_get_next(dev))

+  

+ +#define daxctl_dev_foreach_safe(region, dev, _dev) \

+ +        for (dev = daxctl_dev_get_first(region), \

+ +             _dev = dev ? daxctl_dev_get_next(dev) : NULL; \

+ +             dev != NULL; \

+ +             dev = _dev, \

+ +            _dev = _dev ? daxctl_dev_get_next(_dev) : NULL)

+  

+  #define daxctl_region_foreach(ctx, region) \

+          for (region = daxctl_region_get_first(ctx); \

+               region != NULL; \

+               region = daxctl_region_get_next(region))

+  

+ +#define daxctl_region_foreach_safe(ctx, region, _region) \

+ +        for (region = daxctl_region_get_first(ctx), \

+ +             _region = region ? daxctl_region_get_next(region) : NULL; \

+ +             region != NULL; \

+ +             region = _region, \

+ +            _region = _region ? daxctl_region_get_next(_region) : NULL)

+ +

+  struct daxctl_mapping;

+  struct daxctl_mapping *daxctl_mapping_get_first(struct daxctl_dev *dev);

+  struct daxctl_mapping *daxctl_mapping_get_next(struct daxctl_mapping *mapping);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,216 @@ 

+ From 10653a171bc0ca145236d2c75e5c5422caeb8b55 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 23 Feb 2022 22:28:05 -0700

+ Subject: [PATCH 140/217] util/size.h: fix build for older compilers

+ 

+ Add a fallback for older compilers that lack __builtin_add_overflow()

+ and friends. Commit 7aa7c7be6e80 ("util: add the struct_size() helper from the

+ kernel") which added these helpers from the kernel neglected to copy

+ over the fallback code.

+ 

+ Link: https://lore.kernel.org/r/20220224052805.2462449-1-vishal.l.verma@intel.com

+ Fixes: 7aa7c7be6e80 ("util: add the struct_size() helper from the kernel")

+ Reported-by: Joao Martins <joao.m.martins@oracle.com>

+ Reviewed-by: Joao Martins <joao.m.martins@oracle.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/size.h | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++--

+  1 file changed, 159 insertions(+), 4 deletions(-)

+ 

+ diff --git a/util/size.h b/util/size.h

+ index e72467f..1cb0669 100644

+ --- a/util/size.h

+ +++ b/util/size.h

+ @@ -6,6 +6,7 @@

+  #include <stdbool.h>

+  #include <stdint.h>

+  #include <util/util.h>

+ +#include <ccan/short_types/short_types.h>

+  

+  #define SZ_1K     0x00000400

+  #define SZ_4K     0x00001000

+ @@ -43,23 +44,177 @@ static inline bool is_power_of_2(unsigned long long v)

+   * alias for __builtin_add_overflow, but add type checks similar to

+   * below.

+   */

+ -#define check_add_overflow(a, b, d) (({	\

+ +#define is_signed_type(type)       (((type)(-1)) < (type)1)

+ +#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))

+ +#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))

+ +#define type_min(T) ((T)((T)-type_max(T)-(T)1))

+ +

+ +#if GCC_VERSION >= 50100

+ +#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1

+ +#endif

+ +

+ +#if __clang__ && \

+ +    __has_builtin(__builtin_mul_overflow) && \

+ +    __has_builtin(__builtin_add_overflow)

+ +#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1

+ +#endif

+ +

+ +#if COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW

+ +

+ +#define check_add_overflow(a, b, d) ({		\

+  	typeof(a) __a = (a);			\

+  	typeof(b) __b = (b);			\

+  	typeof(d) __d = (d);			\

+  	(void) (&__a == &__b);			\

+  	(void) (&__a == __d);			\

+  	__builtin_add_overflow(__a, __b, __d);	\

+ -}))

+ +})

+ +

+ +#define check_sub_overflow(a, b, d) ({		\

+ +	typeof(a) __a = (a);			\

+ +	typeof(b) __b = (b);			\

+ +	typeof(d) __d = (d);			\

+ +	(void) (&__a == &__b);			\

+ +	(void) (&__a == __d);			\

+ +	__builtin_sub_overflow(__a, __b, __d);	\

+ +})

+  

+ -#define check_mul_overflow(a, b, d) (({	\

+ +#define check_mul_overflow(a, b, d) ({		\

+  	typeof(a) __a = (a);			\

+  	typeof(b) __b = (b);			\

+  	typeof(d) __d = (d);			\

+  	(void) (&__a == &__b);			\

+  	(void) (&__a == __d);			\

+  	__builtin_mul_overflow(__a, __b, __d);	\

+ -}))

+ +})

+ +

+ +

+ +#else /* !COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */

+ +

+ +/* Checking for unsigned overflow is relatively easy without causing UB. */

+ +#define __unsigned_add_overflow(a, b, d) ({	\

+ +	typeof(a) __a = (a);			\

+ +	typeof(b) __b = (b);			\

+ +	typeof(d) __d = (d);			\

+ +	(void) (&__a == &__b);			\

+ +	(void) (&__a == __d);			\

+ +	*__d = __a + __b;			\

+ +	*__d < __a;				\

+ +})

+ +#define __unsigned_sub_overflow(a, b, d) ({	\

+ +	typeof(a) __a = (a);			\

+ +	typeof(b) __b = (b);			\

+ +	typeof(d) __d = (d);			\

+ +	(void) (&__a == &__b);			\

+ +	(void) (&__a == __d);			\

+ +	*__d = __a - __b;			\

+ +	__a < __b;				\

+ +})

+ +/*

+ + * If one of a or b is a compile-time constant, this avoids a division.

+ + */

+ +#define __unsigned_mul_overflow(a, b, d) ({		\

+ +	typeof(a) __a = (a);				\

+ +	typeof(b) __b = (b);				\

+ +	typeof(d) __d = (d);				\

+ +	(void) (&__a == &__b);				\

+ +	(void) (&__a == __d);				\

+ +	*__d = __a * __b;				\

+ +	__builtin_constant_p(__b) ?			\

+ +	  __b > 0 && __a > type_max(typeof(__a)) / __b : \

+ +	  __a > 0 && __b > type_max(typeof(__b)) / __a;	 \

+ +})

+ +

+ +/*

+ + * For signed types, detecting overflow is much harder, especially if

+ + * we want to avoid UB. But the interface of these macros is such that

+ + * we must provide a result in *d, and in fact we must produce the

+ + * result promised by gcc's builtins, which is simply the possibly

+ + * wrapped-around value. Fortunately, we can just formally do the

+ + * operations in the widest relevant unsigned type (u64) and then

+ + * truncate the result - gcc is smart enough to generate the same code

+ + * with and without the (u64) casts.

+ + */

+ +

+ +/*

+ + * Adding two signed integers can overflow only if they have the same

+ + * sign, and overflow has happened iff the result has the opposite

+ + * sign.

+ + */

+ +#define __signed_add_overflow(a, b, d) ({	\

+ +	typeof(a) __a = (a);			\

+ +	typeof(b) __b = (b);			\

+ +	typeof(d) __d = (d);			\

+ +	(void) (&__a == &__b);			\

+ +	(void) (&__a == __d);			\

+ +	*__d = (u64)__a + (u64)__b;		\

+ +	(((~(__a ^ __b)) & (*__d ^ __a))	\

+ +		& type_min(typeof(__a))) != 0;	\

+ +})

+ +

+ +/*

+ + * Subtraction is similar, except that overflow can now happen only

+ + * when the signs are opposite. In this case, overflow has happened if

+ + * the result has the opposite sign of a.

+ + */

+ +#define __signed_sub_overflow(a, b, d) ({	\

+ +	typeof(a) __a = (a);			\

+ +	typeof(b) __b = (b);			\

+ +	typeof(d) __d = (d);			\

+ +	(void) (&__a == &__b);			\

+ +	(void) (&__a == __d);			\

+ +	*__d = (u64)__a - (u64)__b;		\

+ +	((((__a ^ __b)) & (*__d ^ __a))		\

+ +		& type_min(typeof(__a))) != 0;	\

+ +})

+ +

+ +/*

+ + * Signed multiplication is rather hard. gcc always follows C99, so

+ + * division is truncated towards 0. This means that we can write the

+ + * overflow check like this:

+ + *

+ + * (a > 0 && (b > MAX/a || b < MIN/a)) ||

+ + * (a < -1 && (b > MIN/a || b < MAX/a) ||

+ + * (a == -1 && b == MIN)

+ + *

+ + * The redundant casts of -1 are to silence an annoying -Wtype-limits

+ + * (included in -Wextra) warning: When the type is u8 or u16, the

+ + * __b_c_e in check_mul_overflow obviously selects

+ + * __unsigned_mul_overflow, but unfortunately gcc still parses this

+ + * code and warns about the limited range of __b.

+ + */

+ +

+ +#define __signed_mul_overflow(a, b, d) ({				\

+ +	typeof(a) __a = (a);						\

+ +	typeof(b) __b = (b);						\

+ +	typeof(d) __d = (d);						\

+ +	typeof(a) __tmax = type_max(typeof(a));				\

+ +	typeof(a) __tmin = type_min(typeof(a));				\

+ +	(void) (&__a == &__b);						\

+ +	(void) (&__a == __d);						\

+ +	*__d = (u64)__a * (u64)__b;					\

+ +	(__b > 0   && (__a > __tmax/__b || __a < __tmin/__b)) ||	\

+ +	(__b < (typeof(__b))-1  && (__a > __tmin/__b || __a < __tmax/__b)) || \

+ +	(__b == (typeof(__b))-1 && __a == __tmin);			\

+ +})

+ +

+ +

+ +#define check_add_overflow(a, b, d)					\

+ +	__builtin_choose_expr(is_signed_type(typeof(a)),		\

+ +			__signed_add_overflow(a, b, d),			\

+ +			__unsigned_add_overflow(a, b, d))

+ +

+ +#define check_sub_overflow(a, b, d)					\

+ +	__builtin_choose_expr(is_signed_type(typeof(a)),		\

+ +			__signed_sub_overflow(a, b, d),			\

+ +			__unsigned_sub_overflow(a, b, d))

+ +

+ +#define check_mul_overflow(a, b, d)					\

+ +	__builtin_choose_expr(is_signed_type(typeof(a)),		\

+ +			__signed_mul_overflow(a, b, d),			\

+ +			__unsigned_mul_overflow(a, b, d))

+ +

+ +#endif

+  

+  /*

+   * Compute a*b+c, returning SIZE_MAX on overflow. Internal helper for

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,49 @@ 

+ From 55f36387ee8a88c489863103347ae275b1bc9191 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 23 Feb 2022 18:41:45 -0800

+ Subject: [PATCH 141/217] build: Automate rpmbuild.sh

+ 

+ Prior to the meson conversion rpmbuild.sh with no arguments would find a

+ pre-created ndctl.spec file relative to the script. Restore that

+ behavior by looking for the script in the build/ directory, and try to

+ create it if not there.

+ 

+ Yes, this fails if someone picks a directory other than build/ for the

+ output directory, but build/ is conventional.

+ 

+ Another regression from autotools is the loss of support for building

+ "dirty" rpms i.e. rpms from git source trees with uncommitted changes.

+ At least provide a coherent error message for that case.

+ 

+ Link: https://lore.kernel.org/r/164567050589.2266739.68846452427328787.stgit@dwillia2-desk3.amr.corp.intel.com

+ Reported-by: Jane Chu <jane.chu@oracle.com>

+ Reported-by: Vishal Verma <vishal.l.verma@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  rpmbuild.sh | 9 +++++++++

+  1 file changed, 9 insertions(+)

+ 

+ diff --git a/rpmbuild.sh b/rpmbuild.sh

+ index b1f4d9e..d9823e5 100755

+ --- a/rpmbuild.sh

+ +++ b/rpmbuild.sh

+ @@ -4,6 +4,15 @@ spec=${1:-$(dirname $0)/rhel/ndctl.spec)}

+  

+  pushd $(dirname $0) >/dev/null

+  [ ! -d ~/rpmbuild/SOURCES ] && echo "rpmdev tree not found" && exit 1

+ +if ./git-version | grep -q dirty; then

+ +	echo "Uncommitted changes detected, commit or undo them to proceed"

+ +	git status -uno --short

+ +	exit 1

+ +fi

+ +if [ ! -f $spec ]; then

+ +	meson compile -C build rhel/ndctl.spec

+ +	spec=$(dirname $0)/build/rhel/ndctl.spec

+ +fi

+  ./make-git-snapshot.sh

+  popd > /dev/null

+  rpmbuild --nocheck -ba $spec

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,48 @@ 

+ From 3b5fb8b6428dfaab39bab58d67412427f514c1f4 Mon Sep 17 00:00:00 2001

+ From: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Date: Sat, 26 Feb 2022 17:09:55 +0530

+ Subject: [PATCH 142/217] util/size.h: Fix build error for GCC < 10

+ 

+ Building with GCC 8.4.1 results in following build error for 'util/size.c':

+ 

+ ../util/size.h:57:16: error: missing binary operator before token "("

+    __has_builtin(__builtin_mul_overflow) && \

+ 

+ This is caused due to missing '__has_builtin' preprocessor operator in GCC

+ versions < 10.0.0. The patch updates the check for CLANG's availability of

+ __builtin_{mul,add}_overflow to prevent preprocessor from evaluating the

+ expression "___has_builtin(__builtin_mul_overflow) &&

+ __has_builtin(__builtin_add_overflow)".

+ 

+ Link: https://lore.kernel.org/r/20220226113955.526036-1-vaibhav@linux.ibm.com

+ Fixes:10653a171bc0("util/size.h: fix build for older compilers")

+ Reported-by: Tarun Sahu <tsahu@linux.ibm.com>

+ Reviewed-by: Joao Martins <joao.m.martins@oracle.com>

+ Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/size.h | 5 +++--

+  1 file changed, 3 insertions(+), 2 deletions(-)

+ 

+ diff --git a/util/size.h b/util/size.h

+ index 1cb0669..02baa77 100644

+ --- a/util/size.h

+ +++ b/util/size.h

+ @@ -53,11 +53,12 @@ static inline bool is_power_of_2(unsigned long long v)

+  #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1

+  #endif

+  

+ -#if __clang__ && \

+ -    __has_builtin(__builtin_mul_overflow) && \

+ +#if __clang__

+ +#if __has_builtin(__builtin_mul_overflow) && \

+      __has_builtin(__builtin_add_overflow)

+  #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1

+  #endif

+ +#endif

+  

+  #if COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,47 @@ 

+ From 4b381a31345930d08ab9adb87087bb765f624506 Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Thu, 3 Mar 2022 15:16:57 -0800

+ Subject: [PATCH 143/217] libcxl: Remove extraneous NULL checks when validating

+  cmd status

+ 

+ When a cxl_cmd_new_*() function is executed the returned command

+ pointer is always checked for NULL. Remove extraneous NULL checks

+ later in the command validation path.

+ 

+ Coverity pointed these out as 'check_after_deref' issues.

+ 

+ Link: https://lore.kernel.org/r/20220303231657.1053594-1-alison.schofield@intel.com

+ Fixes: 4f588b964dcc ("libcxl: add GET_PARTITION_INFO mailbox command and accessors")

+ Fixes: 50b9d77232d4 ("libcxl: add accessors for capacity fields of the IDENTIFY command")

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 4 ----

+  1 file changed, 4 deletions(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index daa2bbc..f111d86 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -2283,8 +2283,6 @@ cmd_to_identify(struct cxl_cmd *cmd)

+  	if (cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_IDENTIFY))

+  		return NULL;

+  

+ -	if (!cmd)

+ -		return NULL;

+  	return cmd->output_payload;

+  }

+  

+ @@ -2429,8 +2427,6 @@ cmd_to_get_partition(struct cxl_cmd *cmd)

+  	if (cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_GET_PARTITION_INFO))

+  		return NULL;

+  

+ -	if (!cmd)

+ -		return NULL;

+  	return cmd->output_payload;

+  }

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,35 @@ 

+ From 057ca6fc2ce63625236bf00e795e0847e6508ed8 Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Thu, 3 Mar 2022 16:01:33 -0800

+ Subject: [PATCH 144/217] libdaxctl: free resource allocated with asprintf()

+ 

+ Static analysis reported this resource leak.

+ 

+ Link: https://lore.kernel.org/r/20220304000133.1053883-1-alison.schofield@intel.com

+ Fixes: d07508a0cc3c ("libdaxctl: add daxctl_region_create_dev()")

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  daxctl/lib/libdaxctl.c | 5 ++---

+  1 file changed, 2 insertions(+), 3 deletions(-)

+ 

+ diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c

+ index f173bbb..5703992 100644

+ --- a/daxctl/lib/libdaxctl.c

+ +++ b/daxctl/lib/libdaxctl.c

+ @@ -624,10 +624,9 @@ DAXCTL_EXPORT int daxctl_region_create_dev(struct daxctl_region *region)

+  	}

+  

+  	rc = sysfs_write_attr(ctx, path, num_devices);

+ -	if (rc)

+ -		return rc;

+ +	free(num_devices);

+  

+ -	return 0;

+ +	return rc;

+  }

+  

+  DAXCTL_EXPORT int daxctl_region_destroy_dev(struct daxctl_region *region,

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,51 @@ 

+ From 367593e7b602fd490baf22a26887c09877e75c14 Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Thu, 3 Mar 2022 16:54:23 -0800

+ Subject: [PATCH 145/217] cxl/list: tidy the error path in add_cxl_decoder()

+ 

+ Static analysis reported this NULL pointer dereference during

+ cleanup on error in add_cxl_decoder().

+ 

+ Link: https://lore.kernel.org/r/20220304005423.1054282-1-alison.schofield@intel.com

+ Fixes: 46564977afb7 ("cxl/list: Add decoder support")

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 8 +++++---

+  1 file changed, 5 insertions(+), 3 deletions(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index f111d86..1782f42 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -919,11 +919,11 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  

+  	decoder->dev_path = strdup(cxldecoder_base);

+  	if (!decoder->dev_path)

+ -		goto err;

+ +		goto err_decoder;

+  

+  	decoder->dev_buf = calloc(1, strlen(cxldecoder_base) + 50);

+  	if (!decoder->dev_buf)

+ -		goto err;

+ +		goto err_decoder;

+  	decoder->buf_len = strlen(cxldecoder_base) + 50;

+  

+  	sprintf(path, "%s/start", cxldecoder_base);

+ @@ -1024,10 +1024,12 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	list_add(&port->decoders, &decoder->list);

+  

+  	return decoder;

+ -err:

+ +

+ +err_decoder:

+  	free(decoder->dev_path);

+  	free(decoder->dev_buf);

+  	free(decoder);

+ +err:

+  	free(path);

+  	return NULL;

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,38 @@ 

+ From 7564aeeae7bc8c3813bd80676769bd11a1055ca0 Mon Sep 17 00:00:00 2001

+ From: Alison Schofield <alison.schofield@intel.com>

+ Date: Thu, 3 Mar 2022 17:36:43 -0800

+ Subject: [PATCH 146/217] cxl/list: always free the path var in

+  add_cxl_decoder()

+ 

+ Static analysis reported a resource leak where the 'path' variable was

+ not always freed before returns.

+ 

+ Link: https://lore.kernel.org/r/20220304013643.1054605-1-alison.schofield@intel.com

+ Fixes: 46564977afb7 ("cxl/list: Add decoder support")

+ Signed-off-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 2 ++

+  1 file changed, 2 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 1782f42..59e1644 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1018,11 +1018,13 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	cxl_decoder_foreach(port, decoder_dup)

+  		if (decoder_dup->id == decoder->id) {

+  			free_decoder(decoder, NULL);

+ +			free(path);

+  			return decoder_dup;

+  		}

+  

+  	list_add(&port->decoders, &decoder->list);

+  

+ +	free(path);

+  	return decoder;

+  

+  err_decoder:

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,40 @@ 

+ From 633205122bc5a54b56ac6d961f9fc4aac917b0fd Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Fri, 4 Mar 2022 13:02:51 -0700

+ Subject: [PATCH 147/217] scripts/docsurgeon: Fix document header for section 1

+  man pages

+ 

+ Document header generation for section 1 man pages (cxl-foo commands) was

+ missing the section number in parenthesis, i.e. it would generate:

+ 

+   cxl-foo

+   =======

+ 

+ instead of:

+ 

+   cxl-foo(1)

+   ==========

+ 

+ resulting in asciidoc(tor) warnings.

+ 

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  scripts/docsurgeon | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/scripts/docsurgeon b/scripts/docsurgeon

+ index ca0ad78..1421ef7 100755

+ --- a/scripts/docsurgeon

+ +++ b/scripts/docsurgeon

+ @@ -244,7 +244,7 @@ gen_cli()

+  

+  	# Start template generation

+  	printf "%s\n" "$copyright_cli" > "$tmp"

+ -	gen_header "$name" >> "$tmp"

+ +	gen_header "$name($_arg_section)" >> "$tmp"

+  	gen_section_name "$name" >> "$tmp"

+  	gen_section_synopsis_1 "$name" >> "$tmp"

+  	gen_section "DESCRIPTION" >> "$tmp"

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,156 @@ 

+ From dd58d43458943d20ff063850670bf54a5242c9c5 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Sun, 6 Mar 2022 23:39:25 -0700

+ Subject: [PATCH 148/217] ndctl: release v73

+ 

+ This release incorporates functionality up to the 5.17 kernel.

+ 

+ Highlights include full CXL topology walk and filtering in cxl-list, a

+ new cxl-cli command to set memdev partitioning info, several unit test

+ fixes, conversion of the build system to meson, smart error injection

+ enhancements for 'papr' NVDIMMs, and RPM spec fixes to support config

+ file migration, and flatpak builds.

+ 

+ Commands:

+   cxl-list: full topology walk and filtering

+   cxl-set-partition: new command to set memdev partitions

+   cxl{enable,disable}-port: new commands

+   cxl{enable,disable}-memdev: new commands

+ 

+ Tests:

+   Deprecate BLK aperture support

+   inject-smart.sh: increase tolerance for decimal formatted fields

+ 

+ APIs:

+   ndctl_dimm_refresh_flags

+   cxl_bus_get_ctx

+   cxl_bus_get_devname

+   cxl_bus_get_first

+   cxl_bus_get_id

+   cxl_bus_get_next

+   cxl_bus_get_port

+   cxl_bus_get_provider

+   cxl_cmd_identify_get_persistent_only_size

+   cxl_cmd_identify_get_total_size

+   cxl_cmd_identify_get_volatile_only_size

+   cxl_cmd_new_get_partition

+   cxl_cmd_new_set_partition

+   cxl_cmd_partition_get_active_persistent_size

+   cxl_cmd_partition_get_active_volatile_size

+   cxl_cmd_partition_get_next_persistent_size

+   cxl_cmd_partition_get_next_volatile_size

+   cxl_cmd_partition_set_mode

+   cxl_decoder_get_ctx

+   cxl_decoder_get_devname

+   cxl_decoder_get_first

+   cxl_decoder_get_id

+   cxl_decoder_get_next

+   cxl_decoder_get_nr_targets

+   cxl_decoder_get_port

+   cxl_decoder_get_resource

+   cxl_decoder_get_size

+   cxl_decoder_get_target_by_memdev

+   cxl_decoder_get_target_by_position

+   cxl_decoder_get_target_type

+   cxl_decoder_is_accelmem_capable

+   cxl_decoder_is_locked

+   cxl_decoder_is_mem_capable

+   cxl_decoder_is_pmem_capable

+   cxl_decoder_is_volatile_capable

+   cxl_dport_get_devname

+   cxl_dport_get_first

+   cxl_dport_get_id

+   cxl_dport_get_next

+   cxl_dport_get_physical_node

+   cxl_dport_get_port

+   cxl_dport_maps_memdev

+   cxl_endpoint_get_bus

+   cxl_endpoint_get_ctx

+   cxl_endpoint_get_devname

+   cxl_endpoint_get_first

+   cxl_endpoint_get_host

+   cxl_endpoint_get_id

+   cxl_endpoint_get_memdev

+   cxl_endpoint_get_next

+   cxl_endpoint_get_parent

+   cxl_endpoint_get_port

+   cxl_endpoint_is_enabled

+   cxl_memdev_disable_invalidate

+   cxl_memdev_enable

+   cxl_memdev_get_bus

+   cxl_memdev_get_endpoint

+   cxl_memdev_get_host

+   cxl_memdev_get_numa_node

+   cxl_memdev_get_serial

+   cxl_memdev_is_enabled

+   cxl_port_disable_invalidate

+   cxl_port_enable

+   cxl_port_get_bus

+   cxl_port_get_bus

+   cxl_port_get_ctx

+   cxl_port_get_devname

+   cxl_port_get_dport_by_memdev

+   cxl_port_get_first

+   cxl_port_get_host

+   cxl_port_get_id

+   cxl_port_get_next

+   cxl_port_get_next_all

+   cxl_port_get_nr_dports

+   cxl_port_get_parent

+   cxl_port_hosts_memdev

+   cxl_port_is_enabled

+   cxl_port_is_endpoint

+   cxl_port_is_root

+   cxl_port_is_switch

+   cxl_port_to_bus

+   cxl_port_to_endpoint

+   cxl_target_get_decoder

+   cxl_target_get_devname

+   cxl_target_get_first

+   cxl_target_get_id

+   cxl_target_get_next

+   cxl_target_get_physical_node

+   cxl_target_get_position

+   cxl_target_maps_memdev

+ ---

+  meson.build | 14 +++++++-------

+  1 file changed, 7 insertions(+), 7 deletions(-)

+ 

+ diff --git a/meson.build b/meson.build

+ index f25ec6c..42e11aa 100644

+ --- a/meson.build

+ +++ b/meson.build

+ @@ -1,5 +1,5 @@

+  project('ndctl', 'c',

+ -  version : '72',

+ +  version : '73',

+    license : [

+      'GPL-2.0',

+      'LGPL-2.1',

+ @@ -270,17 +270,17 @@ config_h = configure_file(

+  )

+  add_project_arguments('-include', 'config.h', language : 'c')

+  

+ -LIBNDCTL_CURRENT=25

+ -LIBNDCTL_REVISION=1

+ -LIBNDCTL_AGE=19

+ +LIBNDCTL_CURRENT=26

+ +LIBNDCTL_REVISION=0

+ +LIBNDCTL_AGE=20

+  

+  LIBDAXCTL_CURRENT=6

+ -LIBDAXCTL_REVISION=0

+ +LIBDAXCTL_REVISION=1

+  LIBDAXCTL_AGE=5

+  

+ -LIBCXL_CURRENT=1

+ +LIBCXL_CURRENT=2

+  LIBCXL_REVISION=0

+ -LIBCXL_AGE=0

+ +LIBCXL_AGE=1

+  

+  root_inc = include_directories(['.', 'ndctl', ])

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,49 @@ 

+ From cbe337d6a0ee7d4f0ff9a5c19d14fb5e250df220 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Wed, 9 Mar 2022 15:36:52 -0800

+ Subject: [PATCH 150/217] build: Fix '-Wall' and '-O2' warnings

+ 

+ Stop specifying '-Wall and '-O2' in cc_flags, and rely on the buildtype

+ and warning_level options. Fixup the '-D_FORTIFY_SOURCE=2' option to

+ optionally be enabled for optimizated builds rather then forcing -O2.

+ 

+ Link: https://github.com/pmem/ndctl/issues/195

+ Link: https://lore.kernel.org/r/164686901240.2874657.8473455139820858036.stgit@dwillia2-desk3.amr.corp.intel.com

+ Fixes: 4e5faa1726d2 ("build: Add meson build infrastructure")

+ Reported-by: Steve Scargall <steve.scargall@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  meson.build | 8 +++++---

+  1 file changed, 5 insertions(+), 3 deletions(-)

+ 

+ diff --git a/meson.build b/meson.build

+ index 17ca65a..4dbb80d 100644

+ --- a/meson.build

+ +++ b/meson.build

+ @@ -57,7 +57,6 @@ sed -e s,@VERSION@,@0@,g

+  '''.format(meson.project_version(), prefixdir, libdir, includedir).split()

+  

+  cc_flags = [

+ -  '-Wall',

+    '-Wchar-subscripts',

+    '-Wformat-security',

+    '-Wmissing-declarations',

+ @@ -70,9 +69,12 @@ cc_flags = [

+    '-Wmaybe-uninitialized',

+    '-Wdeclaration-after-statement',

+    '-Wunused-result',

+ -  '-D_FORTIFY_SOURCE=2',

+ -  '-O2',

+  ]

+ +

+ +if get_option('optimization') != '0'

+ +  cc_flags += [ '-D_FORTIFY_SOURCE=2' ]

+ +endif

+ +

+  cc = meson.get_compiler('c')

+  add_project_arguments(cc.get_supported_arguments(cc_flags), language : 'c')

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,33 @@ 

+ From 900cfd8e062975215fb522ca47cc6239a5269628 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 10 Mar 2022 19:35:19 -0800

+ Subject: [PATCH 151/217] build: Fix test timeouts

+ 

+ Older versions of meson, like the version that ships in CentOS Stream

+ interpret a timeout of 0 as immediately fail, rather than infinite test

+ run. Specify a 10 minute timeout by default instead.

+ 

+ Link: https://lore.kernel.org/r/164696971934.3344888.14976446737826853353.stgit@dwillia2-desk3.amr.corp.intel.com

+ Fixes: 4e5faa1726d2 ("build: Add meson build infrastructure")

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/meson.build | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/test/meson.build b/test/meson.build

+ index 07a5bb6..7ccd451 100644

+ --- a/test/meson.build

+ +++ b/test/meson.build

+ @@ -227,7 +227,7 @@ foreach t : tests

+        mmap,

+      ],

+      suite: t[2],

+ -    timeout : 0,

+ +    timeout : 600,

+      env : [

+        'NDCTL=@0@'.format(ndctl_tool.full_path()),

+        'DAXCTL=@0@'.format(daxctl_tool.full_path()),

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,68 @@ 

+ From 6d0e543f8bf01219b793cf4d7a603d3dfd7844ed Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:05 -0700

+ Subject: [PATCH 155/217] build: Move utility helpers to libutil.a

+ 

+ Stop listing util/json.c and util/log.c per command, just add them to

+ the common libutil.a object.

+ 

+ Link: https://lore.kernel.org/r/165118380572.1676208.16232543117821121022.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/meson.build    | 2 --

+  daxctl/meson.build | 1 -

+  ndctl/meson.build  | 2 --

+  util/meson.build   | 2 ++

+  4 files changed, 2 insertions(+), 5 deletions(-)

+ 

+ diff -up ndctl-71.1/cxl/meson.build.orig ndctl-71.1/cxl/meson.build

+ --- ndctl-71.1/cxl/meson.build.orig	2022-10-07 16:54:43.451540066 -0400

+ +++ ndctl-71.1/cxl/meson.build	2022-10-07 16:55:35.330716698 -0400

+ @@ -3,8 +3,6 @@ cxl_src = [

+    'list.c',

+    'port.c',

+    'memdev.c',

+ -  '../util/json.c',

+ -  '../util/log.c',

+    'json.c',

+    'filter.c',

+  ]

+ diff -up ndctl-71.1/daxctl/meson.build.orig ndctl-71.1/daxctl/meson.build

+ --- ndctl-71.1/daxctl/meson.build.orig	2022-10-07 16:54:43.333539664 -0400

+ +++ ndctl-71.1/daxctl/meson.build	2022-10-07 16:55:35.330716698 -0400

+ @@ -4,7 +4,6 @@ daxctl_src = [

+    'list.c',

+    'migrate.c',

+    'device.c',

+ -  '../util/json.c',

+    'json.c',

+    'filter.c',

+  ]

+ diff -up ndctl-71.1/ndctl/meson.build.orig ndctl-71.1/ndctl/meson.build

+ --- ndctl-71.1/ndctl/meson.build.orig	2022-10-07 16:54:43.333539664 -0400

+ +++ ndctl-71.1/ndctl/meson.build	2022-10-07 16:55:35.330716698 -0400

+ @@ -6,11 +6,9 @@ ndctl_src = [

+    'check.c',

+    'region.c',

+    'dimm.c',

+ -  '../util/log.c',

+    '../daxctl/filter.c',

+    'filter.c',

+    'list.c',

+ -  '../util/json.c',

+    '../daxctl/json.c',

+    'json.c',

+    'json-smart.c',

+ diff -up ndctl-71.1/util/meson.build.orig ndctl-71.1/util/meson.build

+ --- ndctl-71.1/util/meson.build.orig	2022-10-07 16:54:43.334539667 -0400

+ +++ ndctl-71.1/util/meson.build	2022-10-07 16:55:35.330716698 -0400

+ @@ -2,6 +2,8 @@ util = static_library('util', [

+    'parse-options.c',

+    'usage.c',

+    'size.c',

+ +  'json.c',

+ +  'log.c',

+    'main.c',

+    'help.c',

+    'strbuf.c',

@@ -0,0 +1,60 @@ 

+ From e1c629bb3e01e3df24c189c0ecabde37788139a2 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:11 -0700

+ Subject: [PATCH 156/217] util: Use SZ_ size macros in display size

+ 

+ In preparation for adding "Terabyte" support, cleanup the "1024"

+ multiplication with the SZ_* macros.

+ 

+ Link: https://lore.kernel.org/r/165118381109.1676208.8857362319985041575.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/json.c | 11 ++++++-----

+  1 file changed, 6 insertions(+), 5 deletions(-)

+ 

+ diff --git a/util/json.c b/util/json.c

+ index f8cc81f..ebdf8d9 100644

+ --- a/util/json.c

+ +++ b/util/json.c

+ @@ -5,6 +5,7 @@

+  #include <stdio.h>

+  #include <util/util.h>

+  #include <util/json.h>

+ +#include <util/size.h>

+  #include <json-c/json.h>

+  #include <json-c/printbuf.h>

+  

+ @@ -27,24 +28,24 @@ static int display_size(struct json_object *jobj, struct printbuf *pbuf,

+  	 * If prefix == JEDEC, we mean prefixes like kilo,mega,giga etc.

+  	 */

+  

+ -	if (bytes < 5000*1024)

+ +	if (bytes < 5000*SZ_1K)

+  		snprintf(buf, sizeof(buf), "%lld", bytes);

+  	else {

+  		/* IEC */

+ -		if (bytes < 2*1024LL*1024LL*1024LL) {

+ -			long cMiB = (bytes * 200LL / (1LL<<20) +1) /2;

+ +		if (bytes < 2L*SZ_1G) {

+ +			long cMiB = (bytes * 200LL / SZ_1M+1) /2;

+  

+  			c = snprintf(buf, sizeof(buf), "\"%ld.%02ld MiB",

+  					cMiB/100 , cMiB % 100);

+  		} else {

+ -			long cGiB = (bytes * 200LL / (1LL<<30) +1) /2;

+ +			long cGiB = (bytes * 200LL / SZ_1G+1) /2;

+  

+  			c = snprintf(buf, sizeof(buf), "\"%ld.%02ld GiB",

+  					cGiB/100 , cGiB % 100);

+  		}

+  

+  		/* JEDEC */

+ -		if (bytes < 2*1024LL*1024LL*1024LL) {

+ +		if (bytes < 2L*SZ_1G) {

+  			long cMB  = (bytes / (1000000LL / 200LL) + 1) / 2;

+  

+  			snprintf(buf + c, sizeof(buf) - c, " (%ld.%02ld MB)\"",

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,61 @@ 

+ From e8b5b191a55b7be671abf2c6d5d10db6edd8c1fb Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:16 -0700

+ Subject: [PATCH 157/217] util: Pretty print terabytes

+ 

+ CXL capacities are such that gigabytes are too small of a unit for

+ displaying capacities. Add terabyte support to the display_size()

+ helper.

+ 

+ Link: https://lore.kernel.org/r/165118381648.1676208.1686584406206186723.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/json.c | 15 +++++++++++++--

+  1 file changed, 13 insertions(+), 2 deletions(-)

+ 

+ diff --git a/util/json.c b/util/json.c

+ index ebdf8d9..1d5c6bc 100644

+ --- a/util/json.c

+ +++ b/util/json.c

+ @@ -37,11 +37,16 @@ static int display_size(struct json_object *jobj, struct printbuf *pbuf,

+  

+  			c = snprintf(buf, sizeof(buf), "\"%ld.%02ld MiB",

+  					cMiB/100 , cMiB % 100);

+ -		} else {

+ +		} else if (bytes < 2*SZ_1T) {

+  			long cGiB = (bytes * 200LL / SZ_1G+1) /2;

+  

+  			c = snprintf(buf, sizeof(buf), "\"%ld.%02ld GiB",

+  					cGiB/100 , cGiB % 100);

+ +		} else {

+ +			long cTiB = (bytes * 200LL / SZ_1T+1) /2;

+ +

+ +			c = snprintf(buf, sizeof(buf), "\"%ld.%02ld TiB",

+ +					cTiB/100 , cTiB % 100);

+  		}

+  

+  		/* JEDEC */

+ @@ -50,12 +55,18 @@ static int display_size(struct json_object *jobj, struct printbuf *pbuf,

+  

+  			snprintf(buf + c, sizeof(buf) - c, " (%ld.%02ld MB)\"",

+  					cMB/100, cMB % 100);

+ -		} else {

+ +		} else if (bytes < 2*SZ_1T) {

+  			long cGB  = (bytes / (1000000000LL/200LL) + 1) / 2;

+  

+  			snprintf(buf + c, sizeof(buf) - c, " (%ld.%02ld GB)\"",

+  					cGB/100 , cGB % 100);

+ +		} else {

+ +			long cTB  = (bytes / (1000000000000LL/200LL) + 1) / 2;

+ +

+ +			snprintf(buf + c, sizeof(buf) - c, " (%ld.%02ld TB)\"",

+ +					cTB/100 , cTB % 100);

+  		}

+ +

+  	}

+  

+  	return printbuf_memappend(pbuf, buf, strlen(buf));

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,49 @@ 

+ From 3ead5b8c5464c208cdbf11c0844b519518845e3e Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:22 -0700

+ Subject: [PATCH 158/217] cxl/port: Fix disable-port man page

+ 

+ The man page was copied from the enable-port. Fix up some enable-port

+ leftovers, and duplicated --endpoint option description.

+ 

+ Link: https://lore.kernel.org/r/165118382203.1676208.17234717366569348622.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-disable-port.txt | 6 +-----

+  1 file changed, 1 insertion(+), 5 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-disable-port.txt b/Documentation/cxl/cxl-disable-port.txt

+ index de13c07..ac56f20 100644

+ --- a/Documentation/cxl/cxl-disable-port.txt

+ +++ b/Documentation/cxl/cxl-disable-port.txt

+ @@ -5,7 +5,7 @@ cxl-disable-port(1)

+  

+  NAME

+  ----

+ -cxl-disable-port - activate / hot-add a given CXL port

+ +cxl-disable-port - disable / hot-remove a given CXL port and descendants

+  

+  SYNOPSIS

+  --------

+ @@ -22,7 +22,6 @@ OPTIONS

+  	Toggle from treating the port arguments as Switch Port identifiers to

+  	Endpoint Port identifiers.

+  

+ -

+  -f::

+  --force::

+  	DANGEROUS: Override the safety measure that blocks attempts to disable a

+ @@ -31,9 +30,6 @@ OPTIONS

+  	firmware and disabling an active device is akin to force removing memory

+  	from a running system.

+  

+ -	Toggle from treating the port arguments as Switch Port identifiers to

+ -	Endpoint Port identifiers.

+ -

+  --debug::

+  	If the cxl tool was built with debug disabled, turn on debug

+  	messages.

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,384 @@ 

+ From 8a35aa8fd3e1db06228329a0ca900ce246ca329e Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:27 -0700

+ Subject: [PATCH 159/217] cxl/bus: Add bus disable support

+ 

+ Route requests to disable the root back to unbinding the platform firmware

+ device, ACPI0017 for ACPI.CXL platforms.

+ 

+ Link: https://lore.kernel.org/r/165118382738.1676208.16851880881648171660.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-disable-bus.txt |  37 ++++++

+  Documentation/cxl/lib/libcxl.txt      |  12 ++

+  Documentation/cxl/meson.build         |   1 +

+  cxl/builtin.h                         |   1 +

+  cxl/bus.c                             | 159 ++++++++++++++++++++++++++

+  cxl/cxl.c                             |   1 +

+  cxl/filter.c                          |   3 +-

+  cxl/filter.h                          |   1 +

+  cxl/lib/libcxl.c                      |  15 +++

+  cxl/lib/libcxl.sym                    |   1 +

+  cxl/libcxl.h                          |   1 +

+  cxl/meson.build                       |   1 +

+  12 files changed, 231 insertions(+), 2 deletions(-)

+  create mode 100644 Documentation/cxl/cxl-disable-bus.txt

+  create mode 100644 cxl/bus.c

+ 

+ diff --git a/Documentation/cxl/cxl-disable-bus.txt b/Documentation/cxl/cxl-disable-bus.txt

+ new file mode 100644

+ index 0000000..65f695c

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-disable-bus.txt

+ @@ -0,0 +1,37 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-disable-bus(1)

+ +===================

+ +

+ +NAME

+ +----

+ +cxl-disable-bus - Shutdown an entire tree of CXL devices

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl disable-bus' <root0> [<root1>..<rootN>] [<options>]

+ +

+ +For test and debug scenarios, disable a CXL bus and any associated

+ +memory devices from CXL.mem operations.

+ +

+ +OPTIONS

+ +-------

+ +-f::

+ +--force::

+ +	DANGEROUS: Override the safety measure that blocks attempts to disable a

+ +	bus if the tool determines a descendent memdev is in active usage.

+ +	Recall that CXL memory ranges might have been established by platform

+ +	firmware and disabling an active device is akin to force removing memory

+ +	from a running system.

+ +

+ +--debug::

+ +	If the cxl tool was built with debug disabled, turn on debug

+ +	messages.

+ +

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-disable-port[1]

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 7b223cb..f8f0e66 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -216,6 +216,18 @@ discovery order. The possible provider names are 'ACPI.CXL' and

+  the kernel device names that are subject to change based on discovery

+  order.

+  

+ +=== BUS: Control

+ +----

+ +int cxl_bus_disable_invalidate(struct cxl_bus *bus);

+ +----

+ +

+ +An entire CXL topology can be torn down with this API. Like other

+ +_invalidate APIs callers must assume that all library objects have been

+ +freed. This one goes one step further and also frees the @bus argument.

+ +This may crash the system and is only useful in kernel driver

+ +development scenarios.

+ +

+ +

+  PORTS

+  -----

+  CXL ports track the PCIe hierarchy between a platform firmware CXL root

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index e927644..974a5a4 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -34,6 +34,7 @@ cxl_manpages = [

+    'cxl-disable-memdev.txt',

+    'cxl-enable-port.txt',

+    'cxl-disable-port.txt',

+ +  'cxl-disable-bus.txt',

+    'cxl-set-partition.txt',

+  ]

+  

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index 7bbad98..a437bc3 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -15,4 +15,5 @@ int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx);

+  #endif /* _CXL_BUILTIN_H_ */

+ diff --git a/cxl/bus.c b/cxl/bus.c

+ new file mode 100644

+ index 0000000..3321295

+ --- /dev/null

+ +++ b/cxl/bus.c

+ @@ -0,0 +1,159 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */

+ +#include <stdio.h>

+ +#include <errno.h>

+ +#include <stdlib.h>

+ +#include <unistd.h>

+ +#include <limits.h>

+ +#include <util/log.h>

+ +#include <cxl/libcxl.h>

+ +#include <util/parse-options.h>

+ +#include <ccan/minmax/minmax.h>

+ +#include <ccan/array_size/array_size.h>

+ +

+ +#include "filter.h"

+ +

+ +static struct parameters {

+ +	bool debug;

+ +	bool force;

+ +} param;

+ +

+ +static struct log_ctx bl;

+ +

+ +#define BASE_OPTIONS()                                                 \

+ +OPT_BOOLEAN(0, "debug", &param.debug, "turn on debug")

+ +

+ +#define DISABLE_OPTIONS()                                              \

+ +OPT_BOOLEAN('f', "force", &param.force,                                \

+ +	    "DANGEROUS: override active memdev safety checks")

+ +

+ +static const struct option disable_options[] = {

+ +	BASE_OPTIONS(),

+ +	DISABLE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static int action_disable(struct cxl_bus *bus)

+ +{

+ +	const char *devname = cxl_bus_get_devname(bus);

+ +	struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);

+ +	struct cxl_memdev *memdev;

+ +	int active_memdevs = 0;

+ +

+ +	cxl_memdev_foreach(ctx, memdev)

+ +		if (bus == cxl_memdev_get_bus(memdev))

+ +			active_memdevs++;

+ +

+ +	if (active_memdevs && !param.force) {

+ +		/*

+ +		 * TODO: actually detect rather than assume active just

+ +		 * because the memdev is enabled

+ +		 */

+ +		log_err(&bl,

+ +			"%s hosts %d memdev%s which %s part of an active region\n",

+ +			devname, active_memdevs, active_memdevs > 1 ? "s" : "",

+ +			active_memdevs > 1 ? "are" : "is");

+ +		log_err(&bl,

+ +			"See 'cxl list -M -b %s' to see impacted device%s\n",

+ +			devname, active_memdevs > 1 ? "s" : "");

+ +		return -EBUSY;

+ +	}

+ +

+ +	return cxl_bus_disable_invalidate(bus);

+ +}

+ +

+ +static struct cxl_bus *find_cxl_bus(struct cxl_ctx *ctx, const char *ident)

+ +{

+ +	struct cxl_bus *bus;

+ +

+ +	cxl_bus_foreach(ctx, bus)

+ +		if (util_cxl_bus_filter(bus, ident))

+ +			return bus;

+ +	return NULL;

+ +}

+ +

+ +static int bus_action(int argc, const char **argv, struct cxl_ctx *ctx,

+ +		      int (*action)(struct cxl_bus *bus),

+ +		      const struct option *options, const char *usage)

+ +{

+ +	int i, rc = 0, count = 0, err = 0;

+ +	const char * const u[] = {

+ +		usage,

+ +		NULL

+ +	};

+ +	unsigned long id;

+ +

+ +	log_init(&bl, "cxl bus", "CXL_PORT_LOG");

+ +	argc = parse_options(argc, argv, options, u, 0);

+ +

+ +	if (argc == 0)

+ +		usage_with_options(u, options);

+ +	for (i = 0; i < argc; i++) {

+ +		if (strcmp(argv[i], "all") == 0) {

+ +			argv[0] = "all";

+ +			argc = 1;

+ +			break;

+ +		}

+ +

+ +		if (sscanf(argv[i], "root%lu", &id) == 1)

+ +			continue;

+ +		if (sscanf(argv[i], "%lu", &id) == 1)

+ +			continue;

+ +

+ +		log_err(&bl, "'%s' is not a valid bus identifer\n", argv[i]);

+ +		err++;

+ +	}

+ +

+ +	if (err == argc) {

+ +		usage_with_options(u, options);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (param.debug) {

+ +		cxl_set_log_priority(ctx, LOG_DEBUG);

+ +		bl.log_priority = LOG_DEBUG;

+ +	} else

+ +		bl.log_priority = LOG_INFO;

+ +

+ +	rc = 0;

+ +	err = 0;

+ +	count = 0;

+ +

+ +	for (i = 0; i < argc; i++) {

+ +		struct cxl_bus *bus;

+ +

+ +		bus = find_cxl_bus(ctx, argv[i]);

+ +		if (!bus) {

+ +			log_dbg(&bl, "bus: %s not found\n", argv[i]);

+ +			continue;

+ +		}

+ +

+ +		log_dbg(&bl, "run action on bus: %s\n",

+ +			cxl_bus_get_devname(bus));

+ +		rc = action(bus);

+ +		if (rc == 0)

+ +			count++;

+ +		else if (rc && !err)

+ +			err = rc;

+ +	}

+ +	rc = err;

+ +

+ +	/*

+ +	 * count if some actions succeeded, 0 if none were attempted,

+ +	 * negative error code otherwise.

+ +	 */

+ +	if (count > 0)

+ +		return count;

+ +	return rc;

+ +}

+ +

+ + int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx)

+ + {

+ +	 int count = bus_action(

+ +		 argc, argv, ctx, action_disable, disable_options,

+ +		 "cxl disable-bus <bus0> [<bus1>..<busN>] [<options>]");

+ +

+ +	 log_info(&bl, "disabled %d bus%s\n", count >= 0 ? count : 0,

+ +		  count > 1 ? "s" : "");

+ +	 return count >= 0 ? 0 : EXIT_FAILURE;

+ + }

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index ab4bbec..aa4ce61 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -69,6 +69,7 @@ static struct cmd_struct commands[] = {

+  	{ "disable-port", .c_fn = cmd_disable_port },

+  	{ "enable-port", .c_fn = cmd_enable_port },

+  	{ "set-partition", .c_fn = cmd_set_partition },

+ +	{ "disable-bus", .c_fn = cmd_disable_bus },

+  };

+  

+  int main(int argc, const char **argv)

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index b339642..c6ab9eb 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -176,8 +176,7 @@ util_cxl_decoder_filter_by_port(struct cxl_decoder *decoder, const char *ident,

+  	return NULL;

+  }

+  

+ -static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,

+ -					   const char *__ident)

+ +struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident)

+  {

+  	char *ident, *save;

+  	const char *arg;

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 697b777..9557943 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -41,6 +41,7 @@ enum cxl_port_filter_mode {

+  

+  struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident,

+  				      enum cxl_port_filter_mode mode);

+ +struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident);

+  struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,

+  					      const char *__ident);

+  struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target,

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 59e1644..0e8dd20 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -556,6 +556,21 @@ static void bus_invalidate(struct cxl_bus *bus)

+  	cxl_flush(ctx);

+  }

+  

+ +CXL_EXPORT int cxl_bus_disable_invalidate(struct cxl_bus *bus)

+ +{

+ +	struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);

+ +	struct cxl_port *port = cxl_bus_get_port(bus);

+ +	int rc;

+ +

+ +	rc = util_unbind(port->uport, ctx);

+ +	if (rc)

+ +		return rc;

+ +

+ +	free_bus(bus, &ctx->buses);

+ +	cxl_flush(ctx);

+ +	return 0;

+ +}

+ +

+  CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)

+  {

+  	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index aab1112..dffcb60 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -86,6 +86,7 @@ global:

+  	cxl_bus_get_id;

+  	cxl_bus_get_port;

+  	cxl_bus_get_ctx;

+ +	cxl_bus_disable_invalidate;

+  	cxl_port_get_first;

+  	cxl_port_get_next;

+  	cxl_port_get_devname;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 0063d31..0007f4d 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -73,6 +73,7 @@ const char *cxl_bus_get_devname(struct cxl_bus *bus);

+  int cxl_bus_get_id(struct cxl_bus *bus);

+  struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);

+  struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus);

+ +int cxl_bus_disable_invalidate(struct cxl_bus *bus);

+  

+  #define cxl_bus_foreach(ctx, bus)                                              \

+  	for (bus = cxl_bus_get_first(ctx); bus != NULL;                        \

+ diff --git a/cxl/meson.build b/cxl/meson.build

+ index 671c8e1..d63dcb1 100644

+ --- a/cxl/meson.build

+ +++ b/cxl/meson.build

+ @@ -2,6 +2,7 @@ cxl_src = [

+    'cxl.c',

+    'list.c',

+    'port.c',

+ +  'bus.c',

+    'memdev.c',

+    'json.c',

+    'filter.c',

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,37 @@ 

+ From 2124f62aad2fcc00def36d119cfcdee22a7961e9 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:32 -0700

+ Subject: [PATCH 160/217] cxl/list: Auto-enable 'single' mode for port listings

+ 

+ The --single parameter instructs the filter code to gate listing of

+ ancestor ports. However, that behavior can be inferred by attempts to list

+ a port without the --ports option, i.e. make:

+ 

+     cxl list -p $port

+ 

+ ...equivalent to:

+ 

+     cxl list -P -S -p $port

+ 

+ Link: https://lore.kernel.org/r/165118383246.1676208.2097194779584921177.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/list.c | 1 +

+  1 file changed, 1 insertion(+)

+ 

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 1e9d441..940782d 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -104,6 +104,7 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  			error("please specify entities to list, e.g. using -m/-M\n");

+  			usage_with_options(u, options);

+  		}

+ +		param.single = true;

+  	}

+  

+  	log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,50 @@ 

+ From 2dbe3b45879ad614968a75392cb1ef9907d8648d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:37 -0700

+ Subject: [PATCH 161/217] cxl/memdev: Fix bus_invalidate() crash

+ 

+ bus_invalidate() attempts to limit the invalidation of memdevs to a single

+ bus scope. However, the ordering of bus_invalidate() leads to a use after

+ free. Unconditionally invalidate memdevs (disconnect memdevs from their

+ endpoints) and resotre on next lookup. Otherwise the following command

+ results in the following backtrace with cxl_test:

+ 

+     cxl disable-memdev 5,1 --force

+ 

+ #2  0x00007ffff7fb97d4 in snprintf (__fmt=0x7ffff7fbc3ed "%s/driver", __n=98,

+     __s=0x574d545619f7bae2 <error: Cannot access memory at address 0x574d545619f7bae2>)

+     at /usr/include/bits/stdio2.h:71

+ #3  cxl_port_is_enabled (port=port@entry=0x422eb0) at ../cxl/lib/libcxl.c:1379

+ #4  0x00007ffff7fb99a9 in cxl_port_get_bus (port=0x422eb0) at ../cxl/lib/libcxl.c:1339

+ #5  0x00007ffff7fba3d0 in bus_invalidate (bus=bus@entry=0x421740) at ../cxl/lib/libcxl.c:549

+ #6  0x00007ffff7fba4e7 in cxl_memdev_disable_invalidate (memdev=0x416fd0) at ../cxl/lib/libcxl.c:596

+ #7  0x000000000040624e in memdev_action (argc=<optimized out>, argv=<optimized out>, ctx=0x4152a0,

+     action=action@entry=0x406b70 <action_disable>, options=options@entry=0x40fca0 <disable_options>,

+     usage=usage@entry=0x40f4b0 "cxl disable-memdev <mem0> [<mem1>..<memN>] [<options>]")

+     at ../cxl/memdev.c:506

+ #8  0x0000000000406d57 in cmd_disable_memdev (argc=<optimized out>, argv=<optimized out>,

+ 

+ Link: https://lore.kernel.org/r/165118383756.1676208.5717187278816036969.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 3 +--

+  1 file changed, 1 insertion(+), 2 deletions(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 0e8dd20..374b0f1 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -546,8 +546,7 @@ static void bus_invalidate(struct cxl_bus *bus)

+  	 * indeterminate, delete them all and start over.

+  	 */

+  	cxl_memdev_foreach(ctx, memdev)

+ -		if (cxl_memdev_get_bus(memdev) == bus)

+ -			memdev->endpoint = NULL;

+ +		memdev->endpoint = NULL;

+  

+  	bus_port = cxl_bus_get_port(bus);

+  	list_for_each_safe(&bus_port->child_ports, port, _p, list)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,73 @@ 

+ From cf0e0586bf45fd7e4ab17ce2b234bf68995daca3 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:42 -0700

+ Subject: [PATCH 162/217] cxl/list: Add support for filtering by host

+  identifiers

+ 

+ Accept host device names as valid filters for memdevs, ports, and

+ endpoints.

+ 

+ # cxl list -u -m 7

+ {

+   "memdev":"mem7",

+   "pmem_size":"256.00 MiB (268.44 MB)",

+   "ram_size":"256.00 MiB (268.44 MB)",

+   "serial":"0x6",

+   "numa_node":0,

+   "host":"cxl_mem.6"

+ }

+ 

+ # cxl list -u -m cxl_mem.6

+ {

+   "memdev":"mem7",

+   "pmem_size":"256.00 MiB (268.44 MB)",

+   "ram_size":"256.00 MiB (268.44 MB)",

+   "serial":"0x6",

+   "numa_node":0,

+   "host":"cxl_mem.6"

+ }

+ 

+ Link: https://lore.kernel.org/r/165118384289.1676208.4779565283924668304.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/filter.c | 9 +++++++++

+  1 file changed, 9 insertions(+)

+ 

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index c6ab9eb..66fd742 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -73,6 +73,9 @@ struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint,

+  

+  		if (strcmp(arg, cxl_endpoint_get_devname(endpoint)) == 0)

+  			break;

+ +

+ +		if (strcmp(arg, cxl_endpoint_get_host(endpoint)) == 0)

+ +			break;

+  	}

+  

+  	free(ident);

+ @@ -116,6 +119,9 @@ static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,

+  

+  		if (strcmp(arg, cxl_port_get_devname(port)) == 0)

+  			break;

+ +

+ +		if (strcmp(arg, cxl_port_get_host(port)) == 0)

+ +			break;

+  	}

+  

+  	free(ident);

+ @@ -303,6 +309,9 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  

+  		if (strcmp(name, cxl_memdev_get_devname(memdev)) == 0)

+  			break;

+ +

+ +		if (strcmp(name, cxl_memdev_get_host(memdev)) == 0)

+ +			break;

+  	}

+  

+  	free(ident);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,92 @@ 

+ From e32631009a97e4cb72e4afb8eec09f89c3317eb9 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:48 -0700

+ Subject: [PATCH 163/217] cxl/port: Relax port identifier validation

+ 

+ Now that util_cxl_port_filter() accepts port host identifiers it is no

+ longer possible to pre-validate that the port arguments follow the "port%d"

+ format. Instead, let all inputs through and warn if the filter fails to

+ identify a port.

+ 

+ Link: https://lore.kernel.org/r/165118384845.1676208.7570620216888371408.stgit@dwillia2-desk3.amr.corp.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/port.c | 30 ++++--------------------------

+  1 file changed, 4 insertions(+), 26 deletions(-)

+ 

+ diff --git a/cxl/port.c b/cxl/port.c

+ index 46a8f32..89f3916 100644

+ --- a/cxl/port.c

+ +++ b/cxl/port.c

+ @@ -145,7 +145,6 @@ static int port_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  		usage,

+  		NULL

+  	};

+ -	unsigned long id;

+  

+  	log_init(&pl, "cxl port", "CXL_PORT_LOG");

+  	argc = parse_options(argc, argv, options, u, 0);

+ @@ -153,31 +152,10 @@ static int port_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	if (argc == 0)

+  		usage_with_options(u, options);

+  	for (i = 0; i < argc; i++) {

+ -		const char *fmt;

+ -

+  		if (strcmp(argv[i], "all") == 0) {

+  			argc = 1;

+  			break;

+  		}

+ -

+ -		if (param.endpoint)

+ -			fmt = "endpoint%lu";

+ -		else

+ -			fmt = "port%lu";

+ -

+ -		if (sscanf(argv[i], fmt, &id) == 1)

+ -			continue;

+ -		if (sscanf(argv[i], "%lu", &id) == 1)

+ -			continue;

+ -

+ -		log_err(&pl, "'%s' is not a valid %s identifer\n", argv[i],

+ -			param.endpoint ? "endpoint" : "port");

+ -		err++;

+ -	}

+ -

+ -	if (err == argc) {

+ -		usage_with_options(u, options);

+ -		return -EINVAL;

+  	}

+  

+  	if (param.debug) {

+ @@ -187,7 +165,6 @@ static int port_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  		pl.log_priority = LOG_INFO;

+  

+  	rc = 0;

+ -	err = 0;

+  	count = 0;

+  

+  	for (i = 0; i < argc; i++) {

+ @@ -198,15 +175,16 @@ static int port_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  

+  			endpoint = find_cxl_endpoint(ctx, argv[i]);

+  			if (!endpoint) {

+ -				log_dbg(&pl, "endpoint: %s not found\n",

+ -					argv[i]);

+ +				log_notice(&pl, "endpoint: %s not found\n",

+ +					   argv[i]);

+  				continue;

+  			}

+  			port = cxl_endpoint_get_port(endpoint);

+  		} else {

+  			port = find_cxl_port(ctx, argv[i]);

+  			if (!port) {

+ -				log_dbg(&pl, "port: %s not found\n", argv[i]);

+ +				log_notice(&pl, "port: %s not found\n",

+ +					   argv[i]);

+  				continue;

+  			}

+  		}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,236 @@ 

+ From ef85ab79e7a45d19ca329c6e4cad9881a5a904e9 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 15:10:54 -0700

+ Subject: [PATCH 165/217] cxl/test: Add topology enumeration and hotplug test

+ 

+ Test the re-plug of memdevs, switch ports, root ports, and bus objects.

+ 

+ Link: https://lore.kernel.org/r/165118385401.1676208.9224280236045777443.stgit@dwillia2-desk3.amr.corp.intel.com

+ Cc: Luis Chamberlain <mcgrof@kernel.org>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/common          |  12 ++++

+  test/cxl-topology.sh | 166 +++++++++++++++++++++++++++++++++++++++++++

+  test/meson.build     |   2 +

+  3 files changed, 180 insertions(+)

+  create mode 100644 test/cxl-topology.sh

+ 

+ diff --git a/test/common b/test/common

+ index fb48795..65615cc 100644

+ --- a/test/common

+ +++ b/test/common

+ @@ -27,6 +27,18 @@ if [ -z $DAXCTL ]; then

+  	fi

+  fi

+  

+ +# CXL

+ +if [ -z $CXL ]; then

+ +	if [ -f "../cxl/cxl" ] && [ -x "../cxl/cxl" ]; then

+ +		export CXL=../cxl/cxl

+ +	elif [ -f "./cxl/cxl" ] && [ -x "./cxl/cxl" ]; then

+ +		export CXL=./cxl/cxl

+ +	else

+ +		echo "Couldn't find a cxl binary"

+ +		exit 1

+ +	fi

+ +fi

+ +

+  if [ -z $TEST_PATH ]; then

+  	export TEST_PATH=.

+  fi

+ diff --git a/test/cxl-topology.sh b/test/cxl-topology.sh

+ new file mode 100644

+ index 0000000..ff11614

+ --- /dev/null

+ +++ b/test/cxl-topology.sh

+ @@ -0,0 +1,166 @@

+ +#!/bin/bash

+ +# SPDX-License-Identifier: GPL-2.0

+ +# Copyright (C) 2022 Intel Corporation. All rights reserved.

+ +

+ +. $(dirname $0)/common

+ +

+ +rc=1

+ +

+ +set -ex

+ +

+ +trap 'err $LINENO' ERR

+ +

+ +check_prereq "jq"

+ +

+ +modprobe -r cxl_test

+ +modprobe cxl_test

+ +udevadm settle

+ +

+ +# THEORY OF OPERATION: Validate the hard coded assumptions of the

+ +# cxl_test.ko module that defines its topology in

+ +# tools/testing/cxl/test/cxl.c. If that model ever changes then the

+ +# paired update must be made to this test.

+ +

+ +# collect cxl_test root device id

+ +json=$($CXL list -b cxl_test)

+ +count=$(jq "length" <<< $json)

+ +((count == 1)) || err "$LINENO"

+ +root=$(jq -r ".[] | .bus" <<< $json)

+ +

+ +

+ +# validate 2 host bridges under a root port

+ +port_sort="sort_by(.port | .[4:] | tonumber)"

+ +json=$($CXL list -b cxl_test -BP)

+ +count=$(jq ".[] | .[\"ports:$root\"] | length" <<< $json)

+ +((count == 2)) || err "$LINENO"

+ +

+ +bridge[0]=$(jq -r ".[] | .[\"ports:$root\"] | $port_sort | .[0].port" <<< $json)

+ +bridge[1]=$(jq -r ".[] | .[\"ports:$root\"] | $port_sort | .[1].port" <<< $json)

+ +

+ +

+ +# validate 2 root ports per host bridge

+ +json=$($CXL list -b cxl_test -T -p ${bridge[0]})

+ +count=$(jq ".[] | .dports | length" <<< $json)

+ +((count == 2)) || err "$LINENO"

+ +

+ +json=$($CXL list -b cxl_test -T -p ${bridge[1]})

+ +count=$(jq ".[] | .dports | length" <<< $json)

+ +((count == 2)) || err "$LINENO"

+ +

+ +

+ +# validate 2 switches per-root port

+ +json=$($CXL list -b cxl_test -P -p ${bridge[0]})

+ +count=$(jq ".[] | .[\"ports:${bridge[0]}\"] | length" <<< $json)

+ +((count == 2)) || err "$LINENO"

+ +

+ +switch[0]=$(jq -r ".[] | .[\"ports:${bridge[0]}\"] | $port_sort | .[0].host" <<< $json)

+ +switch[1]=$(jq -r ".[] | .[\"ports:${bridge[0]}\"] | $port_sort | .[1].host" <<< $json)

+ +

+ +json=$($CXL list -b cxl_test -P -p ${bridge[1]})

+ +count=$(jq ".[] | .[\"ports:${bridge[1]}\"] | length" <<< $json)

+ +((count == 2)) || err "$LINENO"

+ +

+ +switch[2]=$(jq -r ".[] | .[\"ports:${bridge[1]}\"] | $port_sort | .[0].host" <<< $json)

+ +switch[3]=$(jq -r ".[] | .[\"ports:${bridge[1]}\"] | $port_sort | .[1].host" <<< $json)

+ +

+ +

+ +# check that all 8 cxl_test memdevs are enabled by default and have a

+ +# pmem size of 256M

+ +json=$($CXL list -b cxl_test -M)

+ +count=$(jq "map(select(.pmem_size == $((256 << 20)))) | length" <<< $json)

+ +((count == 8)) || err "$LINENO"

+ +

+ +

+ +# validate the expected properties of the 4 root decoders

+ +json=$($CXL list -b cxl_test -D -d root)

+ +port_id=${root:4}

+ +port_id_len=${#port_id}

+ +decoder_sort="sort_by(.decoder | .[$((8+port_id_len)):] | tonumber)"

+ +count=$(jq "[ $decoder_sort | .[0] |

+ +	select(.volatile_capable == true) |

+ +	select(.size == $((256 << 20))) |

+ +	select(.nr_targets == 1) ] | length" <<< $json)

+ +((count == 1)) || err "$LINENO"

+ +

+ +count=$(jq "[ $decoder_sort | .[1] |

+ +	select(.volatile_capable == true) |

+ +	select(.size == $((512 << 20))) |

+ +	select(.nr_targets == 2) ] | length" <<< $json)

+ +((count == 1)) || err "$LINENO"

+ +

+ +count=$(jq "[ $decoder_sort | .[2] |

+ +	select(.pmem_capable == true) |

+ +	select(.size == $((256 << 20))) |

+ +	select(.nr_targets == 1) ] | length" <<< $json)

+ +((count == 1)) || err "$LINENO"

+ +

+ +count=$(jq "[ $decoder_sort | .[3] |

+ +	select(.pmem_capable == true) |

+ +	select(.size == $((512 << 20))) |

+ +	select(.nr_targets == 2) ] | length" <<< $json)

+ +((count == 1)) || err "$LINENO"

+ +

+ +# check that switch ports disappear after all of their memdevs have been

+ +# disabled, and return when the memdevs are enabled.

+ +for s in ${switch[@]}

+ +do

+ +	json=$($CXL list -M -p $s)

+ +	count=$(jq "length" <<< $json)

+ +	((count == 2)) || err "$LINENO"

+ +

+ +	mem[0]=$(jq -r ".[0] | .memdev" <<< $json)

+ +	mem[1]=$(jq -r ".[1] | .memdev" <<< $json)

+ +

+ +	$CXL disable-memdev ${mem[0]} --force

+ +	json=$($CXL list -p $s)

+ +	count=$(jq "length" <<< $json)

+ +	((count == 1)) || err "$LINENO"

+ +

+ +	$CXL disable-memdev ${mem[1]} --force

+ +	json=$($CXL list -p $s)

+ +	count=$(jq "length" <<< $json)

+ +	((count == 0)) || err "$LINENO"

+ +

+ +	$CXL enable-memdev ${mem[0]}

+ +	$CXL enable-memdev ${mem[1]}

+ +

+ +	json=$($CXL list -p $s)

+ +	count=$(jq "length" <<< $json)

+ +	((count == 1)) || err "$LINENO"

+ +

+ +	$CXL disable-port $s --force

+ +	json=$($CXL list -p $s)

+ +	count=$(jq "length" <<< $json)

+ +	((count == 0)) || err "$LINENO"

+ +

+ +	$CXL enable-memdev ${mem[0]} ${mem[1]}

+ +	json=$($CXL list -p $s)

+ +	count=$(jq "length" <<< $json)

+ +	((count == 1)) || err "$LINENO"

+ +done

+ +

+ +

+ +# validate host bridge tear down

+ +for b in ${bridge[@]}

+ +do

+ +	$CXL disable-port $b -f

+ +	json=$($CXL list -M -i -p $b)

+ +	count=$(jq "map(select(.state == \"disabled\")) | length" <<< $json)

+ +	((count == 4)) || err "$LINENO"

+ +

+ +	$CXL enable-port $b -m

+ +	json=$($CXL list -M -p $b)

+ +	count=$(jq "length" <<< $json)

+ +	((count == 4)) || err "$LINENO"

+ +done

+ +

+ +

+ +# validate that the bus can be disabled without issue

+ +$CXL disable-bus $root -f

+ +

+ +

+ +# validate no WARN or lockdep report during the run

+ +log=$(journalctl -r -k --since "-$((SECONDS+1))s")

+ +grep -q "Call Trace" <<< $log && err "$LINENO"

+ +

+ +modprobe -r cxl_test

+ diff --git a/test/meson.build b/test/meson.build

+ index 7ccd451..210dcb0 100644

+ --- a/test/meson.build

+ +++ b/test/meson.build

+ @@ -150,6 +150,7 @@ monitor = find_program('monitor.sh')

+  max_extent = find_program('max_available_extent_ns.sh')

+  pfn_meta_errors = find_program('pfn-meta-errors.sh')

+  track_uuid = find_program('track-uuid.sh')

+ +cxl_topo = find_program('cxl-topology.sh')

+  

+  tests = [

+    [ 'libndctl',               libndctl,		  'ndctl' ],

+ @@ -174,6 +175,7 @@ tests = [

+    [ 'max_extent_ns',          max_extent,	  'ndctl' ],

+    [ 'pfn-meta-errors.sh',     pfn_meta_errors,	  'ndctl' ],

+    [ 'track-uuid.sh',          track_uuid,	  'ndctl' ],

+ +  [ 'cxl-topology.sh',	      cxl_topo,		  'cxl'   ],

+  ]

+  

+  if get_option('destructive').enabled()

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,32 @@ 

+ From 4bd100a8c97cfd9592be74af2e4699a2ab6d2f34 Mon Sep 17 00:00:00 2001

+ From: Michal Suchanek <msuchanek@suse.de>

+ Date: Thu, 10 Mar 2022 14:30:35 +0100

+ Subject: [PATCH 167/217] daxctl: Fix kernel option typo in "Soft Reservation"

+  theory of operation

+ 

+ Link: https://lore.kernel.org/r/20220310133035.GA106666@kunlun.suse.cz

+ Fixes: 8f4e42c ("daxctl: Add "Soft Reservation" theory of operation")

+ Signed-off-by: Michal Suchanek <msuchanek@suse.de>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/daxctl/daxctl-reconfigure-device.txt | 4 ++--

+  1 file changed, 2 insertions(+), 2 deletions(-)

+ 

+ diff --git a/Documentation/daxctl/daxctl-reconfigure-device.txt b/Documentation/daxctl/daxctl-reconfigure-device.txt

+ index 385c0c5..09691d2 100644

+ --- a/Documentation/daxctl/daxctl-reconfigure-device.txt

+ +++ b/Documentation/daxctl/daxctl-reconfigure-device.txt

+ @@ -91,8 +91,8 @@ details.

+  Outside of the NUMA performance details linked above the other method to

+  detect the presence of "Soft Reserved" memory is to dump /proc/iomem and

+  look for "Soft Reserved" ranges. If the kernel was not built with

+ -CONFIG_EFI_SOFTRESERVE, predates the introduction of

+ -CONFIG_EFI_SOFTRESERVE (v5.5), or was booted with the efi=nosoftreserve

+ +CONFIG_EFI_SOFT_RESERVE, predates the introduction of

+ +CONFIG_EFI_SOFT_RESERVE (v5.5), or was booted with the efi=nosoftreserve

+  command line then device-dax will not attach and the expectation is that

+  the memory shows up as a memory-only NUMA node. Otherwise the memory

+  shows up as a device-dax instance and DAXCTL(1) can be used to

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,38 @@ 

+ From 524ad09d5eda320b299468324a2f94fc1802ef00 Mon Sep 17 00:00:00 2001

+ From: Michal Suchanek <msuchanek@suse.de>

+ Date: Thu, 10 Mar 2022 14:30:55 +0100

+ Subject: [PATCH 168/217] meson: make modprobedatadir an option

+ 

+ The modprobe.d directory location is hardcoded.

+ 

+ Link: https://lore.kernel.org/r/20220310133055.GA106731@kunlun.suse.cz

+ Fixes: 4e5faa1 ("build: Add meson build infrastructure")

+ Signed-off-by: Michal Suchanek <msuchanek@suse.de>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  contrib/meson.build | 5 ++++-

+  meson_options.txt   | 2 ++

+  2 files changed, 6 insertions(+), 1 deletion(-)

+ 

+ diff -up ndctl-71.1/contrib/meson.build.orig ndctl-71.1/contrib/meson.build

+ --- ndctl-71.1/contrib/meson.build.orig	2022-10-07 16:42:24.750025016 -0400

+ +++ ndctl-71.1/contrib/meson.build	2022-10-07 16:42:39.374074806 -0400

+ @@ -24,5 +24,8 @@ if bashcompletiondir != 'no'

+    install_data('ndctl', rename : 'cxl', install_dir : bashcompletiondir)

+  endif

+  

+ -modprobedatadir = get_option('sysconfdir') + '/modprobe.d/'

+ +modprobedatadir = get_option('modprobedatadir')

+ +if modprobedatadir == ''

+ +  modprobedatadir = get_option('modprobedatadir')

+ +endif

+  install_data('nvdimm-security.conf', install_dir : modprobedatadir)

+ diff -up ndctl-71.1/meson_options.txt.orig ndctl-71.1/meson_options.txt

+ --- ndctl-71.1/meson_options.txt.orig	2022-10-07 16:42:39.375074810 -0400

+ +++ ndctl-71.1/meson_options.txt	2022-10-07 16:43:10.553180961 -0400

+ @@ -23,3 +23,5 @@ option('pkgconfiglibdir', type : 'string

+         description : 'directory for standard pkg-config files')

+  option('bashcompletiondir', type : 'string',

+         description : '''${datadir}/bash-completion/completions''')

+ +option('modprobedatadir', type : 'string',

+ +       description : '''${sysconfdir}/modprobe.d/''')

@@ -0,0 +1,116 @@ 

+ From 2f3851912624e9ede3132cd3749b4f60a348b1d4 Mon Sep 17 00:00:00 2001

+ From: Michal Suchanek <msuchanek@suse.de>

+ Date: Thu, 10 Mar 2022 14:31:06 +0100

+ Subject: [PATCH 169/217] namespace-action: Drop more zero namespace checks

+ 

+ With seed namespaces caught early on with

+ commit 9bd2994 ("ndctl/namespace: Skip seed namespaces when processing all namespaces.")

+ commit 07011a3 ("ndctl/namespace: Suppress -ENXIO when processing all namespaces.")

+ the function-specific checks are no longer needed and can be dropped.

+ 

+ Reverts commit fb13dfb ("zero_info_block: skip seed devices")

+ Reverts commit fe626a8 ("ndctl/namespace: Fix disable-namespace accounting relative to seed devices")

+ 

+ Link: https://lore.kernel.org/r/20220310133106.GA106734@kunlun.suse.cz

+ Fixes: 80e0d88 ("namespace-action: Drop zero namespace checks.")

+ Fixes: fb13dfb ("zero_info_block: skip seed devices")

+ Fixes: fe626a8 ("ndctl/namespace: Fix disable-namespace accounting relative to seed devices")

+ Signed-off-by: Michal Suchanek <msuchanek@suse.de>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c |  7 +------

+  ndctl/namespace.c    | 11 ++++-------

+  ndctl/region.c       |  2 +-

+  3 files changed, 6 insertions(+), 14 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index ccca8b5..110d8a5 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -4593,7 +4593,6 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)

+  	const char *bdev = NULL;

+  	int fd, active = 0;

+  	char path[50];

+ -	unsigned long long size = ndctl_namespace_get_size(ndns);

+  

+  	if (pfn && ndctl_pfn_is_enabled(pfn))

+  		bdev = ndctl_pfn_get_block_device(pfn);

+ @@ -4630,11 +4629,7 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)

+  				devname);

+  		return -EBUSY;

+  	} else {

+ -		if (size == 0)

+ -			/* No disable necessary due to no capacity allocated */

+ -			return 1;

+ -		else

+ -			ndctl_namespace_disable_invalidate(ndns);

+ +		ndctl_namespace_disable_invalidate(ndns);

+  	}

+  

+  	return 0;

+ diff --git a/ndctl/namespace.c b/ndctl/namespace.c

+ index 257b58c..722f13a 100644

+ --- a/ndctl/namespace.c

+ +++ b/ndctl/namespace.c

+ @@ -1054,9 +1054,6 @@ static int zero_info_block(struct ndctl_namespace *ndns)

+  	void *buf = NULL, *read_buf = NULL;

+  	char path[50];

+  

+ -	if (ndctl_namespace_get_size(ndns) == 0)

+ -		return 1;

+ -

+  	ndctl_namespace_set_raw_mode(ndns, 1);

+  	rc = ndctl_namespace_enable(ndns);

+  	if (rc < 0) {

+ @@ -1130,7 +1127,7 @@ static int namespace_prep_reconfig(struct ndctl_region *region,

+  	}

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc < 0)

+ +	if (rc)

+  		return rc;

+  

+  	ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_RAW);

+ @@ -1426,7 +1423,7 @@ static int dax_clear_badblocks(struct ndctl_dax *dax)

+  		return -ENXIO;

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc < 0) {

+ +	if (rc) {

+  		error("%s: unable to disable namespace: %s\n", devname,

+  			strerror(-rc));

+  		return rc;

+ @@ -1450,7 +1447,7 @@ static int pfn_clear_badblocks(struct ndctl_pfn *pfn)

+  		return -ENXIO;

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc < 0) {

+ +	if (rc) {

+  		error("%s: unable to disable namespace: %s\n", devname,

+  			strerror(-rc));

+  		return rc;

+ @@ -1473,7 +1470,7 @@ static int raw_clear_badblocks(struct ndctl_namespace *ndns)

+  		return -ENXIO;

+  

+  	rc = ndctl_namespace_disable_safe(ndns);

+ -	if (rc < 0) {

+ +	if (rc) {

+  		error("%s: unable to disable namespace: %s\n", devname,

+  			strerror(-rc));

+  		return rc;

+ diff --git a/ndctl/region.c b/ndctl/region.c

+ index e499546..33828b0 100644

+ --- a/ndctl/region.c

+ +++ b/ndctl/region.c

+ @@ -71,7 +71,7 @@ static int region_action(struct ndctl_region *region, enum device_action mode)

+  	case ACTION_DISABLE:

+  		ndctl_namespace_foreach(region, ndns) {

+  			rc = ndctl_namespace_disable_safe(ndns);

+ -			if (rc < 0)

+ +			if (rc)

+  				return rc;

+  		}

+  		rc = ndctl_region_disable_invalidate(region);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,94 @@ 

+ From 8186ec87dcd1b347ab0ee27ec5e87bda8c9a67e2 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 28 Apr 2022 16:54:48 -0700

+ Subject: [PATCH 170/217] ndctl/dimm: Flush invalidated labels after overwrite

+ 

+ Similar to "ndctl write-labels", after "ndctl sanitize-dimm --overwrite"

+ the kernel may contain a cached copy of the label area that has been

+ invalidated by the overwrite. Toggle the enabled state of the dimm-device

+ to trigger the kernel to release the cached copy.

+ 

+ Link: https://lore.kernel.org/all/165118817010.1772793.5101398830527716084.stgit@dwillia2-desk3.amr.corp.intel.com/

+ Link: https://lore.kernel.org/r/165119008839.1783158.3766085644383173318.stgit@dwillia2-desk3.amr.corp.intel.com

+ Cc: Jeff Moyer <jmoyer@redhat.com>

+ Cc: Dave Jiang <dave.jiang@intel.com>

+ Acked-by: Jeff Moyer <jmoyer@redhat.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/dimm.c | 34 ++++++++++++++++++++++------------

+  1 file changed, 22 insertions(+), 12 deletions(-)

+ 

+ diff --git a/ndctl/dimm.c b/ndctl/dimm.c

+ index d9718a3..ac7c527 100644

+ --- a/ndctl/dimm.c

+ +++ b/ndctl/dimm.c

+ @@ -354,6 +354,23 @@ static int rw_bin(FILE *f, struct ndctl_cmd *cmd, ssize_t size,

+  	return 0;

+  }

+  

+ +static int revalidate_labels(struct ndctl_dimm *dimm)

+ +{

+ +	int rc;

+ +

+ +	/*

+ +	 * If the dimm is already disabled the kernel is not holding a cached

+ +	 * copy of the label space.

+ +	 */

+ +	if (!ndctl_dimm_is_enabled(dimm))

+ +		return 0;

+ +

+ +	rc = ndctl_dimm_disable(dimm);

+ +	if (rc)

+ +		return rc;

+ +	return ndctl_dimm_enable(dimm);

+ +}

+ +

+  static int action_write(struct ndctl_dimm *dimm, struct action_context *actx)

+  {

+  	struct ndctl_cmd *cmd_read, *cmd_write;

+ @@ -377,18 +394,10 @@ static int action_write(struct ndctl_dimm *dimm, struct action_context *actx)

+  

+  	size = ndctl_cmd_cfg_read_get_size(cmd_read);

+  	rc = rw_bin(actx->f_in, cmd_write, size, param.offset, WRITE);

+ -

+ -	/*

+ -	 * If the dimm is already disabled the kernel is not holding a cached

+ -	 * copy of the label space.

+ -	 */

+ -	if (!ndctl_dimm_is_enabled(dimm))

+ -		goto out;

+ -

+ -	rc = ndctl_dimm_disable(dimm);

+  	if (rc)

+  		goto out;

+ -	rc = ndctl_dimm_enable(dimm);

+ +

+ +	rc = revalidate_labels(dimm);

+  

+   out:

+  	ndctl_cmd_unref(cmd_read);

+ @@ -1043,7 +1052,7 @@ static int action_security_freeze(struct ndctl_dimm *dimm,

+  static int action_sanitize_dimm(struct ndctl_dimm *dimm,

+  		struct action_context *actx)

+  {

+ -	int rc;

+ +	int rc = 0;

+  	enum ndctl_key_type key_type;

+  

+  	if (ndctl_dimm_get_security(dimm) < 0) {

+ @@ -1085,9 +1094,10 @@ static int action_sanitize_dimm(struct ndctl_dimm *dimm,

+  		rc = ndctl_dimm_overwrite_key(dimm);

+  		if (rc < 0)

+  			return rc;

+ +		rc = revalidate_labels(dimm);

+  	}

+  

+ -	return 0;

+ +	return rc;

+  }

+  

+  static int action_wait_overwrite(struct ndctl_dimm *dimm,

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,45 @@ 

+ From 50e7a021314aa0365c9c85a359a31f26313fe93b Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 2 Jun 2022 09:44:27 -0600

+ Subject: [PATCH 171/217] libcxl: fix a segfault when memdev->pmem is absent

+ 

+ A CXL memdev may not have any persistent capacity, and in this case it

+ is possible that a 'pmem' object never gets instantiated. Such a

+ scenario would cause free_pmem () to dereference a NULL pointer and

+ segfault.

+ 

+ Fix this by only proceeding in free_pmem() if 'pmem' was valid.

+ 

+ Link: https://lore.kernel.org/r/20220602154427.462852-1-vishal.l.verma@intel.com

+ Fixes: cd1aed6cefe8 ("libcxl: add representation for an nvdimm bridge object")

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reported-by: Steven Garcia <steven.garcia@intel.com>

+ Tested-by: Steven Garcia <steven.garcia@intel.com>

+ Reviewed-by: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 8 +++++---

+  1 file changed, 5 insertions(+), 3 deletions(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 374b0f1..c988ce2 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -49,9 +49,11 @@ struct cxl_ctx {

+  

+  static void free_pmem(struct cxl_pmem *pmem)

+  {

+ -	free(pmem->dev_buf);

+ -	free(pmem->dev_path);

+ -	free(pmem);

+ +	if (pmem) {

+ +		free(pmem->dev_buf);

+ +		free(pmem->dev_path);

+ +		free(pmem);

+ +	}

+  }

+  

+  static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,83 @@ 

+ From 3e17210345482ec9795f1046c766564d3b8a0795 Mon Sep 17 00:00:00 2001

+ From: Tarun Sahu <tsahu@linux.ibm.com>

+ Date: Mon, 2 May 2022 12:34:54 +0530

+ Subject: [PATCH 172/217] ndctl/bus: Handle missing scrub commands more

+  gracefully

+ 

+ Buses that don't have nfit support return "No such file or directory"

+ for start-scrub/wait-scrub command.

+ 

+ Presently, non-nfit support buses do not support start-scrub/ wait-scrub

+ operation. This patch is to handle these commands more gracefully by

+ returning" Operation not supported".

+ 

+ This has been tested on PPC64le lpar with nvdimm that does not support

+ scrub.

+ 

+ Previously:

+   $ ./ndctl start-scrub ndbus0

+   error starting scrub: No such file or directory

+ 

+ Now:

+   $ ./ndctl start-scrub ndbus0

+   error starting scrub: Operation not supported

+ 

+ - Invalid ndbus

+   $ sudo ./ndctl start-scrub ndbus5

+   error starting scrub: No such device or address

+ 

+ Link: https://lore.kernel.org/r/20220502070454.179153-1-tsahu@linux.ibm.com

+ Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Reviewed-by: Vaibhav Jain <vaibhav@linux.ibm.com>

+ Signed-off-by: Tarun Sahu <tsahu@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ndctl/lib/libndctl.c | 18 ++++++++++++++----

+  1 file changed, 14 insertions(+), 4 deletions(-)

+ 

+ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c

+ index 110d8a5..ad54f06 100644

+ --- a/ndctl/lib/libndctl.c

+ +++ b/ndctl/lib/libndctl.c

+ @@ -938,10 +938,14 @@ static void *add_bus(void *parent, int id, const char *ctl_base)

+  	if (!bus->wait_probe_path)

+  		goto err_read;

+  

+ -	sprintf(path, "%s/device/nfit/scrub", ctl_base);

+ -	bus->scrub_path = strdup(path);

+ -	if (!bus->scrub_path)

+ -		goto err_read;

+ +	if (ndctl_bus_has_nfit(bus)) {

+ +		sprintf(path, "%s/device/nfit/scrub", ctl_base);

+ +		bus->scrub_path = strdup(path);

+ +		if (!bus->scrub_path)

+ +			goto err_read;

+ +	} else {

+ +		bus->scrub_path = NULL;

+ +	}

+  

+  	sprintf(path, "%s/device/firmware/activate", ctl_base);

+  	if (sysfs_read_attr(ctx, path, buf) < 0)

+ @@ -1377,6 +1381,9 @@ NDCTL_EXPORT int ndctl_bus_start_scrub(struct ndctl_bus *bus)

+  	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);

+  	int rc;

+  

+ +	if (bus->scrub_path == NULL)

+ +		return -EOPNOTSUPP;

+ +

+  	rc = sysfs_write_attr(ctx, bus->scrub_path, "1\n");

+  

+  	/*

+ @@ -1447,6 +1454,9 @@ NDCTL_EXPORT int ndctl_bus_poll_scrub_completion(struct ndctl_bus *bus,

+  	char in_progress;

+  	int fd = 0, rc;

+  

+ +	if (bus->scrub_path == NULL)

+ +		return -EOPNOTSUPP;

+ +

+  	fd = open(bus->scrub_path, O_RDONLY|O_CLOEXEC);

+  	if (fd < 0)

+  		return -errno;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,58 @@ 

+ From bbb2cb56f08d95ecf2c7c047a33cc3dd64eb7fde Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Thu, 16 Jun 2022 13:35:29 -0600

+ Subject: [PATCH 173/217] util/wrapper.c: Fix gcc warning in xrealloc()

+ MIME-Version: 1.0

+ Content-Type: text/plain; charset=UTF-8

+ Content-Transfer-Encoding: 8bit

+ 

+ A GCC update (12.1.1) now produces a warning in the xrealloc() wrapper

+ (originally copied from git, and used in strbuf operations):

+ 

+   ../util/wrapper.c: In function ‘xrealloc’:

+   ../util/wrapper.c:34:31: warning: pointer ‘ptr’ may be used after ‘realloc’ [-Wuse-after-free]

+      34 |                         ret = realloc(ptr, 1);

+         |                               ^~~~~~~~~~~~~~~

+ 

+ Pull in an updated definition for xrealloc() from the git project to fix this.

+ 

+ Link: https://lore.kernel.org/r/20220616193529.56513-1-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  util/wrapper.c | 18 +++++++++---------

+  1 file changed, 9 insertions(+), 9 deletions(-)

+ 

+ diff --git a/util/wrapper.c b/util/wrapper.c

+ index 026a54f..6adfde6 100644

+ --- a/util/wrapper.c

+ +++ b/util/wrapper.c

+ @@ -25,15 +25,15 @@ char *xstrdup(const char *str)

+  

+  void *xrealloc(void *ptr, size_t size)

+  {

+ -	void *ret = realloc(ptr, size);

+ -	if (!ret && !size)

+ -		ret = realloc(ptr, 1);

+ -	if (!ret) {

+ -		ret = realloc(ptr, size);

+ -		if (!ret && !size)

+ -			ret = realloc(ptr, 1);

+ -		if (!ret)

+ -			die("Out of memory, realloc failed");

+ +	void *ret;

+ +

+ +	if (!size) {

+ +		free(ptr);

+ +		return malloc(1);

+  	}

+ +

+ +	ret = realloc(ptr, size);

+ +	if (!ret)

+ +		die("Out of memory, realloc failed");

+  	return ret;

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,31 @@ 

+ From 29a9e9daa67e2b68bb2433c31fdbc82e86b5f0fe Mon Sep 17 00:00:00 2001

+ From: Shivaprasad G Bhat <sbhat@linux.ibm.com>

+ Date: Mon, 18 Jul 2022 13:53:35 +0530

+ Subject: [PATCH 174/217] libcxl: Fix memory leakage in cxl_port_init()

+ 

+ The local variable 'path' is not freed in cxl_port_init() for success case.

+ The patch fixes that.

+ 

+ Link: https://lore.kernel.org/r/165813258358.95191.6678871197554236554.stgit@LAPTOP-TBQTPII8

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Shivaprasad G Bhat <sbhat@linux.ibm.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 1 +

+  1 file changed, 1 insertion(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index c988ce2..bf3568d 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -769,6 +769,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,

+  	if (sysfs_read_attr(ctx, path, buf) == 0)

+  		port->module = util_modalias_to_module(ctx, buf);

+  

+ +	free(path);

+  	return 0;

+  err:

+  	free(port->dev_path);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,47 @@ 

+ From 6a843797767868279a5197699a53154bbed5eb2a Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:01:52 -0700

+ Subject: [PATCH 175/217] cxl/list: Reformat option list

+ 

+ Cleanup some spurious spaces and let clang-format re-layout the options.

+ 

+ Link: https://lore.kernel.org/r/165781811294.1555691.6271986101970794441.stgit@dwillia2-xfh.jf.intel.com

+ Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/list.c | 9 ++++-----

+  1 file changed, 4 insertions(+), 5 deletions(-)

+ 

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 940782d..1b5f583 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -36,8 +36,7 @@ static const struct option options[] = {

+  		   "filter by CXL endpoint device name(s)"),

+  	OPT_BOOLEAN('E', "endpoints", &param.endpoints,

+  		    "include CXL endpoint info"),

+ -	OPT_STRING('d', "decoder", &param.decoder_filter,

+ -		   "decoder device name",

+ +	OPT_STRING('d', "decoder", &param.decoder_filter, "decoder device name",

+  		   "filter by CXL decoder device name(s) / class"),

+  	OPT_BOOLEAN('D', "decoders", &param.decoders,

+  		    "include CXL decoder info"),

+ @@ -45,11 +44,11 @@ static const struct option options[] = {

+  		    "include CXL target data with decoders or ports"),

+  	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+  	OPT_BOOLEAN('u', "human", &param.human,

+ -		    "use human friendly number formats "),

+ +		    "use human friendly number formats"),

+  	OPT_BOOLEAN('H', "health", &param.health,

+ -		    "include memory device health information "),

+ +		    "include memory device health information"),

+  	OPT_BOOLEAN('I', "partition", &param.partition,

+ -		    "include memory device partition information "),

+ +		    "include memory device partition information"),

+  #ifdef ENABLE_DEBUG

+  	OPT_BOOLEAN(0, "debug", &debug, "debug list walk"),

+  #endif

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,46 @@ 

+ From b4262c8e65a4f5aa931b5451535084297968949d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:01:58 -0700

+ Subject: [PATCH 176/217] cxl/list: Emit endpoint decoders filtered by memdev

+ 

+ For example, dump all the endpoint decoders from memdev 'mem8'.

+ 

+     cxl list -Di -m 8 -d endpoint

+ 

+ Link: https://lore.kernel.org/r/165781811836.1555691.1997564050287016121.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/filter.c | 8 ++++++++

+  1 file changed, 8 insertions(+)

+ 

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 66fd742..2f88a9d 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -428,7 +428,9 @@ util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,

+  				  const char *ident, const char *serial)

+  {

+  	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	struct cxl_endpoint *endpoint;

+  	struct cxl_memdev *memdev;

+ +	struct cxl_port *port;

+  

+  	if (!ident && !serial)

+  		return decoder;

+ @@ -438,6 +440,12 @@ util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,

+  			continue;

+  		if (cxl_decoder_get_target_by_memdev(decoder, memdev))

+  			return decoder;

+ +		port = cxl_decoder_get_port(decoder);

+ +		if (!port || !cxl_port_is_endpoint(port))

+ +			continue;

+ +		endpoint = cxl_port_to_endpoint(port);

+ +		if (cxl_endpoint_get_memdev(endpoint) == memdev)

+ +			return decoder;

+  	}

+  

+  	return NULL;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,59 @@ 

+ From f649df38298043f68e73bc730ccb824de045f42d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:04 -0700

+ Subject: [PATCH 177/217] cxl/list: Hide 0s in disabled decoder listings

+ 

+ Trim some redundant information from decoder listings when they are

+ disabled.

+ 

+ Link: https://lore.kernel.org/r/165781812427.1555691.5252994293073680408.stgit@dwillia2-xfh.jf.intel.com

+ Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/json.c | 12 ++++++------

+  1 file changed, 6 insertions(+), 6 deletions(-)

+ 

+ diff --git a/cxl/json.c b/cxl/json.c

+ index fdc6f73..a213fda 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -442,7 +442,7 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	const char *devname = cxl_decoder_get_devname(decoder);

+  	struct cxl_port *port = cxl_decoder_get_port(decoder);

+  	struct json_object *jdecoder, *jobj;

+ -	u64 val;

+ +	u64 val, size;

+  

+  	jdecoder = json_object_new_object();

+  	if (!jdecoder)

+ @@ -452,21 +452,21 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	if (jobj)

+  		json_object_object_add(jdecoder, "decoder", jobj);

+  

+ +	size = cxl_decoder_get_size(decoder);

+  	val = cxl_decoder_get_resource(decoder);

+ -	if (val < ULLONG_MAX) {

+ +	if (size && val < ULLONG_MAX) {

+  		jobj = util_json_object_hex(val, flags);

+  		if (jobj)

+  			json_object_object_add(jdecoder, "resource", jobj);

+  	}

+  

+ -	val = cxl_decoder_get_size(decoder);

+ -	if (val < ULLONG_MAX) {

+ -		jobj = util_json_object_size(val, flags);

+ +	if (size && size < ULLONG_MAX) {

+ +		jobj = util_json_object_size(size, flags);

+  		if (jobj)

+  			json_object_object_add(jdecoder, "size", jobj);

+  	}

+  

+ -	if (val == 0) {

+ +	if (size == 0) {

+  		jobj = json_object_new_string("disabled");

+  		if (jobj)

+  			json_object_object_add(jdecoder, "state", jobj);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,167 @@ 

+ From bbc0da95d12b3c890cc323a34b48cf489d4b467a Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:09 -0700

+ Subject: [PATCH 178/217] cxl/list: Add DPA span to endpoint decoder listings

+ 

+ Optionally include in decoder listings the device local address space for

+ endpoint decoders with active / allocated capacity.

+ 

+ Link: https://lore.kernel.org/r/165781812967.1555691.4685129673233918478.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  2 ++

+  cxl/json.c                       | 18 +++++++++++++

+  cxl/lib/libcxl.c                 | 43 +++++++++++++++++++++++++++++++-

+  cxl/lib/libcxl.sym               |  6 +++++

+  cxl/lib/private.h                |  2 ++

+  cxl/libcxl.h                     |  2 ++

+  6 files changed, 72 insertions(+), 1 deletion(-)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index f8f0e66..2aef489 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -392,6 +392,8 @@ more CXL decoder objects.

+  ----

+  unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);

+ +unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder);

+ +unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder);

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+  int cxl_decoder_get_id(struct cxl_decoder *decoder);

+  int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);

+ diff --git a/cxl/json.c b/cxl/json.c

+ index a213fda..3f52d3b 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -472,6 +472,24 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  			json_object_object_add(jdecoder, "state", jobj);

+  	}

+  

+ +	if (cxl_port_is_endpoint(port)) {

+ +		size = cxl_decoder_get_dpa_size(decoder);

+ +		val = cxl_decoder_get_dpa_resource(decoder);

+ +		if (size && val < ULLONG_MAX) {

+ +			jobj = util_json_object_hex(val, flags);

+ +			if (jobj)

+ +				json_object_object_add(jdecoder, "dpa_resource",

+ +						       jobj);

+ +		}

+ +

+ +		if (size && size < ULLONG_MAX) {

+ +			jobj = util_json_object_size(size, flags);

+ +			if (jobj)

+ +				json_object_object_add(jdecoder, "dpa_size",

+ +						       jobj);

+ +		}

+ +	}

+ +

+  	if (cxl_port_is_root(port) && cxl_decoder_is_mem_capable(decoder)) {

+  		if (cxl_decoder_is_pmem_capable(decoder)) {

+  			jobj = json_object_new_boolean(true);

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index bf3568d..6f4d64d 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -956,8 +956,19 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  		decoder->size = strtoull(buf, NULL, 0);

+  

+  	switch (port->type) {

+ -	case CXL_PORT_SWITCH:

+  	case CXL_PORT_ENDPOINT:

+ +		sprintf(path, "%s/dpa_resource", cxldecoder_base);

+ +		if (sysfs_read_attr(ctx, path, buf) < 0)

+ +			decoder->dpa_resource = ULLONG_MAX;

+ +		else

+ +			decoder->dpa_resource = strtoull(buf, NULL, 0);

+ +		sprintf(path, "%s/dpa_size", cxldecoder_base);

+ +		if (sysfs_read_attr(ctx, path, buf) < 0)

+ +			decoder->dpa_size = ULLONG_MAX;

+ +		else

+ +			decoder->dpa_size = strtoull(buf, NULL, 0);

+ +

+ +	case CXL_PORT_SWITCH:

+  		decoder->pmem_capable = true;

+  		decoder->volatile_capable = true;

+  		decoder->mem_capable = true;

+ @@ -1114,6 +1125,36 @@ CXL_EXPORT unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder)

+  	return decoder->size;

+  }

+  

+ +CXL_EXPORT unsigned long long

+ +cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +

+ +	if (!cxl_port_is_endpoint(port)) {

+ +		err(ctx, "%s: not an endpoint decoder\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return ULLONG_MAX;

+ +	}

+ +

+ +	return decoder->dpa_resource;

+ +}

+ +

+ +CXL_EXPORT unsigned long long

+ +cxl_decoder_get_dpa_size(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +

+ +	if (!cxl_port_is_endpoint(port)) {

+ +		err(ctx, "%s: not an endpoint decoder\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return ULLONG_MAX;

+ +	}

+ +

+ +	return decoder->dpa_size;

+ +}

+ +

+  CXL_EXPORT enum cxl_decoder_target_type

+  cxl_decoder_get_target_type(struct cxl_decoder *decoder)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index dffcb60..8e2fc75 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -167,3 +167,9 @@ global:

+  	cxl_cmd_new_set_partition;

+  	cxl_cmd_partition_set_mode;

+  } LIBCXL_1;

+ +

+ +LIBCXL_3 {

+ +global:

+ +	cxl_decoder_get_dpa_resource;

+ +	cxl_decoder_get_dpa_size;

+ +} LIBCXL_2;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index c6d88f7..24a2ae6 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -101,6 +101,8 @@ struct cxl_decoder {

+  	struct cxl_ctx *ctx;

+  	u64 start;

+  	u64 size;

+ +	u64 dpa_resource;

+ +	u64 dpa_size;

+  	void *dev_buf;

+  	size_t buf_len;

+  	char *dev_path;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 0007f4d..76aebe3 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -129,6 +129,8 @@ struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);

+  struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);

+ +unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder);

+ +unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder);

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+  struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,

+  						    struct cxl_memdev *memdev);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,459 @@ 

+ From aaf1059e1c96b8052851030d4db971708e98e4d8 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:15 -0700

+ Subject: [PATCH 179/217] ccan/list: Import latest list helpers

+ 

+ Pick up the definition of list_add_{before,after} and other updates from

+ ccan at commit 52b86922f846 ("ccan/base64: fix GCC warning.").

+ 

+ Link: https://lore.kernel.org/r/165781813572.1555691.15909358688944168922.stgit@dwillia2-xfh.jf.intel.com

+ Reported-by: Ira Weiny <ira.weiny@intel.com>

+ Reviewed-by: Ira Weiny <ira.weiny@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  ccan/list/list.h   | 258 ++++++++++++++++++++++++++++++++++++++-------

+  ndctl/lib/inject.c |   1 -

+  util/list.h        |  40 -------

+  3 files changed, 222 insertions(+), 77 deletions(-)

+  delete mode 100644 util/list.h

+ 

+ diff --git a/ccan/list/list.h b/ccan/list/list.h

+ index 3ebd1b2..15f5fb7 100644

+ --- a/ccan/list/list.h

+ +++ b/ccan/list/list.h

+ @@ -95,8 +95,8 @@ struct list_node *list_check_node(const struct list_node *n,

+  #define list_debug(h, loc) list_check((h), loc)

+  #define list_debug_node(n, loc) list_check_node((n), loc)

+  #else

+ -#define list_debug(h, loc) (h)

+ -#define list_debug_node(n, loc) (n)

+ +#define list_debug(h, loc) ((void)loc, h)

+ +#define list_debug_node(n, loc) ((void)loc, n)

+  #endif

+  

+  /**

+ @@ -111,7 +111,7 @@ struct list_node *list_check_node(const struct list_node *n,

+   * Example:

+   *	static struct list_head my_list = LIST_HEAD_INIT(my_list);

+   */

+ -#define LIST_HEAD_INIT(name) { { &name.n, &name.n } }

+ +#define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } }

+  

+  /**

+   * LIST_HEAD - define and initialize an empty list_head

+ @@ -145,6 +145,48 @@ static inline void list_head_init(struct list_head *h)

+  	h->n.next = h->n.prev = &h->n;

+  }

+  

+ +/**

+ + * list_node_init - initialize a list_node

+ + * @n: the list_node to link to itself.

+ + *

+ + * You don't need to use this normally!  But it lets you list_del(@n)

+ + * safely.

+ + */

+ +static inline void list_node_init(struct list_node *n)

+ +{

+ +	n->next = n->prev = n;

+ +}

+ +

+ +/**

+ + * list_add_after - add an entry after an existing node in a linked list

+ + * @h: the list_head to add the node to (for debugging)

+ + * @p: the existing list_node to add the node after

+ + * @n: the new list_node to add to the list.

+ + *

+ + * The existing list_node must already be a member of the list.

+ + * The new list_node does not need to be initialized; it will be overwritten.

+ + *

+ + * Example:

+ + *	struct child c1, c2, c3;

+ + *	LIST_HEAD(h);

+ + *

+ + *	list_add_tail(&h, &c1.list);

+ + *	list_add_tail(&h, &c3.list);

+ + *	list_add_after(&h, &c1.list, &c2.list);

+ + */

+ +#define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC)

+ +static inline void list_add_after_(struct list_head *h,

+ +				   struct list_node *p,

+ +				   struct list_node *n,

+ +				   const char *abortstr)

+ +{

+ +	n->next = p->next;

+ +	n->prev = p;

+ +	p->next->prev = n;

+ +	p->next = n;

+ +	(void)list_debug(h, abortstr);

+ +}

+ +

+  /**

+   * list_add - add an entry at the start of a linked list.

+   * @h: the list_head to add the node to

+ @@ -163,10 +205,34 @@ static inline void list_add_(struct list_head *h,

+  			     struct list_node *n,

+  			     const char *abortstr)

+  {

+ -	n->next = h->n.next;

+ -	n->prev = &h->n;

+ -	h->n.next->prev = n;

+ -	h->n.next = n;

+ +	list_add_after_(h, &h->n, n, abortstr);

+ +}

+ +

+ +/**

+ + * list_add_before - add an entry before an existing node in a linked list

+ + * @h: the list_head to add the node to (for debugging)

+ + * @p: the existing list_node to add the node before

+ + * @n: the new list_node to add to the list.

+ + *

+ + * The existing list_node must already be a member of the list.

+ + * The new list_node does not need to be initialized; it will be overwritten.

+ + *

+ + * Example:

+ + *	list_head_init(&h);

+ + *	list_add_tail(&h, &c1.list);

+ + *	list_add_tail(&h, &c3.list);

+ + *	list_add_before(&h, &c3.list, &c2.list);

+ + */

+ +#define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC)

+ +static inline void list_add_before_(struct list_head *h,

+ +				    struct list_node *p,

+ +				    struct list_node *n,

+ +				    const char *abortstr)

+ +{

+ +	n->next = p;

+ +	n->prev = p->prev;

+ +	p->prev->next = n;

+ +	p->prev = n;

+  	(void)list_debug(h, abortstr);

+  }

+  

+ @@ -185,11 +251,7 @@ static inline void list_add_tail_(struct list_head *h,

+  				  struct list_node *n,

+  				  const char *abortstr)

+  {

+ -	n->next = &h->n;

+ -	n->prev = h->n.prev;

+ -	h->n.prev->next = n;

+ -	h->n.prev = n;

+ -	(void)list_debug(h, abortstr);

+ +	list_add_before_(h, &h->n, n, abortstr);

+  }

+  

+  /**

+ @@ -229,6 +291,21 @@ static inline bool list_empty_nodebug(const struct list_head *h)

+  }

+  #endif

+  

+ +/**

+ + * list_empty_nocheck - is a list empty?

+ + * @h: the list_head

+ + *

+ + * If the list is empty, returns true. This doesn't perform any

+ + * debug check for list consistency, so it can be called without

+ + * locks, racing with the list being modified. This is ok for

+ + * checks where an incorrect result is not an issue (optimized

+ + * bail out path for example).

+ + */

+ +static inline bool list_empty_nocheck(const struct list_head *h)

+ +{

+ +	return h->n.next == &h->n;

+ +}

+ +

+  /**

+   * list_del - delete an entry from an (unknown) linked list.

+   * @n: the list_node to delete from the list.

+ @@ -237,7 +314,7 @@ static inline bool list_empty_nodebug(const struct list_head *h)

+   * another list, but not deleted again.

+   *

+   * See also:

+ - *	list_del_from()

+ + *	list_del_from(), list_del_init()

+   *

+   * Example:

+   *	list_del(&child->list);

+ @@ -255,6 +332,27 @@ static inline void list_del_(struct list_node *n, const char* abortstr)

+  #endif

+  }

+  

+ +/**

+ + * list_del_init - delete a node, and reset it so it can be deleted again.

+ + * @n: the list_node to be deleted.

+ + *

+ + * list_del(@n) or list_del_init() again after this will be safe,

+ + * which can be useful in some cases.

+ + *

+ + * See also:

+ + *	list_del_from(), list_del()

+ + *

+ + * Example:

+ + *	list_del_init(&child->list);

+ + *	parent->num_children--;

+ + */

+ +#define list_del_init(n) list_del_init_(n, LIST_LOC)

+ +static inline void list_del_init_(struct list_node *n, const char *abortstr)

+ +{

+ +	list_del_(n, abortstr);

+ +	list_node_init(n);

+ +}

+ +

+  /**

+   * list_del_from - delete an entry from a known linked list.

+   * @h: the list_head the node is in.

+ @@ -285,6 +383,39 @@ static inline void list_del_from(struct list_head *h, struct list_node *n)

+  	list_del(n);

+  }

+  

+ +/**

+ + * list_swap - swap out an entry from an (unknown) linked list for a new one.

+ + * @o: the list_node to replace from the list.

+ + * @n: the list_node to insert in place of the old one.

+ + *

+ + * Note that this leaves @o in an undefined state; it can be added to

+ + * another list, but not deleted/swapped again.

+ + *

+ + * See also:

+ + *	list_del()

+ + *

+ + * Example:

+ + *	struct child x1, x2;

+ + *	LIST_HEAD(xh);

+ + *

+ + *	list_add(&xh, &x1.list);

+ + *	list_swap(&x1.list, &x2.list);

+ + */

+ +#define list_swap(o, n) list_swap_(o, n, LIST_LOC)

+ +static inline void list_swap_(struct list_node *o,

+ +			      struct list_node *n,

+ +			      const char* abortstr)

+ +{

+ +	(void)list_debug_node(o, abortstr);

+ +	*n = *o;

+ +	n->next->prev = n;

+ +	n->prev->next = n;

+ +#ifdef CCAN_LIST_DEBUG

+ +	/* Catch use-after-del. */

+ +	o->next = o->prev = NULL;

+ +#endif

+ +}

+ +

+  /**

+   * list_entry - convert a list_node back into the structure containing it.

+   * @n: the list_node

+ @@ -406,9 +537,29 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)

+   *		printf("Name: %s\n", child->name);

+   */

+  #define list_for_each_rev(h, i, member)					\

+ -	for (i = container_of_var(list_debug(h,	LIST_LOC)->n.prev, i, member); \

+ -	     &i->member != &(h)->n;					\

+ -	     i = container_of_var(i->member.prev, i, member))

+ +	list_for_each_rev_off(h, i, list_off_var_(i, member))

+ +

+ +/**

+ + * list_for_each_rev_safe - iterate through a list backwards,

+ + * maybe during deletion

+ + * @h: the list_head

+ + * @i: the structure containing the list_node

+ + * @nxt: the structure containing the list_node

+ + * @member: the list_node member of the structure

+ + *

+ + * This is a convenient wrapper to iterate @i over the entire list backwards.

+ + * It's a for loop, so you can break and continue as normal.  The extra

+ + * variable * @nxt is used to hold the next element, so you can delete @i

+ + * from the list.

+ + *

+ + * Example:

+ + *	struct child *next;

+ + *	list_for_each_rev_safe(&parent->children, child, next, list) {

+ + *		printf("Name: %s\n", child->name);

+ + *	}

+ + */

+ +#define list_for_each_rev_safe(h, i, nxt, member)			\

+ +	list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member))

+  

+  /**

+   * list_for_each_safe - iterate through a list, maybe during deletion

+ @@ -422,7 +573,6 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)

+   * @nxt is used to hold the next element, so you can delete @i from the list.

+   *

+   * Example:

+ - *	struct child *next;

+   *	list_for_each_safe(&parent->children, child, next, list) {

+   *		list_del(&child->list);

+   *		parent->num_children--;

+ @@ -537,10 +687,28 @@ static inline void list_prepend_list_(struct list_head *to,

+  	list_head_init(from);

+  }

+  

+ +/* internal macros, do not use directly */

+ +#define list_for_each_off_dir_(h, i, off, dir)				\

+ +	for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir,	\

+ +				   (off));				\

+ +	list_node_from_off_((void *)i, (off)) != &(h)->n;		\

+ +	i = list_node_to_off_(list_node_from_off_((void *)i, (off))->dir, \

+ +			      (off)))

+ +

+ +#define list_for_each_safe_off_dir_(h, i, nxt, off, dir)		\

+ +	for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir,	\

+ +				   (off)),				\

+ +	nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir,	\

+ +				(off));					\

+ +	list_node_from_off_(i, (off)) != &(h)->n;			\

+ +	i = nxt,							\

+ +	nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir,	\

+ +				(off)))

+ +

+  /**

+   * list_for_each_off - iterate through a list of memory regions.

+   * @h: the list_head

+ - * @i: the pointer to a memory region wich contains list node data.

+ + * @i: the pointer to a memory region which contains list node data.

+   * @off: offset(relative to @i) at which list node data resides.

+   *

+   * This is a low-level wrapper to iterate @i over the entire list, used to

+ @@ -548,12 +716,12 @@ static inline void list_prepend_list_(struct list_head *to,

+   * so you can break and continue as normal.

+   *

+   * WARNING! Being the low-level macro that it is, this wrapper doesn't know

+ - * nor care about the type of @i. The only assumtion made is that @i points

+ + * nor care about the type of @i. The only assumption made is that @i points

+   * to a chunk of memory that at some @offset, relative to @i, contains a

+ - * properly filled `struct node_list' which in turn contains pointers to

+ - * memory chunks and it's turtles all the way down. Whith all that in mind

+ + * properly filled `struct list_node' which in turn contains pointers to

+ + * memory chunks and it's turtles all the way down. With all that in mind

+   * remember that given the wrong pointer/offset couple this macro will

+ - * happilly churn all you memory untill SEGFAULT stops it, in other words

+ + * happily churn all you memory until SEGFAULT stops it, in other words

+   * caveat emptor.

+   *

+   * It is worth mentioning that one of legitimate use-cases for that wrapper

+ @@ -567,17 +735,24 @@ static inline void list_prepend_list_(struct list_head *to,

+   *		printf("Name: %s\n", child->name);

+   */

+  #define list_for_each_off(h, i, off)                                    \

+ -	for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.next,	\

+ -				   (off));				\

+ -       list_node_from_off_((void *)i, (off)) != &(h)->n;                \

+ -       i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \

+ -                             (off)))

+ +	list_for_each_off_dir_((h),(i),(off),next)

+ +

+ +/**

+ + * list_for_each_rev_off - iterate through a list of memory regions backwards

+ + * @h: the list_head

+ + * @i: the pointer to a memory region which contains list node data.

+ + * @off: offset(relative to @i) at which list node data resides.

+ + *

+ + * See list_for_each_off for details

+ + */

+ +#define list_for_each_rev_off(h, i, off)                                    \

+ +	list_for_each_off_dir_((h),(i),(off),prev)

+  

+  /**

+   * list_for_each_safe_off - iterate through a list of memory regions, maybe

+   * during deletion

+   * @h: the list_head

+ - * @i: the pointer to a memory region wich contains list node data.

+ + * @i: the pointer to a memory region which contains list node data.

+   * @nxt: the structure containing the list_node

+   * @off: offset(relative to @i) at which list node data resides.

+   *

+ @@ -590,15 +765,26 @@ static inline void list_prepend_list_(struct list_head *to,

+   *		printf("Name: %s\n", child->name);

+   */

+  #define list_for_each_safe_off(h, i, nxt, off)                          \

+ -	for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.next,	\

+ -				   (off)),				\

+ -         nxt = list_node_to_off_(list_node_from_off_(i, (off))->next,   \

+ -                                 (off));                                \

+ -       list_node_from_off_(i, (off)) != &(h)->n;                        \

+ -       i = nxt,                                                         \

+ -         nxt = list_node_to_off_(list_node_from_off_(i, (off))->next,   \

+ -                                 (off)))

+ +	list_for_each_safe_off_dir_((h),(i),(nxt),(off),next)

+  

+ +/**

+ + * list_for_each_rev_safe_off - iterate backwards through a list of

+ + * memory regions, maybe during deletion

+ + * @h: the list_head

+ + * @i: the pointer to a memory region which contains list node data.

+ + * @nxt: the structure containing the list_node

+ + * @off: offset(relative to @i) at which list node data resides.

+ + *

+ + * For details see `list_for_each_rev_off' and `list_for_each_rev_safe'

+ + * descriptions.

+ + *

+ + * Example:

+ + *	list_for_each_rev_safe_off(&parent->children, child,

+ + *		next, offsetof(struct child, list))

+ + *		printf("Name: %s\n", child->name);

+ + */

+ +#define list_for_each_rev_safe_off(h, i, nxt, off)                      \

+ +	list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev)

+  

+  /* Other -off variants. */

+  #define list_entry_off(n, type, off)		\

+ diff --git a/ndctl/lib/inject.c b/ndctl/lib/inject.c

+ index d61c02c..3486ffe 100644

+ --- a/ndctl/lib/inject.c

+ +++ b/ndctl/lib/inject.c

+ @@ -2,7 +2,6 @@

+  // Copyright (C) 2014-2020, Intel Corporation. All rights reserved.

+  #include <stdlib.h>

+  #include <limits.h>

+ -#include <util/list.h>

+  #include <util/size.h>

+  #include <ndctl/libndctl.h>

+  #include <ccan/list/list.h>

+ diff --git a/util/list.h b/util/list.h

+ deleted file mode 100644

+ index 1ea9c59..0000000

+ --- a/util/list.h

+ +++ /dev/null

+ @@ -1,40 +0,0 @@

+ -/* SPDX-License-Identifier: GPL-2.0 */

+ -/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */

+ -#ifndef _NDCTL_LIST_H_

+ -#define _NDCTL_LIST_H_

+ -

+ -#include <ccan/list/list.h>

+ -

+ -/**

+ - * list_add_after - add an entry after the given node in the linked list.

+ - * @h: the list_head to add the node to

+ - * @l: the list_node after which to add to

+ - * @n: the list_node to add to the list.

+ - *

+ - * The list_node does not need to be initialized; it will be overwritten.

+ - * Example:

+ - *	struct child *child = malloc(sizeof(*child));

+ - *

+ - *	child->name = "geoffrey";

+ - *	list_add_after(&parent->children, &child1->list, &child->list);

+ - *	parent->num_children++;

+ - */

+ -#define list_add_after(h, l, n) list_add_after_(h, l, n, LIST_LOC)

+ -static inline void list_add_after_(struct list_head *h,

+ -				   struct list_node *l,

+ -				   struct list_node *n,

+ -				   const char *abortstr)

+ -{

+ -	if (l->next == &h->n) {

+ -		/* l is the last element, this becomes a list_add_tail */

+ -		list_add_tail(h, n);

+ -		return;

+ -	}

+ -	n->next = l->next;

+ -	n->prev = l;

+ -	l->next->prev = n;

+ -	l->next = n;

+ -	(void)list_debug(h, abortstr);

+ -}

+ -

+ -#endif /* _NDCTL_LIST_H_ */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,103 @@ 

+ From 06ae7118aaa74aa2139004fa12b4910bc15236de Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:21 -0700

+ Subject: [PATCH 180/217] cxl/lib: Maintain decoders in id order

+ 

+ Given that decoder instance order is fundamental to the DPA translation

+ sequence for endpoint decoders, enforce that cxl_decoder_for_each() returns

+ decoders in instance order. Otherwise, they show up in readddir() order

+ which is not predictable.

+ 

+ Add a list_add_sorted() to generically handle inserting into a sorted list.

+ 

+ Link: https://lore.kernel.org/r/165781814167.1555691.14895625637451030942.stgit@dwillia2-xfh.jf.intel.com

+ Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c |  8 +++++++-

+  util/list.h      | 39 +++++++++++++++++++++++++++++++++++++++

+  2 files changed, 46 insertions(+), 1 deletion(-)

+  create mode 100644 util/list.h

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 6f4d64d..ea597f6 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -19,6 +19,7 @@

+  #include <ccan/short_types/short_types.h>

+  

+  #include <util/log.h>

+ +#include <util/list.h>

+  #include <util/size.h>

+  #include <util/sysfs.h>

+  #include <util/bitmap.h>

+ @@ -909,6 +910,11 @@ cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint)

+  	return NULL;

+  }

+  

+ +static int decoder_id_cmp(struct cxl_decoder *d1, struct cxl_decoder *d2)

+ +{

+ +	return d1->id - d2->id;

+ +}

+ +

+  static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  {

+  	const char *devname = devpath_to_devname(cxldecoder_base);

+ @@ -1050,7 +1056,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  			return decoder_dup;

+  		}

+  

+ -	list_add(&port->decoders, &decoder->list);

+ +	list_add_sorted(&port->decoders, decoder, list, decoder_id_cmp);

+  

+  	free(path);

+  	return decoder;

+ diff --git a/util/list.h b/util/list.h

+ new file mode 100644

+ index 0000000..cb77271

+ --- /dev/null

+ +++ b/util/list.h

+ @@ -0,0 +1,39 @@

+ +/* SPDX-License-Identifier: GPL-2.0 */

+ +/* Copyright (C) 2022 Intel Corporation. All rights reserved. */

+ +#ifndef _NDCTL_LIST_H_

+ +#define _NDCTL_LIST_H_

+ +

+ +#include <ccan/list/list.h>

+ +

+ +#define list_add_sorted(head, n, node, cmp)                                    \

+ +	do {                                                                   \

+ +		struct list_head *__head = (head);                             \

+ +		typeof(n) __iter, __next;                                      \

+ +		typeof(n) __new = (n);                                         \

+ +                                                                               \

+ +		if (list_empty(__head)) {                                      \

+ +			list_add(__head, &__new->node);                        \

+ +			break;                                                 \

+ +		}                                                              \

+ +                                                                               \

+ +		list_for_each (__head, __iter, node) {                         \

+ +			if (cmp(__new, __iter) < 0) {                          \

+ +				list_add_before(__head, &__iter->node,         \

+ +						&__new->node);                 \

+ +				break;                                         \

+ +			}                                                      \

+ +			__next = list_next(__head, __iter, node);              \

+ +			if (!__next) {                                         \

+ +				list_add_after(__head, &__iter->node,          \

+ +					       &__new->node);                  \

+ +				break;                                         \

+ +			}                                                      \

+ +			if (cmp(__new, __next) < 0) {                          \

+ +				list_add_before(__head, &__next->node,         \

+ +						&__new->node);                 \

+ +				break;                                         \

+ +			}                                                      \

+ +		}                                                              \

+ +	} while (0)

+ +

+ +#endif /* _NDCTL_LIST_H_ */

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,93 @@ 

+ From 8ed95d22504d7b2b258d1800878e32c162badf8c Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:27 -0700

+ Subject: [PATCH 181/217] cxl/memdev: Fix json for multi-device partitioning

+ 

+ In the case when someone partitions several devices at once, collect all

+ the affected memdevs into a json array.

+ 

+ With the move to use util_display_json_array() that also requires a set of

+ flags to be specifiied. Apply the UTIL_JSON_HUMAN flag for all interactive

+ command result output to bring this command in line with other tools.

+ 

+ Link: https://lore.kernel.org/r/165781814737.1555691.889129128205037941.stgit@dwillia2-xfh.jf.intel.com

+ Cc: Alison Schofield <alison.schofield@intel.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/memdev.c | 26 +++++++++++++++++++++-----

+  1 file changed, 21 insertions(+), 5 deletions(-)

+ 

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index 91d914d..9fcd8ae 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -19,6 +19,7 @@

+  struct action_context {

+  	FILE *f_out;

+  	FILE *f_in;

+ +	struct json_object *jdevs;

+  };

+  

+  static struct parameters {

+ @@ -339,12 +340,13 @@ out:

+  }

+  

+  static int action_setpartition(struct cxl_memdev *memdev,

+ -		struct action_context *actx)

+ +			       struct action_context *actx)

+  {

+  	const char *devname = cxl_memdev_get_devname(memdev);

+  	enum cxl_setpart_type type = CXL_SETPART_PMEM;

+  	unsigned long long size = ULLONG_MAX;

+  	struct json_object *jmemdev;

+ +	unsigned long flags;

+  	struct cxl_cmd *cmd;

+  	int rc;

+  

+ @@ -396,10 +398,12 @@ out_err:

+  	if (rc)

+  		log_err(&ml, "%s error: %s\n", devname, strerror(-rc));

+  

+ -	jmemdev = util_cxl_memdev_to_json(memdev, UTIL_JSON_PARTITION);

+ -	if (jmemdev)

+ -		printf("%s\n", json_object_to_json_string_ext(jmemdev,

+ -		       JSON_C_TO_STRING_PRETTY));

+ +	flags = UTIL_JSON_PARTITION;

+ +	if (actx->f_out == stdout && isatty(1))

+ +		flags |= UTIL_JSON_HUMAN;

+ +	jmemdev = util_cxl_memdev_to_json(memdev, flags);

+ +	if (actx->jdevs && jmemdev)

+ +		json_object_array_add(actx->jdevs, jmemdev);

+  

+  	return rc;

+  }

+ @@ -446,6 +450,9 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  		err++;

+  	}

+  

+ +	if (action == action_setpartition)

+ +		actx.jdevs = json_object_new_array();

+ +

+  	if (err == argc) {

+  		usage_with_options(u, options);

+  		return -EINVAL;

+ @@ -528,6 +535,15 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	if (actx.f_in != stdin)

+  		fclose(actx.f_in);

+  

+ +	if (actx.jdevs) {

+ +		unsigned long flags = 0;

+ +

+ +		if (actx.f_out == stdout && isatty(1))

+ +			flags |= UTIL_JSON_HUMAN;

+ +		util_display_json_array(actx.f_out, actx.jdevs, flags);

+ +	}

+ +

+ +

+   out_close_fout:

+  	if (actx.f_out != stdout)

+  		fclose(actx.f_out);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,181 @@ 

+ From d2a7fc7fb87396eb267cf6c8948468f7e56bea89 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:33 -0700

+ Subject: [PATCH 182/217] cxl/list: Emit 'mode' for endpoint decoder objects

+ 

+ The 'mode' property of an endpoint decoder indicates the access

+ properties of the DPA (device physical address) mapped into HPA (host

+ physical address) by the decoder. Where the modes are 'none'

+ (decoder-disabled), 'ram' (voltaile memory), 'pmem' (persistent memory),

+ and 'mixed' (an unexpected, but possible, case where the decoder

+ straddles a mode / partition boundary).

+ 

+ Link: https://lore.kernel.org/r/165781815306.1555691.17541956592287631419.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  9 +++++++++

+  cxl/json.c                       |  8 ++++++++

+  cxl/lib/libcxl.c                 | 30 ++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |  1 +

+  cxl/lib/private.h                |  1 +

+  cxl/libcxl.h                     | 23 +++++++++++++++++++++++

+  6 files changed, 72 insertions(+)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 2aef489..90fe338 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -405,6 +405,15 @@ enum cxl_decoder_target_type {

+  };

+  

+  cxl_decoder_get_target_type(struct cxl_decoder *decoder);

+ +

+ +enum cxl_decoder_mode {

+ +	CXL_DECODER_MODE_NONE,

+ +	CXL_DECODER_MODE_MIXED,

+ +	CXL_DECODER_MODE_PMEM,

+ +	CXL_DECODER_MODE_RAM,

+ +};

+ +enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder);

+ +

+  bool cxl_decoder_is_pmem_capable(struct cxl_decoder *decoder);

+  bool cxl_decoder_is_volatile_capable(struct cxl_decoder *decoder);

+  bool cxl_decoder_is_mem_capable(struct cxl_decoder *decoder);

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 3f52d3b..ae9c812 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -473,6 +473,8 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	}

+  

+  	if (cxl_port_is_endpoint(port)) {

+ +		enum cxl_decoder_mode mode = cxl_decoder_get_mode(decoder);

+ +

+  		size = cxl_decoder_get_dpa_size(decoder);

+  		val = cxl_decoder_get_dpa_resource(decoder);

+  		if (size && val < ULLONG_MAX) {

+ @@ -488,6 +490,12 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  				json_object_object_add(jdecoder, "dpa_size",

+  						       jobj);

+  		}

+ +

+ +		if (mode > CXL_DECODER_MODE_NONE) {

+ +			jobj = json_object_new_string(cxl_decoder_mode_name(mode));

+ +			if (jobj)

+ +				json_object_object_add(jdecoder, "mode", jobj);

+ +		}

+  	}

+  

+  	if (cxl_port_is_root(port) && cxl_decoder_is_mem_capable(decoder)) {

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index ea597f6..b802e5d 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -961,6 +961,21 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	else

+  		decoder->size = strtoull(buf, NULL, 0);

+  

+ +	sprintf(path, "%s/mode", cxldecoder_base);

+ +	if (sysfs_read_attr(ctx, path, buf) == 0) {

+ +		if (strcmp(buf, "ram") == 0)

+ +			decoder->mode = CXL_DECODER_MODE_RAM;

+ +		else if (strcmp(buf, "pmem") == 0)

+ +			decoder->mode = CXL_DECODER_MODE_PMEM;

+ +		else if (strcmp(buf, "mixed") == 0)

+ +			decoder->mode = CXL_DECODER_MODE_MIXED;

+ +		else if (strcmp(buf, "none") == 0)

+ +			decoder->mode = CXL_DECODER_MODE_NONE;

+ +		else

+ +			decoder->mode = CXL_DECODER_MODE_MIXED;

+ +	} else

+ +		decoder->mode = CXL_DECODER_MODE_NONE;

+ +

+  	switch (port->type) {

+  	case CXL_PORT_ENDPOINT:

+  		sprintf(path, "%s/dpa_resource", cxldecoder_base);

+ @@ -1161,6 +1176,21 @@ cxl_decoder_get_dpa_size(struct cxl_decoder *decoder)

+  	return decoder->dpa_size;

+  }

+  

+ +CXL_EXPORT enum cxl_decoder_mode

+ +cxl_decoder_get_mode(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +

+ +	if (!cxl_port_is_endpoint(port)) {

+ +		err(ctx, "%s: not an endpoint decoder\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return CXL_DECODER_MODE_NONE;

+ +	}

+ +

+ +	return decoder->mode;

+ +}

+ +

+  CXL_EXPORT enum cxl_decoder_target_type

+  cxl_decoder_get_target_type(struct cxl_decoder *decoder)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 8e2fc75..88c5a7e 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -172,4 +172,5 @@ LIBCXL_3 {

+  global:

+  	cxl_decoder_get_dpa_resource;

+  	cxl_decoder_get_dpa_size;

+ +	cxl_decoder_get_mode;

+  } LIBCXL_2;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 24a2ae6..f6d4573 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -108,6 +108,7 @@ struct cxl_decoder {

+  	char *dev_path;

+  	int nr_targets;

+  	int id;

+ +	enum cxl_decoder_mode mode;

+  	bool pmem_capable;

+  	bool volatile_capable;

+  	bool mem_capable;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 76aebe3..1436dc4 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -127,10 +127,33 @@ struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port,

+  struct cxl_decoder;

+  struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);

+  struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);

+ +struct cxl_decoder *cxl_decoder_get_last(struct cxl_port *port);

+ +struct cxl_decoder *cxl_decoder_get_prev(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder);

+ +enum cxl_decoder_mode {

+ +	CXL_DECODER_MODE_NONE,

+ +	CXL_DECODER_MODE_MIXED,

+ +	CXL_DECODER_MODE_PMEM,

+ +	CXL_DECODER_MODE_RAM,

+ +};

+ +static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode)

+ +{

+ +	static const char *names[] = {

+ +		[CXL_DECODER_MODE_NONE] = "none",

+ +		[CXL_DECODER_MODE_MIXED] = "mixed",

+ +		[CXL_DECODER_MODE_PMEM] = "pmem",

+ +		[CXL_DECODER_MODE_RAM] = "ram",

+ +	};

+ +

+ +	if (mode < CXL_DECODER_MODE_NONE || mode > CXL_DECODER_MODE_RAM)

+ +		mode = CXL_DECODER_MODE_NONE;

+ +	return names[mode];

+ +}

+ +

+ +enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder);

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+  struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,

+  						    struct cxl_memdev *memdev);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,56 @@ 

+ From b1c29cfa125f6da219bfcec732a8290bb124cdce Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:38 -0700

+ Subject: [PATCH 183/217] cxl/set-partition: Accept 'ram' as an alias for

+  'volatile'

+ 

+ 'ram' is a more convenient shorthand for volatile memory.

+ 

+ Link: https://lore.kernel.org/r/165781815878.1555691.12251226240559355924.stgit@dwillia2-xfh.jf.intel.com

+ Cc: Alison Schofield <alison.schofield@intel.com>

+ Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-set-partition.txt | 2 +-

+  cxl/memdev.c                            | 4 +++-

+  2 files changed, 4 insertions(+), 2 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-set-partition.txt b/Documentation/cxl/cxl-set-partition.txt

+ index 1e548af..f0126da 100644

+ --- a/Documentation/cxl/cxl-set-partition.txt

+ +++ b/Documentation/cxl/cxl-set-partition.txt

+ @@ -37,7 +37,7 @@ include::memdev-option.txt[]

+  

+  -t::

+  --type=::

+ -	Type of partition, 'pmem' or 'volatile', to modify.

+ +	Type of partition, 'pmem' or 'ram' (volatile), to modify.

+  	Default: 'pmem'

+  

+  -s::

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index 9fcd8ae..1cecad2 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -65,7 +65,7 @@ OPT_BOOLEAN('f', "force", &param.force,                                \

+  

+  #define SET_PARTITION_OPTIONS() \

+  OPT_STRING('t', "type",  &param.type, "type",			\

+ -	"'pmem' or 'volatile' (Default: 'pmem')"),		\

+ +	"'pmem' or 'ram' (volatile) (Default: 'pmem')"),		\

+  OPT_STRING('s', "size",  &param.size, "size",			\

+  	"size in bytes (Default: all available capacity)"),	\

+  OPT_BOOLEAN('a', "align",  &param.align,			\

+ @@ -355,6 +355,8 @@ static int action_setpartition(struct cxl_memdev *memdev,

+  			/* default */;

+  		else if (strcmp(param.type, "volatile") == 0)

+  			type = CXL_SETPART_VOLATILE;

+ +		else if (strcmp(param.type, "ram") == 0)

+ +			type = CXL_SETPART_VOLATILE;

+  		else {

+  			log_err(&ml, "invalid type '%s'\n", param.type);

+  			return -EINVAL;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,763 @@ 

+ From 6624f4fdf7ba43039111c996dfd3982b4fdc43bc Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:44 -0700

+ Subject: [PATCH 184/217] cxl/memdev: Add {reserve,free}-dpa commands

+ 

+ Add helper commands for managing allocations of DPA (device physical

+ address) capacity on a set of CXL memory devices.

+ 

+ The main convenience this command affords is automatically picking the next

+ decoder to allocate per-memdev.

+ 

+ For example, to allocate 256MiB from all endpoints that are covered by a

+ given root decoder, and collect those resulting endpoint-decoders into an

+ array:

+ 

+   readarray -t mem < <(cxl list -M -d $decoder | jq -r ".[].memdev")

+   readarray -t endpoint < <(cxl reserve-dpa -t pmem ${mem[*]} -s $((256<<20)) |

+                             jq -r ".[] | .decoder.decoder")

+ 

+ Link: https://lore.kernel.org/r/165781816425.1555691.17958897857798325111.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ [vishal: fix typo pointed out by Jonathan]

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format                         |   1 +

+  Documentation/cxl/cxl-free-dpa.txt    |  53 +++++

+  Documentation/cxl/cxl-reserve-dpa.txt |  67 ++++++

+  Documentation/cxl/lib/libcxl.txt      |   2 +

+  Documentation/cxl/meson.build         |   2 +

+  cxl/builtin.h                         |   2 +

+  cxl/cxl.c                             |   2 +

+  cxl/filter.c                          |   4 +-

+  cxl/filter.h                          |   2 +

+  cxl/lib/libcxl.c                      |  86 ++++++++

+  cxl/lib/libcxl.sym                    |   4 +

+  cxl/libcxl.h                          |   9 +

+  cxl/memdev.c                          | 280 +++++++++++++++++++++++++-

+  13 files changed, 511 insertions(+), 3 deletions(-)

+  create mode 100644 Documentation/cxl/cxl-free-dpa.txt

+  create mode 100644 Documentation/cxl/cxl-reserve-dpa.txt

+ 

+ diff --git a/.clang-format b/.clang-format

+ index 6aabcb6..7254a1b 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -81,6 +81,7 @@ ForEachMacros:

+    - 'cxl_bus_foreach'

+    - 'cxl_port_foreach'

+    - 'cxl_decoder_foreach'

+ +  - 'cxl_decoder_foreach_reverse'

+    - 'cxl_target_foreach'

+    - 'cxl_dport_foreach'

+    - 'cxl_endpoint_foreach'

+ diff --git a/Documentation/cxl/cxl-free-dpa.txt b/Documentation/cxl/cxl-free-dpa.txt

+ new file mode 100644

+ index 0000000..73fb048

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-free-dpa.txt

+ @@ -0,0 +1,53 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-free-dpa(1)

+ +===============

+ +

+ +NAME

+ +----

+ +cxl-free-dpa - release device-physical address space

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl free-dpa' <mem0> [<mem1>..<memN>] [<options>]

+ +

+ +The CXL region provisioning process proceeds in multiple steps. One of

+ +the steps is identifying and reserving the DPA span that each member of

+ +the interleave-set (region) contributes in advance of attaching that

+ +allocation to a region. For development, test, and debug purposes this

+ +command is a helper to find the last allocated decoder on a device and

+ +zero-out / free its DPA allocation.

+ +

+ +OPTIONS

+ +-------

+ +<memory device(s)>::

+ +include::memdev-option.txt[]

+ +

+ +-d::

+ +--decoder::

+ +	Specify the decoder to free. The CXL specification

+ +	mandates that DPA must be released in the reverse order it was

+ +	allocated. See linkcxl:cxl-reserve-dpa[1]

+ +

+ +-t::

+ +--type::

+ +	Constrain the search for "last allocated decoder" to decoders targeting

+ +	the given partition.

+ +

+ +-f::

+ +--force::

+ +	The kernel enforces CXL DPA ordering constraints on deallocation events,

+ +	and the tool anticipates those and fails operations that are expected to

+ +	fail without sending them to the kernel. For test purposes, continue to

+ +	attempt "expected to fail" operations to exercise the driver.

+ +

+ +-v::

+ +	Turn on verbose debug messages in the library (if libcxl was built with

+ +	logging and debug enabled).

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-reserve-dpa[1]

+ diff --git a/Documentation/cxl/cxl-reserve-dpa.txt b/Documentation/cxl/cxl-reserve-dpa.txt

+ new file mode 100644

+ index 0000000..5e79ef2

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-reserve-dpa.txt

+ @@ -0,0 +1,67 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-reserve-dpa(1)

+ +==================

+ +

+ +NAME

+ +----

+ +cxl-reserve-dpa - allocate device-physical address space

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl reserve-dpa' <mem0> [<mem1>..<memN>] [<options>]

+ +

+ +The CXL region provisioning process proceeds in multiple steps. One of

+ +the steps is identifying and reserving the DPA span that each member of

+ +the interleave-set (region) contributes in advance of attaching that

+ +allocation to a region. For development, test, and debug purposes this

+ +command is a helper to find the next available decoder on endpoint

+ +(memdev) and mark a span of DPA as busy.

+ +

+ +OPTIONS

+ +-------

+ +<memory device(s)>::

+ +include::memdev-option.txt[]

+ +

+ +-d::

+ +--decoder::

+ +	Specify the decoder to attempt the allocation. The CXL specification

+ +	mandates that allocations must be ordered by DPA and decoder instance.

+ +	I.e. the lowest DPA allocation on the device is covered by decoder0, and

+ +	the last / highest DPA allocation is covered by the last decoder. This

+ +	ordering is enforced by the kernel. By default the tool picks the 'next

+ +	available' decoder.

+ +

+ +-t::

+ +--type::

+ +	Select the partition for the allocation. CXL devices implement a

+ +	partition that divdes 'ram' and 'pmem' capacity, where 'pmem' capacity

+ +	consumes the higher DPA capacity above the partition boundary. The type

+ +	defaults to 'pmem'. Note that given CXL DPA allocation constraints, once

+ +	any 'pmem' allocation is established then all remaining 'ram' capacity

+ +	becomes reserved (skipped).

+ +

+ +-f::

+ +--force::

+ +	The kernel enforces CXL DPA allocation ordering constraints, and

+ +	the tool anticipates those and fails operations that are expected to

+ +	fail without sending them to the kernel. For test purposes, continue to

+ +	attempt "expected to fail" operations to exercise the driver.

+ +

+ +-s::

+ +--size::

+ +	Specify the size of the allocation. This option supports the suffixes

+ +	"k" or "K" for KiB, "m" or "M" for MiB, "g" or "G" for GiB and "t" or

+ +	"T" for TiB. This defaults to "all available capacity of the specified

+ +	type".

+ +

+ +-v::

+ +	Turn on verbose debug messages in the library (if libcxl was built with

+ +	logging and debug enabled).

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-free-dpa[1]

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 90fe338..7a38ce4 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -394,6 +394,7 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder);

+ +int cxl_decoder_set_dpa_size(struct cxl_decoder *decoder, unsigned long long size);

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+  int cxl_decoder_get_id(struct cxl_decoder *decoder);

+  int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);

+ @@ -413,6 +414,7 @@ enum cxl_decoder_mode {

+  	CXL_DECODER_MODE_RAM,

+  };

+  enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder);

+ +int cxl_decoder_set_mode(struct cxl_decoder *decoder, enum cxl_decoder_mode mode);

+  

+  bool cxl_decoder_is_pmem_capable(struct cxl_decoder *decoder);

+  bool cxl_decoder_is_volatile_capable(struct cxl_decoder *decoder);

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index 974a5a4..d019dfc 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -36,6 +36,8 @@ cxl_manpages = [

+    'cxl-disable-port.txt',

+    'cxl-disable-bus.txt',

+    'cxl-set-partition.txt',

+ +  'cxl-reserve-dpa.txt',

+ +  'cxl-free-dpa.txt',

+  ]

+  

+  foreach man : cxl_manpages

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index a437bc3..9e6fc62 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -12,6 +12,8 @@ int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_reserve_dpa(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_free_dpa(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx);

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index aa4ce61..ef4cda9 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -66,6 +66,8 @@ static struct cmd_struct commands[] = {

+  	{ "write-labels", .c_fn = cmd_write_labels },

+  	{ "disable-memdev", .c_fn = cmd_disable_memdev },

+  	{ "enable-memdev", .c_fn = cmd_enable_memdev },

+ +	{ "reserve-dpa", .c_fn = cmd_reserve_dpa },

+ +	{ "free-dpa", .c_fn = cmd_free_dpa },

+  	{ "disable-port", .c_fn = cmd_disable_port },

+  	{ "enable-port", .c_fn = cmd_enable_port },

+  	{ "set-partition", .c_fn = cmd_set_partition },

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 2f88a9d..e5fab19 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -380,8 +380,8 @@ struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,

+  	return NULL;

+  }

+  

+ -static struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder,

+ -						   const char *__ident)

+ +struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder,

+ +					    const char *__ident)

+  {

+  	struct cxl_port *port = cxl_decoder_get_port(decoder);

+  	int pid, did;

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 9557943..c913daf 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -50,6 +50,8 @@ struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target,

+  struct cxl_dport *util_cxl_dport_filter_by_memdev(struct cxl_dport *dport,

+  						  const char *ident,

+  						  const char *serial);

+ +struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder,

+ +					    const char *__ident);

+  int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);

+  bool cxl_filter_has(const char *needle, const char *__filter);

+  #endif /* _CXL_UTIL_FILTER_H_ */

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index b802e5d..e52896f 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1121,6 +1121,20 @@ CXL_EXPORT struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder)

+  	return list_next(&port->decoders, decoder, list);

+  }

+  

+ +CXL_EXPORT struct cxl_decoder *cxl_decoder_get_last(struct cxl_port *port)

+ +{

+ +	cxl_decoders_init(port);

+ +

+ +	return list_tail(&port->decoders, struct cxl_decoder, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_decoder *cxl_decoder_get_prev(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_port *port = decoder->port;

+ +

+ +	return list_prev(&port->decoders, decoder, list);

+ +}

+ +

+  CXL_EXPORT struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder)

+  {

+  	return decoder->ctx;

+ @@ -1176,6 +1190,78 @@ cxl_decoder_get_dpa_size(struct cxl_decoder *decoder)

+  	return decoder->dpa_size;

+  }

+  

+ +CXL_EXPORT int cxl_decoder_set_dpa_size(struct cxl_decoder *decoder,

+ +					unsigned long long size)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	char *path = decoder->dev_buf;

+ +	int len = decoder->buf_len, rc;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	if (!cxl_port_is_endpoint(port)) {

+ +		err(ctx, "%s: not an endpoint decoder\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (snprintf(path, len, "%s/dpa_size", decoder->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return -ENOMEM;

+ +	}

+ +

+ +	sprintf(buf, "%#llx\n", size);

+ +	rc = sysfs_write_attr(ctx, path, buf);

+ +	if (rc < 0)

+ +		return rc;

+ +

+ +	decoder->dpa_size = size;

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_decoder_set_mode(struct cxl_decoder *decoder,

+ +				    enum cxl_decoder_mode mode)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	char *path = decoder->dev_buf;

+ +	int len = decoder->buf_len, rc;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	if (!cxl_port_is_endpoint(port)) {

+ +		err(ctx, "%s: not an endpoint decoder\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return -EINVAL;

+ +	}

+ +

+ +	switch (mode) {

+ +	case CXL_DECODER_MODE_PMEM:

+ +		sprintf(buf, "pmem");

+ +		break;

+ +	case CXL_DECODER_MODE_RAM:

+ +		sprintf(buf, "ram");

+ +		break;

+ +	default:

+ +		err(ctx, "%s: unsupported mode: %d\n",

+ +		    cxl_decoder_get_devname(decoder), mode);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (snprintf(path, len, "%s/mode", decoder->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return -ENOMEM;

+ +	}

+ +

+ +	rc = sysfs_write_attr(ctx, path, buf);

+ +	if (rc < 0)

+ +		return rc;

+ +

+ +	decoder->mode = mode;

+ +	return 0;

+ +}

+ +

+  CXL_EXPORT enum cxl_decoder_mode

+  cxl_decoder_get_mode(struct cxl_decoder *decoder)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 88c5a7e..7712de0 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -173,4 +173,8 @@ global:

+  	cxl_decoder_get_dpa_resource;

+  	cxl_decoder_get_dpa_size;

+  	cxl_decoder_get_mode;

+ +	cxl_decoder_get_last;

+ +	cxl_decoder_get_prev;

+ +	cxl_decoder_set_dpa_size;

+ +	cxl_decoder_set_mode;

+  } LIBCXL_2;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 1436dc4..33a216e 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -139,6 +139,7 @@ enum cxl_decoder_mode {

+  	CXL_DECODER_MODE_PMEM,

+  	CXL_DECODER_MODE_RAM,

+  };

+ +

+  static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode)

+  {

+  	static const char *names[] = {

+ @@ -154,6 +155,10 @@ static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode)

+  }

+  

+  enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder);

+ +int cxl_decoder_set_mode(struct cxl_decoder *decoder,

+ +			 enum cxl_decoder_mode mode);

+ +int cxl_decoder_set_dpa_size(struct cxl_decoder *decoder,

+ +			     unsigned long long size);

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+  struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,

+  						    struct cxl_memdev *memdev);

+ @@ -182,6 +187,10 @@ bool cxl_decoder_is_locked(struct cxl_decoder *decoder);

+  	for (decoder = cxl_decoder_get_first(port); decoder != NULL;           \

+  	     decoder = cxl_decoder_get_next(decoder))

+  

+ +#define cxl_decoder_foreach_reverse(port, decoder)                             \

+ +	for (decoder = cxl_decoder_get_last(port); decoder != NULL;           \

+ +	     decoder = cxl_decoder_get_prev(decoder))

+ +

+  struct cxl_target;

+  struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder);

+  struct cxl_target *cxl_target_get_next(struct cxl_target *target);

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index 1cecad2..e42f554 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -33,6 +33,7 @@ static struct parameters {

+  	bool align;

+  	const char *type;

+  	const char *size;

+ +	const char *decoder_filter;

+  } param;

+  

+  static struct log_ctx ml;

+ @@ -71,6 +72,19 @@ OPT_STRING('s', "size",  &param.size, "size",			\

+  OPT_BOOLEAN('a', "align",  &param.align,			\

+  	"auto-align --size per device's requirement")

+  

+ +#define RESERVE_DPA_OPTIONS()                                          \

+ +OPT_STRING('s', "size", &param.size, "size",                           \

+ +	   "size in bytes (Default: all available capacity)")

+ +

+ +#define DPA_OPTIONS()                                          \

+ +OPT_STRING('d', "decoder", &param.decoder_filter,              \

+ +   "decoder instance id",                                      \

+ +   "override the automatic decoder selection"),                \

+ +OPT_STRING('t', "type", &param.type, "type",                   \

+ +	   "'pmem' or 'ram' (volatile) (Default: 'pmem')"),    \

+ +OPT_BOOLEAN('f', "force", &param.force,                        \

+ +	    "Attempt 'expected to fail' operations")

+ +

+  static const struct option read_options[] = {

+  	BASE_OPTIONS(),

+  	LABEL_OPTIONS(),

+ @@ -108,6 +122,242 @@ static const struct option set_partition_options[] = {

+  	OPT_END(),

+  };

+  

+ +static const struct option reserve_dpa_options[] = {

+ +	BASE_OPTIONS(),

+ +	RESERVE_DPA_OPTIONS(),

+ +	DPA_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static const struct option free_dpa_options[] = {

+ +	BASE_OPTIONS(),

+ +	DPA_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +enum reserve_dpa_mode {

+ +	DPA_ALLOC,

+ +	DPA_FREE,

+ +};

+ +

+ +static int __reserve_dpa(struct cxl_memdev *memdev,

+ +			 enum reserve_dpa_mode alloc_mode,

+ +			 struct action_context *actx)

+ +{

+ +	struct cxl_decoder *decoder, *auto_target = NULL, *target = NULL;

+ +	struct cxl_endpoint *endpoint = cxl_memdev_get_endpoint(memdev);

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	unsigned long long avail_dpa, size;

+ +	enum cxl_decoder_mode mode;

+ +	struct cxl_port *port;

+ +	char buf[256];

+ +	int rc;

+ +

+ +	if (param.type) {

+ +		if (strcmp(param.type, "ram") == 0)

+ +			mode = CXL_DECODER_MODE_RAM;

+ +		else if (strcmp(param.type, "volatile") == 0)

+ +			mode = CXL_DECODER_MODE_RAM;

+ +		else if (strcmp(param.type, "ram") == 0)

+ +			mode = CXL_DECODER_MODE_RAM;

+ +		else if (strcmp(param.type, "pmem") == 0)

+ +			mode = CXL_DECODER_MODE_PMEM;

+ +		else {

+ +			log_err(&ml, "%s: unsupported type: %s\n", devname,

+ +				param.type);

+ +			return -EINVAL;

+ +		}

+ +	} else

+ +		mode = CXL_DECODER_MODE_RAM;

+ +

+ +	if (!endpoint) {

+ +		log_err(&ml, "%s: CXL operation disabled\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	port = cxl_endpoint_get_port(endpoint);

+ +

+ +	if (mode == CXL_DECODER_MODE_RAM)

+ +		avail_dpa = cxl_memdev_get_ram_size(memdev);

+ +	else

+ +		avail_dpa = cxl_memdev_get_pmem_size(memdev);

+ +

+ +	cxl_decoder_foreach(port, decoder) {

+ +		size = cxl_decoder_get_dpa_size(decoder);

+ +		if (size == ULLONG_MAX)

+ +			continue;

+ +		if (cxl_decoder_get_mode(decoder) != mode)

+ +			continue;

+ +

+ +		if (size > avail_dpa) {

+ +			log_err(&ml, "%s: capacity accounting error\n",

+ +				devname);

+ +			return -ENXIO;

+ +		}

+ +		avail_dpa -= size;

+ +	}

+ +

+ +	if (!param.size)

+ +		if (alloc_mode == DPA_ALLOC) {

+ +			size = avail_dpa;

+ +			if (!avail_dpa) {

+ +				log_err(&ml, "%s: no available capacity\n",

+ +					devname);

+ +				return -ENOSPC;

+ +			}

+ +		} else

+ +			size = 0;

+ +	else {

+ +		size = parse_size64(param.size);

+ +		if (size == ULLONG_MAX) {

+ +			log_err(&ml, "%s: failed to parse size option '%s'\n",

+ +				devname, param.size);

+ +			return -EINVAL;

+ +		}

+ +		if (size > avail_dpa) {

+ +			log_err(&ml, "%s: '%s' exceeds available capacity\n",

+ +				devname, param.size);

+ +			if (!param.force)

+ +				return -ENOSPC;

+ +		}

+ +	}

+ +

+ +	/*

+ +	 * Find next free decoder, assumes cxl_decoder_foreach() is in

+ +	 * hardware instance-id order

+ +	 */

+ +	if (alloc_mode == DPA_ALLOC)

+ +		cxl_decoder_foreach(port, decoder) {

+ +			/* first 0-dpa_size is our target */

+ +			if (cxl_decoder_get_dpa_size(decoder) == 0) {

+ +				auto_target = decoder;

+ +				break;

+ +			}

+ +		}

+ +	else

+ +		cxl_decoder_foreach_reverse(port, decoder) {

+ +			/* nothing to free? */

+ +			if (!cxl_decoder_get_dpa_size(decoder))

+ +				continue;

+ +			/*

+ +			 * Active decoders can't be freed, and by definition all

+ +			 * previous decoders must also be active

+ +			 */

+ +			if (cxl_decoder_get_size(decoder))

+ +				break;

+ +			/* first dpa_size > 0 + disabled decoder is our target */

+ +			if (cxl_decoder_get_dpa_size(decoder) < ULLONG_MAX) {

+ +				auto_target = decoder;

+ +				break;

+ +			}

+ +		}

+ +

+ +	if (param.decoder_filter) {

+ +		unsigned long id;

+ +		char *end;

+ +

+ +		id = strtoul(param.decoder_filter, &end, 0);

+ +		/* allow for standalone ordinal decoder ids */

+ +		if (*end == '\0')

+ +			rc = snprintf(buf, sizeof(buf), "decoder%d.%ld",

+ +				      cxl_port_get_id(port), id);

+ +		else

+ +			rc = snprintf(buf, sizeof(buf), "%s",

+ +				      param.decoder_filter);

+ +

+ +		if (rc >= (int)sizeof(buf)) {

+ +			log_err(&ml, "%s: decoder filter '%s' too long\n",

+ +				devname, param.decoder_filter);

+ +			return -EINVAL;

+ +		}

+ +

+ +		if (alloc_mode == DPA_ALLOC)

+ +			cxl_decoder_foreach(port, decoder) {

+ +				target = util_cxl_decoder_filter(decoder, buf);

+ +				if (target)

+ +					break;

+ +			}

+ +		else

+ +			cxl_decoder_foreach_reverse(port, decoder) {

+ +				target = util_cxl_decoder_filter(decoder, buf);

+ +				if (target)

+ +					break;

+ +			}

+ +

+ +		if (!target) {

+ +			log_err(&ml, "%s: no match for decoder: '%s'\n",

+ +				devname, param.decoder_filter);

+ +			return -ENXIO;

+ +		}

+ +

+ +		if (target != auto_target) {

+ +			log_err(&ml, "%s: %s is out of sequence\n", devname,

+ +				cxl_decoder_get_devname(target));

+ +			if (!param.force)

+ +				return -EINVAL;

+ +		}

+ +	}

+ +

+ +	if (!target)

+ +		target = auto_target;

+ +

+ +	if (!target) {

+ +		log_err(&ml, "%s: no suitable decoder found\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	if (cxl_decoder_get_mode(target) != mode) {

+ +		rc = cxl_decoder_set_dpa_size(target, 0);

+ +		if (rc) {

+ +			log_err(&ml,

+ +				"%s: %s: failed to clear allocation to set mode\n",

+ +				devname, cxl_decoder_get_devname(target));

+ +			return rc;

+ +		}

+ +		rc = cxl_decoder_set_mode(target, mode);

+ +		if (rc) {

+ +			log_err(&ml, "%s: %s: failed to set %s mode\n", devname,

+ +				cxl_decoder_get_devname(target),

+ +				mode == CXL_DECODER_MODE_PMEM ? "pmem" : "ram");

+ +			return rc;

+ +		}

+ +	}

+ +

+ +	rc = cxl_decoder_set_dpa_size(target, size);

+ +	if (rc)

+ +		log_err(&ml, "%s: %s: failed to set dpa allocation\n", devname,

+ +			cxl_decoder_get_devname(target));

+ +	else {

+ +		struct json_object *jdev, *jdecoder;

+ +		unsigned long flags = 0;

+ +

+ +		if (actx->f_out == stdout && isatty(1))

+ +			flags |= UTIL_JSON_HUMAN;

+ +		jdev = util_cxl_memdev_to_json(memdev, flags);

+ +		jdecoder = util_cxl_decoder_to_json(target, flags);

+ +		if (!jdev || !jdecoder) {

+ +			json_object_put(jdev);

+ +			json_object_put(jdecoder);

+ +		} else {

+ +			json_object_object_add(jdev, "decoder", jdecoder);

+ +			json_object_array_add(actx->jdevs, jdev);

+ +		}

+ +	}

+ +	return rc;

+ +}

+ +

+ +static int action_reserve_dpa(struct cxl_memdev *memdev,

+ +			      struct action_context *actx)

+ +{

+ +	return __reserve_dpa(memdev, DPA_ALLOC, actx);

+ +}

+ +

+ +static int action_free_dpa(struct cxl_memdev *memdev,

+ +			   struct action_context *actx)

+ +{

+ +	return __reserve_dpa(memdev, DPA_FREE, actx);

+ +}

+ +

+  static int action_disable(struct cxl_memdev *memdev, struct action_context *actx)

+  {

+  	if (!cxl_memdev_is_enabled(memdev))

+ @@ -452,7 +702,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  		err++;

+  	}

+  

+ -	if (action == action_setpartition)

+ +	if (action == action_setpartition || action == action_reserve_dpa ||

+ +	    action == action_free_dpa)

+  		actx.jdevs = json_object_new_array();

+  

+  	if (err == argc) {

+ @@ -495,6 +746,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	count = 0;

+  

+  	for (i = 0; i < argc; i++) {

+ +		bool found = false;

+ +

+  		cxl_memdev_foreach(ctx, memdev) {

+  			const char *memdev_filter = NULL;

+  			const char *serial_filter = NULL;

+ @@ -507,6 +760,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  			if (!util_cxl_memdev_filter(memdev, memdev_filter,

+  						    serial_filter))

+  				continue;

+ +			found = true;

+  

+  			if (action == action_write) {

+  				single = memdev;

+ @@ -519,6 +773,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  			else if (rc && !err)

+  				err = rc;

+  		}

+ +		if (!found)

+ +			log_info(&ml, "no memdev matches %s\n", argv[i]);

+  	}

+  	rc = err;

+  

+ @@ -622,3 +878,25 @@ int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx)

+  

+  	return count >= 0 ? 0 : EXIT_FAILURE;

+  }

+ +

+ +int cmd_reserve_dpa(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(

+ +		argc, argv, ctx, action_reserve_dpa, reserve_dpa_options,

+ +		"cxl reserve-dpa <mem0> [<mem1>..<memn>] [<options>]");

+ +	log_info(&ml, "reservation completed on %d mem device%s\n",

+ +		 count >= 0 ? count : 0, count > 1 ? "s" : "");

+ +

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ +

+ +int cmd_free_dpa(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	int count = memdev_action(

+ +		argc, argv, ctx, action_free_dpa, free_dpa_options,

+ +		"cxl free-dpa <mem0> [<mem1>..<memn>] [<options>]");

+ +	log_info(&ml, "reservation release completed on %d mem device%s\n",

+ +		 count >= 0 ? count : 0, count > 1 ? "s" : "");

+ +

+ +	return count >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,86 @@ 

+ From 74a8134ef2dfa3c22c7e22b0bfd30b6a5cdf678b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:49 -0700

+ Subject: [PATCH 185/217] cxl/test: Update CXL memory parameters

+ 

+ In support of testing CXL region configurations cxl_test changed the size

+ of its root decoders and endpoints. Use the size of the first root decoder

+ to determine if this is an updated kernel.

+ 

+ Link: https://lore.kernel.org/r/165781816971.1555691.18362747345754213762.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/cxl-topology.sh | 32 +++++++++++++++++++++-----------

+  1 file changed, 21 insertions(+), 11 deletions(-)

+ 

+ diff --git a/test/cxl-topology.sh b/test/cxl-topology.sh

+ index ff11614..2583005 100644

+ --- a/test/cxl-topology.sh

+ +++ b/test/cxl-topology.sh

+ @@ -64,14 +64,9 @@ switch[2]=$(jq -r ".[] | .[\"ports:${bridge[1]}\"] | $port_sort | .[0].host" <<<

+  switch[3]=$(jq -r ".[] | .[\"ports:${bridge[1]}\"] | $port_sort | .[1].host" <<< $json)

+  

+  

+ -# check that all 8 cxl_test memdevs are enabled by default and have a

+ -# pmem size of 256M

+ -json=$($CXL list -b cxl_test -M)

+ -count=$(jq "map(select(.pmem_size == $((256 << 20)))) | length" <<< $json)

+ -((count == 8)) || err "$LINENO"

+ -

+ -

+  # validate the expected properties of the 4 root decoders

+ +# use the size of the first decoder to determine the cxl_test version /

+ +# properties

+  json=$($CXL list -b cxl_test -D -d root)

+  port_id=${root:4}

+  port_id_len=${#port_id}

+ @@ -80,26 +75,41 @@ count=$(jq "[ $decoder_sort | .[0] |

+  	select(.volatile_capable == true) |

+  	select(.size == $((256 << 20))) |

+  	select(.nr_targets == 1) ] | length" <<< $json)

+ -((count == 1)) || err "$LINENO"

+ +

+ +if [ $count -eq 1 ]; then

+ +	decoder_base_size=$((256 << 20))

+ +	pmem_size=$((256 << 20))

+ +else

+ +	decoder_base_size=$((1 << 30))

+ +	pmem_size=$((1 << 30))

+ +fi

+  

+  count=$(jq "[ $decoder_sort | .[1] |

+  	select(.volatile_capable == true) |

+ -	select(.size == $((512 << 20))) |

+ +	select(.size == $((decoder_base_size * 2))) |

+  	select(.nr_targets == 2) ] | length" <<< $json)

+  ((count == 1)) || err "$LINENO"

+  

+  count=$(jq "[ $decoder_sort | .[2] |

+  	select(.pmem_capable == true) |

+ -	select(.size == $((256 << 20))) |

+ +	select(.size == $decoder_base_size) |

+  	select(.nr_targets == 1) ] | length" <<< $json)

+  ((count == 1)) || err "$LINENO"

+  

+  count=$(jq "[ $decoder_sort | .[3] |

+  	select(.pmem_capable == true) |

+ -	select(.size == $((512 << 20))) |

+ +	select(.size == $((decoder_base_size * 2))) |

+  	select(.nr_targets == 2) ] | length" <<< $json)

+  ((count == 1)) || err "$LINENO"

+  

+ +

+ +# check that all 8 cxl_test memdevs are enabled by default and have a

+ +# pmem size of 256M, or 1G

+ +json=$($CXL list -b cxl_test -M)

+ +count=$(jq "map(select(.pmem_size == $pmem_size)) | length" <<< $json)

+ +((count == 8)) || err "$LINENO"

+ +

+ +

+  # check that switch ports disappear after all of their memdevs have been

+  # disabled, and return when the memdevs are enabled.

+  for s in ${switch[@]}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,169 @@ 

+ From eef9685245d172a80e9a5dfd830942824e7d40b4 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Thu, 14 Jul 2022 10:02:55 -0700

+ Subject: [PATCH 186/217] cxl/test: Checkout region setup/teardown

+ 

+ Exercise the fundamental region provisioning sysfs mechanisms of discovering

+ available DPA capacity, allocating DPA to a region, and programming HDM

+ decoders.

+ 

+ Link: https://lore.kernel.org/r/165781817516.1555691.3557156570639615515.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/cxl-region-sysfs.sh | 122 +++++++++++++++++++++++++++++++++++++++

+  test/meson.build         |   2 +

+  2 files changed, 124 insertions(+)

+  create mode 100644 test/cxl-region-sysfs.sh

+ 

+ diff --git a/test/cxl-region-sysfs.sh b/test/cxl-region-sysfs.sh

+ new file mode 100644

+ index 0000000..2582edb

+ --- /dev/null

+ +++ b/test/cxl-region-sysfs.sh

+ @@ -0,0 +1,122 @@

+ +#!/bin/bash

+ +# SPDX-License-Identifier: GPL-2.0

+ +# Copyright (C) 2022 Intel Corporation. All rights reserved.

+ +

+ +. $(dirname $0)/common

+ +

+ +rc=1

+ +

+ +set -ex

+ +

+ +trap 'err $LINENO' ERR

+ +

+ +check_prereq "jq"

+ +

+ +modprobe -r cxl_test

+ +modprobe cxl_test

+ +udevadm settle

+ +

+ +# THEORY OF OPERATION: Create a x8 interleave across the pmem capacity

+ +# of the 8 endpoints defined by cxl_test, commit the decoders (which

+ +# just stubs out the actual hardware programming aspect, but updates the

+ +# driver state), and then tear it all down again. As with other cxl_test

+ +# tests if the CXL topology in tools/testing/cxl/test/cxl.c ever changes

+ +# then the paired update must be made to this test.

+ +

+ +# find the root decoder that spans both test host-bridges and support pmem

+ +decoder=$($CXL list -b cxl_test -D -d root | jq -r ".[] |

+ +	  select(.pmem_capable == true) |

+ +	  select(.nr_targets == 2) |

+ +	  .decoder")

+ +

+ +# find the memdevs mapped by that decoder

+ +readarray -t mem < <($CXL list -M -d $decoder | jq -r ".[].memdev")

+ +

+ +# ask cxl reserve-dpa to allocate pmem capacity from each of those memdevs

+ +readarray -t endpoint < <($CXL reserve-dpa -t pmem ${mem[*]} -s $((256<<20)) |

+ +			  jq -r ".[] | .decoder.decoder")

+ +

+ +# instantiate an empty region

+ +region=$(cat /sys/bus/cxl/devices/$decoder/create_pmem_region)

+ +echo $region > /sys/bus/cxl/devices/$decoder/create_pmem_region

+ +uuidgen > /sys/bus/cxl/devices/$region/uuid

+ +

+ +# setup interleave geometry

+ +nr_targets=${#endpoint[@]}

+ +echo $nr_targets > /sys/bus/cxl/devices/$region/interleave_ways

+ +g=$(cat /sys/bus/cxl/devices/$decoder/interleave_granularity)

+ +echo $g > /sys/bus/cxl/devices/$region/interleave_granularity

+ +echo $((nr_targets * (256<<20))) > /sys/bus/cxl/devices/$region/size

+ +

+ +# grab the list of memdevs grouped by host-bridge interleave position

+ +port_dev0=$($CXL list -T -d $decoder | jq -r ".[] |

+ +	    .targets | .[] | select(.position == 0) | .target")

+ +port_dev1=$($CXL list -T -d $decoder | jq -r ".[] |

+ +	    .targets | .[] | select(.position == 1) | .target")

+ +readarray -t mem_sort0 < <($CXL list -M -p $port_dev0 | jq -r ".[] | .memdev")

+ +readarray -t mem_sort1 < <($CXL list -M -p $port_dev1 | jq -r ".[] | .memdev")

+ +

+ +# TODO: add a cxl list option to list memdevs in valid region provisioning

+ +# order, hardcode for now.

+ +mem_sort=()

+ +mem_sort[0]=${mem_sort0[0]}

+ +mem_sort[1]=${mem_sort1[0]}

+ +mem_sort[2]=${mem_sort0[2]}

+ +mem_sort[3]=${mem_sort1[2]}

+ +mem_sort[4]=${mem_sort0[1]}

+ +mem_sort[5]=${mem_sort1[1]}

+ +mem_sort[6]=${mem_sort0[3]}

+ +mem_sort[7]=${mem_sort1[3]}

+ +

+ +# TODO: use this alternative memdev ordering to validate a negative test for

+ +# specifying invalid positions of memdevs

+ +#mem_sort[2]=${mem_sort0[0]}

+ +#mem_sort[1]=${mem_sort1[0]}

+ +#mem_sort[0]=${mem_sort0[2]}

+ +#mem_sort[3]=${mem_sort1[2]}

+ +#mem_sort[4]=${mem_sort0[1]}

+ +#mem_sort[5]=${mem_sort1[1]}

+ +#mem_sort[6]=${mem_sort0[3]}

+ +#mem_sort[7]=${mem_sort1[3]}

+ +

+ +# re-generate the list of endpoint decoders in region position programming order

+ +endpoint=()

+ +for i in ${mem_sort[@]}

+ +do

+ +	readarray -O ${#endpoint[@]} -t endpoint < <($CXL list -Di -d endpoint -m $i | jq -r ".[] |

+ +						     select(.mode == \"pmem\") | .decoder")

+ +done

+ +

+ +# attach all endpoint decoders to the region

+ +pos=0

+ +for i in ${endpoint[@]}

+ +do

+ +	echo $i > /sys/bus/cxl/devices/$region/target$pos

+ +	pos=$((pos+1))

+ +done

+ +echo "$region added ${#endpoint[@]} targets: ${endpoint[@]}"

+ +

+ +# walk up the topology and commit all decoders

+ +echo 1 > /sys/bus/cxl/devices/$region/commit

+ +

+ +# walk down the topology and de-commit all decoders

+ +echo 0 > /sys/bus/cxl/devices/$region/commit

+ +

+ +# remove endpoints from the region

+ +pos=0

+ +for i in ${endpoint[@]}

+ +do

+ +	echo "" > /sys/bus/cxl/devices/$region/target$pos

+ +	pos=$((pos+1))

+ +done

+ +

+ +# release DPA capacity

+ +readarray -t endpoint < <($CXL free-dpa -t pmem ${mem[*]} |

+ +			  jq -r ".[] | .decoder.decoder")

+ +echo "$region released ${#endpoint[@]} targets: ${endpoint[@]}"

+ +

+ +# validate no WARN or lockdep report during the run

+ +log=$(journalctl -r -k --since "-$((SECONDS+1))s")

+ +grep -q "Call Trace" <<< $log && err "$LINENO"

+ +

+ +modprobe -r cxl_test

+ diff --git a/test/meson.build b/test/meson.build

+ index 210dcb0..3203d9c 100644

+ --- a/test/meson.build

+ +++ b/test/meson.build

+ @@ -151,6 +151,7 @@ max_extent = find_program('max_available_extent_ns.sh')

+  pfn_meta_errors = find_program('pfn-meta-errors.sh')

+  track_uuid = find_program('track-uuid.sh')

+  cxl_topo = find_program('cxl-topology.sh')

+ +cxl_sysfs = find_program('cxl-region-sysfs.sh')

+  

+  tests = [

+    [ 'libndctl',               libndctl,		  'ndctl' ],

+ @@ -176,6 +177,7 @@ tests = [

+    [ 'pfn-meta-errors.sh',     pfn_meta_errors,	  'ndctl' ],

+    [ 'track-uuid.sh',          track_uuid,	  'ndctl' ],

+    [ 'cxl-topology.sh',	      cxl_topo,		  'cxl'   ],

+ +  [ 'cxl-region-sysfs.sh',    cxl_sysfs,	  'cxl'   ],

+  ]

+  

+  if get_option('destructive').enabled()

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,121 @@ 

+ From f149f539e874415c0ec19b43a2c9bf2c56f3aa80 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 13 Jul 2022 14:37:58 -0600

+ Subject: [PATCH 187/217] cxl/test: add a test to {read,write,zero}-labels

+ 

+ Add a unit test to test writing, reading, and zeroing LSA aread for

+ cxl_test based memdevs using ndctl commands, and reading using cxl-cli

+ commands to exercise that route as much as possible.

+ 

+ Note that writing using cxl-cli requires a bit more enabling to enable,

+ as the corresponding nvdimm-bridge object will need to be disabled

+ first.

+ 

+ Link: https://lore.kernel.org/r/20220713203758.519892-1-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/cxl-labels.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++++

+  test/meson.build   |  2 ++

+  2 files changed, 71 insertions(+)

+  create mode 100644 test/cxl-labels.sh

+ 

+ diff --git a/test/cxl-labels.sh b/test/cxl-labels.sh

+ new file mode 100644

+ index 0000000..e782e2d

+ --- /dev/null

+ +++ b/test/cxl-labels.sh

+ @@ -0,0 +1,69 @@

+ +#!/bin/bash

+ +# SPDX-License-Identifier: GPL-2.0

+ +# Copyright (C) 2022 Intel Corporation. All rights reserved.

+ +

+ +. $(dirname $0)/common

+ +

+ +rc=1

+ +

+ +set -ex

+ +

+ +trap 'err $LINENO' ERR

+ +

+ +check_prereq "jq"

+ +

+ +modprobe -r cxl_test

+ +modprobe cxl_test

+ +udevadm settle

+ +

+ +test_label_ops()

+ +{

+ +	nmem="$1"

+ +	lsa=$(mktemp /tmp/lsa-$nmem.XXXX)

+ +	lsa_read=$(mktemp /tmp/lsa-read-$nmem.XXXX)

+ +

+ +	# determine LSA size

+ +	"$NDCTL" read-labels -o "$lsa_read" "$nmem"

+ +	lsa_size=$(stat -c %s "$lsa_read")

+ +

+ +	dd "if=/dev/urandom" "of=$lsa" "bs=$lsa_size" "count=1"

+ +	"$NDCTL" write-labels -i "$lsa" "$nmem"

+ +	"$NDCTL" read-labels -o "$lsa_read" "$nmem"

+ +

+ +	# compare what was written vs read

+ +	diff "$lsa" "$lsa_read"

+ +

+ +	# zero the LSA and test

+ +	"$NDCTL" zero-labels "$nmem"

+ +	dd "if=/dev/zero" "of=$lsa" "bs=$lsa_size" "count=1"

+ +	"$NDCTL" read-labels -o "$lsa_read" "$nmem"

+ +	diff "$lsa" "$lsa_read"

+ +

+ +	# cleanup

+ +	rm "$lsa" "$lsa_read"

+ +}

+ +

+ +test_label_ops_cxl()

+ +{

+ +	mem="$1"

+ +	lsa_read=$(mktemp /tmp/lsa-read-$mem.XXXX)

+ +

+ +	"$CXL" read-labels -o "$lsa_read" "$mem"

+ +	rm "$lsa_read"

+ +}

+ +

+ +# test reading labels directly through cxl-cli

+ +readarray -t mems < <("$CXL" list -b cxl_test -Mi | jq -r '.[].memdev')

+ +

+ +for mem in ${mems[@]}; do

+ +	test_label_ops_cxl "$mem"

+ +done

+ +

+ +# find nmem devices corresponding to cxl memdevs

+ +readarray -t nmems < <("$NDCTL" list -b cxl_test -Di | jq -r '.[].dev')

+ +

+ +for nmem in ${nmems[@]}; do

+ +	test_label_ops "$nmem"

+ +done

+ +

+ +modprobe -r cxl_test

+ diff --git a/test/meson.build b/test/meson.build

+ index 3203d9c..b382f46 100644

+ --- a/test/meson.build

+ +++ b/test/meson.build

+ @@ -152,6 +152,7 @@ pfn_meta_errors = find_program('pfn-meta-errors.sh')

+  track_uuid = find_program('track-uuid.sh')

+  cxl_topo = find_program('cxl-topology.sh')

+  cxl_sysfs = find_program('cxl-region-sysfs.sh')

+ +cxl_labels = find_program('cxl-labels.sh')

+  

+  tests = [

+    [ 'libndctl',               libndctl,		  'ndctl' ],

+ @@ -178,6 +179,7 @@ tests = [

+    [ 'track-uuid.sh',          track_uuid,	  'ndctl' ],

+    [ 'cxl-topology.sh',	      cxl_topo,		  'cxl'   ],

+    [ 'cxl-region-sysfs.sh',    cxl_sysfs,	  'cxl'   ],

+ +  [ 'cxl-labels.sh',          cxl_labels,	  'cxl'   ],

+  ]

+  

+  if get_option('destructive').enabled()

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,93 @@ 

+ From db55c5254d932d8d1be1fc082ea7a919def47a5d Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Tue, 26 Jul 2022 18:54:54 -0700

+ Subject: [PATCH 188/217] cxl/list: Clarify "-B" vs "-P -p root"

+ 

+ Matthew notes that 'cxl list' documentation claims that 'cxl list -B' and

+ 'cxl list -P -p root' are equivalent. Which they are not:

+ 

+ $ cxl list -B

+ [

+   {

+     "bus":"root0",

+     "provider":"ACPI.CXL"

+   }

+ ]

+ 

+ $ cxl list -P -p root

+ [

+   {

+     "bus":"root0",

+     "provider":"ACPI.CXL",

+     "ports:root0":[

+       {

+         "port":"port1",

+         "host":"ACPI0016:00"

+       }

+     ]

+   }

+ ]

+ 

+ Clarify that '--single' needs to be appended to '-P -p root' to make it

+ equivalent to 'cxl list -B'. This is due to the behavior that listing ports

+ includes all descendants of a port that matches the filter. In the case of

+ '-P -p root' that results in all enabled ports.

+ 

+ $ cxl list -P -p root -S

+ [

+   {

+     "bus":"root0",

+     "provider":"ACPI.CXL"

+   }

+ ]

+ 

+ Link: https://lore.kernel.org/r/165888675979.3375698.5785835464908538946.stgit@dwillia2-xfh.jf.intel.com

+ Cc: Adam Manzanares <a.manzanares@samsung.com>

+ Reported-by: Matthew Ho <sunfishho12@gmail.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt | 20 ++++++++++++++------

+  1 file changed, 14 insertions(+), 6 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index f6aba0c..088ea70 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -255,19 +255,27 @@ OPTIONS

+  --port=::

+  	Specify CXL Port device name(s), device id(s), and or port type

+  	names to filter the listing. The supported port type names are "root"

+ -	and "switch". Note that since a bus object is also a port, the following

+ -	two syntaxes are equivalent:

+ +	and "switch". Note that a bus object is also a port, so the

+ +	following two syntaxes are equivalent:

+  ----

+  # cxl list -B

+ -# cxl list -P -p root

+ +# cxl list -P -p root -S

+  ----

+ -	Additionally, endpoint objects are also ports so the following commands

+ -	are also equivalent.

+ +	...where the '-S/--single' is required since descendant ports are always

+ +	included in a port listing and '-S/--single' stops after listing the

+ +	bus.  Additionally, endpoint objects are ports so the following commands

+ +	are equivalent, and no '-S/--single' is required as endpoint ports are

+ +	terminal:

+  ----

+  # cxl list -E

+  # cxl list -P -p endpoint

+  ----

+ -	By default, only 'switch' ports are listed.

+ +	By default, only 'switch' ports are listed, i.e.

+ +----

+ +# cxl list -P

+ +# cxl list -P -p switch

+ +----

+ +	...are equivalent.

+  

+  -S::

+  --single::

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,45 @@ 

+ From 0a43bfdf030b4a84fce562462944a9a44888afaa Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:04 -0600

+ Subject: [PATCH 189/217] libcxl: add a depth attribute to cxl_port

+ 

+ Add a depth attribute to the cxl_port structure, that can be used for

+ calculating its distance from the root port, and will be needed for

+ interleave granularity calculations during region creation.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-2-vishal.l.verma@intel.com

+ Suggested-by: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c  | 1 +

+  cxl/lib/private.h | 1 +

+  2 files changed, 2 insertions(+)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index e52896f..145c6ba 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -744,6 +744,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,

+  	port->type = type;

+  	port->parent = parent_port;

+  	port->type = type;

+ +	port->depth = parent_port ? parent_port->depth + 1 : 0;

+  

+  	list_head_init(&port->child_ports);

+  	list_head_init(&port->endpoints);

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index f6d4573..832a815 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -66,6 +66,7 @@ struct cxl_port {

+  	int decoders_init;

+  	int dports_init;

+  	int nr_dports;

+ +	int depth;

+  	struct cxl_ctx *ctx;

+  	struct cxl_bus *bus;

+  	enum cxl_port_type type;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,82 @@ 

+ From a951e6ddaec82dc0c33fb4e665e20f8fe4ce9caf Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:05 -0600

+ Subject: [PATCH 190/217] cxl/port: Consolidate the debug option in cxl-port

+  man pages

+ 

+ In preparation for additional commands that implement the --debug

+ option, consolidate the option description from the cxl-port man pages

+ into an include.

+ 

+ The port man pages also mentioned the debug option requiring a build

+ with debug enabled, which wasn't true - so remove that part.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-3-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-disable-port.txt | 5 +----

+  Documentation/cxl/cxl-enable-port.txt  | 5 +----

+  Documentation/cxl/debug-option.txt     | 4 ++++

+  Documentation/cxl/meson.build          | 1 +

+  4 files changed, 7 insertions(+), 8 deletions(-)

+  create mode 100644 Documentation/cxl/debug-option.txt

+ 

+ diff --git a/Documentation/cxl/cxl-disable-port.txt b/Documentation/cxl/cxl-disable-port.txt

+ index ac56f20..7a22efc 100644

+ --- a/Documentation/cxl/cxl-disable-port.txt

+ +++ b/Documentation/cxl/cxl-disable-port.txt

+ @@ -30,10 +30,7 @@ OPTIONS

+  	firmware and disabling an active device is akin to force removing memory

+  	from a running system.

+  

+ ---debug::

+ -	If the cxl tool was built with debug disabled, turn on debug

+ -	messages.

+ -

+ +include::debug-option.txt[]

+  

+  include::../copyright.txt[]

+  

+ diff --git a/Documentation/cxl/cxl-enable-port.txt b/Documentation/cxl/cxl-enable-port.txt

+ index 9a37cef..50b53d1 100644

+ --- a/Documentation/cxl/cxl-enable-port.txt

+ +++ b/Documentation/cxl/cxl-enable-port.txt

+ @@ -31,10 +31,7 @@ OPTIONS

+  	memdev is only enabled after all CXL ports in its device topology

+  	ancestry are enabled.

+  

+ ---debug::

+ -	If the cxl tool was built with debug enabled, turn on debug

+ -	messages.

+ -

+ +include::debug-option.txt[]

+  

+  include::../copyright.txt[]

+  

+ diff --git a/Documentation/cxl/debug-option.txt b/Documentation/cxl/debug-option.txt

+ new file mode 100644

+ index 0000000..70b922f

+ --- /dev/null

+ +++ b/Documentation/cxl/debug-option.txt

+ @@ -0,0 +1,4 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +--debug::

+ +	Turn on additional debug messages including library debug.

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index d019dfc..423be90 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -22,6 +22,7 @@ filedeps = [

+    '../copyright.txt',

+    'memdev-option.txt',

+    'labels-options.txt',

+ +  'debug-option.txt',

+  ]

+  

+  cxl_manpages = [

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,74 @@ 

+ From 14565442634cfab0aac8823129a175be572fb11e Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:06 -0600

+ Subject: [PATCH 191/217] cxl/memdev: refactor decoder mode string parsing

+ 

+ In preparation for create-region to use a similar decoder mode string

+ to enum operation, break out the mode string parsing into its own inline

+ helper in libcxl.h, and call it from memdev.c:__reserve_dpa().

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-4-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/libcxl.h | 13 +++++++++++++

+  cxl/memdev.c | 11 ++---------

+  2 files changed, 15 insertions(+), 9 deletions(-)

+ 

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 33a216e..c1f8d14 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -4,6 +4,7 @@

+  #define _LIBCXL_H_

+  

+  #include <stdarg.h>

+ +#include <string.h>

+  #include <unistd.h>

+  #include <stdbool.h>

+  

+ @@ -154,6 +155,18 @@ static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode)

+  	return names[mode];

+  }

+  

+ +static inline enum cxl_decoder_mode

+ +cxl_decoder_mode_from_ident(const char *ident)

+ +{

+ +	if (strcmp(ident, "ram") == 0)

+ +		return CXL_DECODER_MODE_RAM;

+ +	else if (strcmp(ident, "volatile") == 0)

+ +		return CXL_DECODER_MODE_RAM;

+ +	else if (strcmp(ident, "pmem") == 0)

+ +		return CXL_DECODER_MODE_PMEM;

+ +	return CXL_DECODER_MODE_NONE;

+ +}

+ +

+  enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder);

+  int cxl_decoder_set_mode(struct cxl_decoder *decoder,

+  			 enum cxl_decoder_mode mode);

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index e42f554..0b3ad02 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -154,15 +154,8 @@ static int __reserve_dpa(struct cxl_memdev *memdev,

+  	int rc;

+  

+  	if (param.type) {

+ -		if (strcmp(param.type, "ram") == 0)

+ -			mode = CXL_DECODER_MODE_RAM;

+ -		else if (strcmp(param.type, "volatile") == 0)

+ -			mode = CXL_DECODER_MODE_RAM;

+ -		else if (strcmp(param.type, "ram") == 0)

+ -			mode = CXL_DECODER_MODE_RAM;

+ -		else if (strcmp(param.type, "pmem") == 0)

+ -			mode = CXL_DECODER_MODE_PMEM;

+ -		else {

+ +		mode = cxl_decoder_mode_from_ident(param.type);

+ +		if (mode == CXL_DECODER_MODE_NONE) {

+  			log_err(&ml, "%s: unsupported type: %s\n", devname,

+  				param.type);

+  			return -EINVAL;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,651 @@ 

+ From d25dc6d7956bc022d7e4c4453416c52368df291d Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:07 -0600

+ Subject: [PATCH 192/217] libcxl: Introduce libcxl region and mapping objects

+ 

+ Add a cxl_region object to libcxl that represents a CXL region. CXL

+ regions are made up of one or more cxl_memdev 'targets'. The

+ relationship between a target and a region is conveyed with a

+ cxl_memdev_mapping object.

+ 

+ CXL regions are childeren of root decoders, and are organized as such.

+ Mapping objects are childeren of a CXL region.  Introduce the two

+ classes of objects themselves, and common accessors related to them.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-5-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .clang-format      |   2 +

+  cxl/lib/libcxl.c   | 442 ++++++++++++++++++++++++++++++++++++++++++++-

+  cxl/lib/libcxl.sym |  20 ++

+  cxl/lib/private.h  |  35 ++++

+  cxl/libcxl.h       |  41 +++++

+  5 files changed, 530 insertions(+), 10 deletions(-)

+ 

+ diff --git a/.clang-format b/.clang-format

+ index 7254a1b..b6169e1 100644

+ --- a/.clang-format

+ +++ b/.clang-format

+ @@ -86,6 +86,8 @@ ForEachMacros:

+    - 'cxl_dport_foreach'

+    - 'cxl_endpoint_foreach'

+    - 'cxl_port_foreach_all'

+ +  - 'cxl_region_foreach'

+ +  - 'cxl_region_foreach_safe'

+    - 'daxctl_dev_foreach'

+    - 'daxctl_mapping_foreach'

+    - 'daxctl_region_foreach'

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 145c6ba..ad98188 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -79,6 +79,38 @@ static void free_target(struct cxl_target *target, struct list_head *head)

+  	free(target);

+  }

+  

+ +static void free_region(struct cxl_region *region, struct list_head *head)

+ +{

+ +	struct cxl_memdev_mapping *mapping, *_m;

+ +

+ +	list_for_each_safe(&region->mappings, mapping, _m, list) {

+ +		list_del_from(&region->mappings, &mapping->list);

+ +		free(mapping);

+ +	}

+ +	if (head)

+ +		list_del_from(head, &region->list);

+ +	kmod_module_unref(region->module);

+ +	free(region->dev_buf);

+ +	free(region->dev_path);

+ +	free(region);

+ +}

+ +

+ +static void free_stale_regions(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_region *region, *_r;

+ +

+ +	list_for_each_safe(&decoder->stale_regions, region, _r, list)

+ +		free_region(region, &decoder->stale_regions);

+ +}

+ +

+ +static void free_regions(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_region *region, *_r;

+ +

+ +	list_for_each_safe(&decoder->regions, region, _r, list)

+ +		free_region(region, &decoder->regions);

+ +}

+ +

+  static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)

+  {

+  	struct cxl_target *target, *_t;

+ @@ -87,6 +119,8 @@ static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)

+  		list_del_from(head, &decoder->list);

+  	list_for_each_safe(&decoder->targets, target, _t, list)

+  		free_target(target, &decoder->targets);

+ +	free_regions(decoder);

+ +	free_stale_regions(decoder);

+  	free(decoder->dev_buf);

+  	free(decoder->dev_path);

+  	free(decoder);

+ @@ -304,6 +338,402 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)

+  	ctx->ctx.log_priority = priority;

+  }

+  

+ +static int is_enabled(const char *drvpath)

+ +{

+ +	struct stat st;

+ +

+ +	if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode))

+ +		return 0;

+ +	else

+ +		return 1;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_is_enabled(struct cxl_region *region)

+ +{

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	char *path = region->dev_buf;

+ +	int len = region->buf_len;

+ +

+ +	if (snprintf(path, len, "%s/driver", region->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", cxl_region_get_devname(region));

+ +		return 0;

+ +	}

+ +

+ +	return is_enabled(path);

+ +}

+ +

+ +CXL_EXPORT int cxl_region_disable(struct cxl_region *region)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +

+ +	util_unbind(region->dev_path, ctx);

+ +

+ +	if (cxl_region_is_enabled(region)) {

+ +		err(ctx, "%s: failed to disable\n", devname);

+ +		return -EBUSY;

+ +	}

+ +

+ +	dbg(ctx, "%s: disabled\n", devname);

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_enable(struct cxl_region *region)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	char *path = region->dev_buf;

+ +	int len = region->buf_len;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +	u64 resource = ULLONG_MAX;

+ +

+ +	if (cxl_region_is_enabled(region))

+ +		return 0;

+ +

+ +	util_bind(devname, region->module, "cxl", ctx);

+ +

+ +	if (!cxl_region_is_enabled(region)) {

+ +		err(ctx, "%s: failed to enable\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	/*

+ +	 * Currently 'resource' is the only attr that may change after enabling.

+ +	 * Just refresh it here. If there are additional resources that need

+ +	 * to be refreshed here later, split these out into a common helper

+ +	 * for this and add_cxl_region()

+ +	 */

+ +	if (snprintf(path, len, "%s/resource", region->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return 0;

+ +	}

+ +

+ +	if (sysfs_read_attr(ctx, path, buf) == 0)

+ +		resource = strtoull(buf, NULL, 0);

+ +

+ +	if (resource < ULLONG_MAX)

+ +		region->start = resource;

+ +

+ +	dbg(ctx, "%s: enabled\n", devname);

+ +

+ +	return 0;

+ +}

+ +

+ +static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)

+ +{

+ +	const char *devname = devpath_to_devname(cxlregion_base);

+ +	char *path = calloc(1, strlen(cxlregion_base) + 100);

+ +	struct cxl_region *region, *region_dup, *_r;

+ +	struct cxl_decoder *decoder = parent;

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	char buf[SYSFS_ATTR_SIZE];

+ +	u64 resource = ULLONG_MAX;

+ +

+ +	dbg(ctx, "%s: base: \'%s\'\n", devname, cxlregion_base);

+ +

+ +	if (!path)

+ +		return NULL;

+ +

+ +	region = calloc(1, sizeof(*region));

+ +	if (!region)

+ +		goto err;

+ +

+ +	region->id = id;

+ +	region->ctx = ctx;

+ +	region->decoder = decoder;

+ +	list_head_init(&region->mappings);

+ +

+ +	region->dev_path = strdup(cxlregion_base);

+ +	if (!region->dev_path)

+ +		goto err;

+ +

+ +	region->dev_buf = calloc(1, strlen(cxlregion_base) + 50);

+ +	if (!region->dev_buf)

+ +		goto err;

+ +	region->buf_len = strlen(cxlregion_base) + 50;

+ +

+ +	sprintf(path, "%s/size", cxlregion_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		region->size = ULLONG_MAX;

+ +	else

+ +		region->size = strtoull(buf, NULL, 0);

+ +

+ +	sprintf(path, "%s/resource", cxlregion_base);

+ +	if (sysfs_read_attr(ctx, path, buf) == 0)

+ +		resource = strtoull(buf, NULL, 0);

+ +

+ +	if (resource < ULLONG_MAX)

+ +		region->start = resource;

+ +

+ +	sprintf(path, "%s/uuid", cxlregion_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		goto err;

+ +	if (strlen(buf) && uuid_parse(buf, region->uuid) < 0) {

+ +		dbg(ctx, "%s:%s\n", path, buf);

+ +		goto err;

+ +	}

+ +

+ +	sprintf(path, "%s/interleave_granularity", cxlregion_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		region->interleave_granularity = UINT_MAX;

+ +	else

+ +		region->interleave_granularity = strtoul(buf, NULL, 0);

+ +

+ +	sprintf(path, "%s/interleave_ways", cxlregion_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		region->interleave_ways = UINT_MAX;

+ +	else

+ +		region->interleave_ways = strtoul(buf, NULL, 0);

+ +

+ +	sprintf(path, "%s/commit", cxlregion_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		region->decode_state = CXL_DECODE_UNKNOWN;

+ +	else

+ +		region->decode_state = strtoul(buf, NULL, 0);

+ +

+ +	sprintf(path, "%s/modalias", cxlregion_base);

+ +	if (sysfs_read_attr(ctx, path, buf) == 0)

+ +		region->module = util_modalias_to_module(ctx, buf);

+ +

+ +	cxl_region_foreach_safe(decoder, region_dup, _r)

+ +		if (region_dup->id == region->id) {

+ +			list_del_from(&decoder->regions, &region_dup->list);

+ +			list_add_tail(&decoder->stale_regions,

+ +				      &region_dup->list);

+ +			break;

+ +		}

+ +

+ +	list_add(&decoder->regions, &region->list);

+ +

+ +	return region;

+ +err:

+ +	free(region->dev_path);

+ +	free(region->dev_buf);

+ +	free(region);

+ +	free(path);

+ +	return NULL;

+ +}

+ +

+ +static void cxl_regions_init(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +

+ +	if (decoder->regions_init)

+ +		return;

+ +

+ +	/* Only root port decoders may have child regions */

+ +	if (!cxl_port_is_root(port))

+ +		return;

+ +

+ +	decoder->regions_init = 1;

+ +

+ +	sysfs_device_parse(ctx, decoder->dev_path, "region", decoder,

+ +			   add_cxl_region);

+ +}

+ +

+ +CXL_EXPORT struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder)

+ +{

+ +	cxl_regions_init(decoder);

+ +

+ +	return list_top(&decoder->regions, struct cxl_region, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_region *cxl_region_get_next(struct cxl_region *region)

+ +{

+ +	struct cxl_decoder *decoder = region->decoder;

+ +

+ +	return list_next(&decoder->regions, region, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region)

+ +{

+ +	return region->ctx;

+ +}

+ +

+ +CXL_EXPORT struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region)

+ +{

+ +	return region->decoder;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_get_id(struct cxl_region *region)

+ +{

+ +	return region->id;

+ +}

+ +

+ +CXL_EXPORT const char *cxl_region_get_devname(struct cxl_region *region)

+ +{

+ +	return devpath_to_devname(region->dev_path);

+ +}

+ +

+ +CXL_EXPORT void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu)

+ +{

+ +	memcpy(uu, region->uuid, sizeof(uuid_t));

+ +}

+ +

+ +CXL_EXPORT unsigned long long cxl_region_get_size(struct cxl_region *region)

+ +{

+ +	return region->size;

+ +}

+ +

+ +CXL_EXPORT unsigned long long cxl_region_get_resource(struct cxl_region *region)

+ +{

+ +	return region->start;

+ +}

+ +

+ +CXL_EXPORT unsigned int

+ +cxl_region_get_interleave_ways(struct cxl_region *region)

+ +{

+ +	return region->interleave_ways;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_decode_is_committed(struct cxl_region *region)

+ +{

+ +	return (region->decode_state == CXL_DECODE_COMMIT) ? 1 : 0;

+ +}

+ +

+ +CXL_EXPORT unsigned int

+ +cxl_region_get_interleave_granularity(struct cxl_region *region)

+ +{

+ +	return region->interleave_granularity;

+ +}

+ +

+ +static struct cxl_decoder *__cxl_port_match_decoder(struct cxl_port *port,

+ +						    const char *ident)

+ +{

+ +	struct cxl_decoder *decoder;

+ +

+ +	cxl_decoder_foreach(port, decoder)

+ +		if (strcmp(cxl_decoder_get_devname(decoder), ident) == 0)

+ +			return decoder;

+ +

+ +	return NULL;

+ +}

+ +

+ +static struct cxl_decoder *cxl_port_find_decoder(struct cxl_port *port,

+ +						 const char *ident)

+ +{

+ +	struct cxl_decoder *decoder;

+ +	struct cxl_endpoint *ep;

+ +

+ +	/* First, check decoders directly under @port */

+ +	decoder = __cxl_port_match_decoder(port, ident);

+ +	if (decoder)

+ +		return decoder;

+ +

+ +	/* Next, iterate over the endpoints under @port */

+ +	cxl_endpoint_foreach(port, ep) {

+ +		decoder = __cxl_port_match_decoder(cxl_endpoint_get_port(ep),

+ +						   ident);

+ +		if (decoder)

+ +			return decoder;

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+ +static struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,

+ +						   const char *ident)

+ +{

+ +	struct cxl_bus *bus;

+ +

+ +	cxl_bus_foreach(ctx, bus) {

+ +		struct cxl_decoder *decoder;

+ +		struct cxl_port *port, *top;

+ +

+ +		port = cxl_bus_get_port(bus);

+ +		decoder = cxl_port_find_decoder(port, ident);

+ +		if (decoder)

+ +			return decoder;

+ +

+ +		top = port;

+ +		cxl_port_foreach_all (top, port) {

+ +			decoder = cxl_port_find_decoder(port, ident);

+ +			if (decoder)

+ +				return decoder;

+ +		}

+ +	}

+ +

+ +	return NULL;

+ +}

+ +

+ +static void cxl_mappings_init(struct cxl_region *region)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	char *mapping_path, buf[SYSFS_ATTR_SIZE];

+ +	unsigned int i;

+ +

+ +	if (region->mappings_init)

+ +		return;

+ +	region->mappings_init = 1;

+ +

+ +	mapping_path = calloc(1, strlen(region->dev_path) + 100);

+ +	if (!mapping_path) {

+ +		err(ctx, "%s: allocation failure\n", devname);

+ +		return;

+ +	}

+ +

+ +	for (i = 0; i < region->interleave_ways; i++) {

+ +		struct cxl_memdev_mapping *mapping;

+ +		struct cxl_decoder *decoder;

+ +

+ +		sprintf(mapping_path, "%s/target%d", region->dev_path, i);

+ +		if (sysfs_read_attr(ctx, mapping_path, buf) < 0) {

+ +			err(ctx, "%s: failed to read target%d\n", devname, i);

+ +			continue;

+ +		}

+ +

+ +		decoder = cxl_decoder_get_by_name(ctx, buf);

+ +		if (!decoder) {

+ +			err(ctx, "%s target%d: %s lookup failure\n",

+ +			    devname, i, buf);

+ +			continue;

+ +		}

+ +

+ +		mapping = calloc(1, sizeof(*mapping));

+ +		if (!mapping) {

+ +			err(ctx, "%s target%d: allocation failure\n", devname, i);

+ +			continue;

+ +		}

+ +

+ +		mapping->region = region;

+ +		mapping->decoder = decoder;

+ +		mapping->position = i;

+ +		list_add(&region->mappings, &mapping->list);

+ +	}

+ +	free(mapping_path);

+ +}

+ +

+ +CXL_EXPORT struct cxl_memdev_mapping *

+ +cxl_mapping_get_first(struct cxl_region *region)

+ +{

+ +	cxl_mappings_init(region);

+ +

+ +	return list_top(&region->mappings, struct cxl_memdev_mapping, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_memdev_mapping *

+ +cxl_mapping_get_next(struct cxl_memdev_mapping *mapping)

+ +{

+ +	struct cxl_region *region = mapping->region;

+ +

+ +	return list_next(&region->mappings, mapping, list);

+ +}

+ +

+ +CXL_EXPORT struct cxl_decoder *

+ +cxl_mapping_get_decoder(struct cxl_memdev_mapping *mapping)

+ +{

+ +	return mapping->decoder;

+ +}

+ +

+ +CXL_EXPORT unsigned int

+ +cxl_mapping_get_position(struct cxl_memdev_mapping *mapping)

+ +{

+ +	return mapping->position;

+ +}

+ +

+  static void *add_cxl_pmem(void *parent, int id, const char *br_base)

+  {

+  	const char *devname = devpath_to_devname(br_base);

+ @@ -681,16 +1111,6 @@ CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)

+  	return memdev->lsa_size;

+  }

+  

+ -static int is_enabled(const char *drvpath)

+ -{

+ -	struct stat st;

+ -

+ -	if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode))

+ -		return 0;

+ -	else

+ -		return 1;

+ -}

+ -

+  CXL_EXPORT int cxl_memdev_is_enabled(struct cxl_memdev *memdev)

+  {

+  	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);

+ @@ -940,6 +1360,8 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	decoder->ctx = ctx;

+  	decoder->port = port;

+  	list_head_init(&decoder->targets);

+ +	list_head_init(&decoder->regions);

+ +	list_head_init(&decoder->stale_regions);

+  

+  	decoder->dev_path = strdup(cxldecoder_base);

+  	if (!decoder->dev_path)

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 7712de0..e410298 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -177,4 +177,24 @@ global:

+  	cxl_decoder_get_prev;

+  	cxl_decoder_set_dpa_size;

+  	cxl_decoder_set_mode;

+ +	cxl_region_get_first;

+ +	cxl_region_get_next;

+ +	cxl_region_decode_is_committed;

+ +	cxl_region_is_enabled;

+ +	cxl_region_disable;

+ +	cxl_region_enable;

+ +	cxl_region_get_ctx;

+ +	cxl_region_get_decoder;

+ +	cxl_region_get_id;

+ +	cxl_region_get_devname;

+ +	cxl_region_get_uuid;

+ +	cxl_region_get_size;

+ +	cxl_region_get_resource;

+ +	cxl_region_get_interleave_ways;

+ +	cxl_region_get_interleave_granularity;

+ +	cxl_mapping_get_first;

+ +	cxl_mapping_get_next;

+ +	cxl_mapping_get_decoder;

+ +	cxl_mapping_get_region;

+ +	cxl_mapping_get_position;

+  } LIBCXL_2;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 832a815..5e2fdd5 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -116,7 +116,42 @@ struct cxl_decoder {

+  	bool accelmem_capable;

+  	bool locked;

+  	enum cxl_decoder_target_type target_type;

+ +	int regions_init;

+  	struct list_head targets;

+ +	struct list_head regions;

+ +	struct list_head stale_regions;

+ +};

+ +

+ +enum cxl_decode_state {

+ +	CXL_DECODE_UNKNOWN = -1,

+ +	CXL_DECODE_RESET = 0,

+ +	CXL_DECODE_COMMIT,

+ +};

+ +

+ +struct cxl_region {

+ +	struct cxl_decoder *decoder;

+ +	struct list_node list;

+ +	int mappings_init;

+ +	struct cxl_ctx *ctx;

+ +	void *dev_buf;

+ +	size_t buf_len;

+ +	char *dev_path;

+ +	int id;

+ +	uuid_t uuid;

+ +	u64 start;

+ +	u64 size;

+ +	unsigned int interleave_ways;

+ +	unsigned int interleave_granularity;

+ +	enum cxl_decode_state decode_state;

+ +	struct kmod_module *module;

+ +	struct list_head mappings;

+ +};

+ +

+ +struct cxl_memdev_mapping {

+ +	struct cxl_region *region;

+ +	struct cxl_decoder *decoder;

+ +	unsigned int position;

+ +	struct list_node list;

+  };

+  

+  enum cxl_cmd_query_status {

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index c1f8d14..19d94e4 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -237,6 +237,47 @@ int cxl_memdev_is_enabled(struct cxl_memdev *memdev);

+  	for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL;        \

+  	     endpoint = cxl_endpoint_get_next(endpoint))

+  

+ +struct cxl_region;

+ +struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder);

+ +struct cxl_region *cxl_region_get_next(struct cxl_region *region);

+ +int cxl_region_decode_is_committed(struct cxl_region *region);

+ +int cxl_region_is_enabled(struct cxl_region *region);

+ +int cxl_region_disable(struct cxl_region *region);

+ +int cxl_region_enable(struct cxl_region *region);

+ +struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region);

+ +struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region);

+ +int cxl_region_get_id(struct cxl_region *region);

+ +const char *cxl_region_get_devname(struct cxl_region *region);

+ +void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu);

+ +unsigned long long cxl_region_get_size(struct cxl_region *region);

+ +unsigned long long cxl_region_get_resource(struct cxl_region *region);

+ +unsigned int cxl_region_get_interleave_ways(struct cxl_region *region);

+ +unsigned int cxl_region_get_interleave_granularity(struct cxl_region *region);

+ +

+ +#define cxl_region_foreach(decoder, region)                                    \

+ +	for (region = cxl_region_get_first(decoder); region != NULL;           \

+ +	     region = cxl_region_get_next(region))

+ +

+ +#define cxl_region_foreach_safe(decoder, region, _region)                      \

+ +	for (region = cxl_region_get_first(decoder),                           \

+ +	     _region = region ? cxl_region_get_next(region) : NULL;            \

+ +	     region != NULL;                                                   \

+ +	     region = _region,                                                 \

+ +	     _region = _region ? cxl_region_get_next(_region) : NULL)

+ +

+ +struct cxl_memdev_mapping;

+ +struct cxl_memdev_mapping *cxl_mapping_get_first(struct cxl_region *region);

+ +struct cxl_memdev_mapping *

+ +cxl_mapping_get_next(struct cxl_memdev_mapping *mapping);

+ +struct cxl_decoder *cxl_mapping_get_decoder(struct cxl_memdev_mapping *mapping);

+ +struct cxl_region *cxl_mapping_get_region(struct cxl_memdev_mapping *mapping);

+ +unsigned int cxl_mapping_get_position(struct cxl_memdev_mapping *mapping);

+ +

+ +#define cxl_mapping_foreach(region, mapping) \

+ +        for (mapping = cxl_mapping_get_first(region); \

+ +             mapping != NULL; \

+ +             mapping = cxl_mapping_get_next(mapping))

+ +

+  struct cxl_cmd;

+  const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);

+  struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,548 @@ 

+ From c0f2b36c481119e06eaec60dda17a42100a81ebc Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:08 -0600

+ Subject: [PATCH 193/217] cxl-cli: add region listing support

+ 

+ Add cxl_region -> json and cxl_mapping -> json emitter helpers, and

+ teach cxl_filter_walk about cxl_regions. With these in place, 'cxl-list'

+ can now emit json objects for CXL regions. They can be top-level objects

+ if requested by themselves, or nested under root-decoders, if listed

+ along with decoders. Allow a plain 'cxl list' command to imply

+ '--regions'.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-6-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt |  13 ++-

+  cxl/filter.c                   | 158 +++++++++++++++++++++++++++++++--

+  cxl/filter.h                   |   4 +

+  cxl/json.c                     | 114 ++++++++++++++++++++++++

+  cxl/json.h                     |   5 ++

+  cxl/list.c                     |  25 +++---

+  6 files changed, 295 insertions(+), 24 deletions(-)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index 088ea70..b88940a 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -317,8 +317,9 @@ OPTIONS

+  

+  -T::

+  --targets::

+ -	Extend decoder listings with downstream port target information, and /

+ -	or port and bus listings with the downstream port information.

+ +	Extend decoder listings with downstream port target information, port

+ +	and bus listings with the downstream port information, and / or regions

+ +	with mapping information.

+  ----

+  # cxl list -BTu -b ACPI.CXL

+  {

+ @@ -335,6 +336,14 @@ OPTIONS

+  }

+  ----

+  

+ +-R::

+ +--regions::

+ +	Include region objects in the listing.

+ +

+ +-r::

+ +--region::

+ +	Specify CXL region device name(s), or device id(s), to filter the listing.

+ +

+  --debug::

+  	If the cxl tool was built with debug enabled, turn on debug

+  	messages.

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index e5fab19..38ece55 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -585,6 +585,73 @@ util_cxl_memdev_filter_by_port(struct cxl_memdev *memdev, const char *bus_ident,

+  	return NULL;

+  }

+  

+ +static struct cxl_region *

+ +util_cxl_region_filter_by_bus(struct cxl_region *region, const char *__ident)

+ +{

+ +	struct cxl_decoder *decoder = cxl_region_get_decoder(region);

+ +

+ +	if (!util_cxl_decoder_filter_by_bus(decoder, __ident))

+ +		return NULL;

+ +	return region;

+ +}

+ +

+ +static struct cxl_region *

+ +util_cxl_region_filter_by_port(struct cxl_region *region, const char *__ident)

+ +{

+ +	struct cxl_decoder *decoder = cxl_region_get_decoder(region);

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +

+ +	if (!util_cxl_port_filter(port, __ident ,CXL_PF_ANCESTRY))

+ +		return NULL;

+ +	return region;

+ +}

+ +

+ +static struct cxl_region *

+ +util_cxl_region_filter_by_decoder(struct cxl_region *region,

+ +				  const char *__ident)

+ +{

+ +	struct cxl_decoder *decoder = cxl_region_get_decoder(region);

+ +

+ +	if (!util_cxl_decoder_filter(decoder, __ident))

+ +		return NULL;

+ +	return region;

+ +}

+ +

+ +struct cxl_region *util_cxl_region_filter(struct cxl_region *region,

+ +					    const char *__ident)

+ +{

+ +	char *ident, *save;

+ +	const char *name;

+ +	int id;

+ +

+ +	if (!__ident)

+ +		return region;

+ +

+ +	ident = strdup(__ident);

+ +	if (!ident)

+ +		return NULL;

+ +

+ +	for (name = strtok_r(ident, which_sep(__ident), &save); name;

+ +	     name = strtok_r(NULL, which_sep(__ident), &save)) {

+ +		if (strcmp(name, "all") == 0)

+ +			break;

+ +

+ +		if ((sscanf(name, "%d", &id) == 1 ||

+ +		     sscanf(name, "region%d", &id) == 1) &&

+ +		    cxl_region_get_id(region) == id)

+ +			break;

+ +

+ +		if (strcmp(name, cxl_region_get_devname(region)) == 0)

+ +			break;

+ +	}

+ +

+ +	free(ident);

+ +	if (name)

+ +		return region;

+ +	return NULL;

+ +

+ +}

+ +

+  static unsigned long params_to_flags(struct cxl_filter_params *param)

+  {

+  	unsigned long flags = 0;

+ @@ -672,26 +739,57 @@ static struct json_object *pick_array(struct json_object *child,

+  	return NULL;

+  }

+  

+ +static void walk_regions(struct cxl_decoder *decoder,

+ +			 struct json_object *jregions,

+ +			 struct cxl_filter_params *p,

+ +			 unsigned long flags)

+ +{

+ +	struct json_object *jregion;

+ +	struct cxl_region *region;

+ +

+ +	cxl_region_foreach(decoder, region) {

+ +		if (!util_cxl_region_filter(region, p->region_filter))

+ +			continue;

+ +		if (!util_cxl_region_filter_by_bus(region, p->bus_filter))

+ +			continue;

+ +		if (!util_cxl_region_filter_by_port(region, p->port_filter))

+ +			continue;

+ +		if (!util_cxl_region_filter_by_decoder(region, p->decoder_filter))

+ +			continue;

+ +		if (!p->idle && !cxl_region_is_enabled(region))

+ +			continue;

+ +		jregion = util_cxl_region_to_json(region, flags);

+ +		if (!jregion)

+ +			continue;

+ +		json_object_array_add(jregions, jregion);

+ +	}

+ +

+ +	return;

+ +}

+ +

+  static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,

+ -			  struct json_object *jdecoders, unsigned long flags)

+ +			  struct json_object *jdecoders,

+ +			  struct json_object *jregions, unsigned long flags)

+  {

+  	struct cxl_decoder *decoder;

+  

+  	cxl_decoder_foreach(port, decoder) {

+ +		const char *devname = cxl_decoder_get_devname(decoder);

+ +		struct json_object *jchildregions = NULL;

+  		struct json_object *jdecoder;

+  

+  		if (!p->decoders)

+ -			continue;

+ +			goto walk_children;

+  		if (!util_cxl_decoder_filter(decoder, p->decoder_filter))

+ -			continue;

+ +			goto walk_children;

+  		if (!util_cxl_decoder_filter_by_bus(decoder, p->bus_filter))

+ -			continue;

+ +			goto walk_children;

+  		if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter,

+  						     pf_mode(p)))

+ -			continue;

+ +			goto walk_children;

+  		if (!util_cxl_decoder_filter_by_memdev(

+  			    decoder, p->memdev_filter, p->serial_filter))

+ -			continue;

+ +			goto walk_children;

+  		if (!p->idle && cxl_decoder_get_size(decoder) == 0)

+  			continue;

+  		jdecoder = util_cxl_decoder_to_json(decoder, flags);

+ @@ -702,7 +800,27 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,

+  		util_cxl_targets_append_json(jdecoder, decoder,

+  					     p->memdev_filter, p->serial_filter,

+  					     flags);

+ +

+ +		if (p->regions) {

+ +			jchildregions = json_object_new_array();

+ +			if (!jchildregions) {

+ +				err(p, "failed to allocate region object\n");

+ +				return;

+ +			}

+ +		}

+ +

+  		json_object_array_add(jdecoders, jdecoder);

+ +

+ +walk_children:

+ +		if (!p->regions)

+ +			continue;

+ +		if (!cxl_port_is_root(port))

+ +			continue;

+ +		walk_regions(decoder,

+ +			     pick_array(jchildregions, jregions),

+ +			     p, flags);

+ +		cond_add_put_array_suffix(jdecoder, "regions", devname,

+ +					  jchildregions);

+  	}

+  }

+  

+ @@ -782,7 +900,7 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,

+  		if (!p->decoders)

+  			continue;

+  		walk_decoders(cxl_endpoint_get_port(endpoint), p,

+ -			      pick_array(jchilddecoders, jdecoders), flags);

+ +			      pick_array(jchilddecoders, jdecoders), NULL, flags);

+  		cond_add_put_array_suffix(jendpoint, "decoders", devname,

+  					  jchilddecoders);

+  	}

+ @@ -869,7 +987,8 @@ walk_children:

+  				       flags);

+  

+  		walk_decoders(port, p,

+ -			      pick_array(jchilddecoders, jportdecoders), flags);

+ +			      pick_array(jchilddecoders, jportdecoders), NULL,

+ +			      flags);

+  		walk_child_ports(port, p, pick_array(jchildports, jports),

+  				 pick_array(jchilddecoders, jportdecoders),

+  				 pick_array(jchildeps, jeps),

+ @@ -894,6 +1013,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	struct json_object *jbusdecoders = NULL;

+  	struct json_object *jepdecoders = NULL;

+  	struct json_object *janondevs = NULL;

+ +	struct json_object *jregions = NULL;

+  	struct json_object *jeps = NULL;

+  	struct cxl_memdev *memdev;

+  	int top_level_objs = 0;

+ @@ -936,6 +1056,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  	if (!jepdecoders)

+  		goto err;

+  

+ +	jregions = json_object_new_array();

+ +	if (!jregions)

+ +		goto err;

+ +

+  	dbg(p, "walk memdevs\n");

+  	cxl_memdev_foreach(ctx, memdev) {

+  		struct json_object *janondev;

+ @@ -964,6 +1088,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  		struct json_object *jchildports = NULL;

+  		struct json_object *jchilddevs = NULL;

+  		struct json_object *jchildeps = NULL;

+ +		struct json_object *jchildregions = NULL;

+  		struct cxl_port *port = cxl_bus_get_port(bus);

+  		const char *devname = cxl_bus_get_devname(bus);

+  

+ @@ -1021,11 +1146,20 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)

+  					continue;

+  				}

+  			}

+ +			if (p->regions && !p->decoders) {

+ +				jchildregions = json_object_new_array();

+ +				if (!jchildregions) {

+ +					err(p,

+ +					    "%s: failed to enumerate child regions\n",

+ +					    devname);

+ +					continue;

+ +				}

+ +			}

+  		}

+  walk_children:

+  		dbg(p, "walk decoders\n");

+  		walk_decoders(port, p, pick_array(jchilddecoders, jbusdecoders),

+ -			      flags);

+ +			      pick_array(jchildregions, jregions), flags);

+  

+  		dbg(p, "walk ports\n");

+  		walk_child_ports(port, p, pick_array(jchildports, jports),

+ @@ -1038,6 +1172,8 @@ walk_children:

+  					  jchildeps);

+  		cond_add_put_array_suffix(jbus, "decoders", devname,

+  					  jchilddecoders);

+ +		cond_add_put_array_suffix(jbus, "regions", devname,

+ +					  jchildregions);

+  		cond_add_put_array_suffix(jbus, "memdevs", devname, jchilddevs);

+  	}

+  

+ @@ -1057,6 +1193,8 @@ walk_children:

+  		top_level_objs++;

+  	if (json_object_array_length(jepdecoders))

+  		top_level_objs++;

+ +	if (json_object_array_length(jregions))

+ +		top_level_objs++;

+  

+  	splice_array(p, janondevs, jplatform, "anon memdevs", top_level_objs > 1);

+  	splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);

+ @@ -1069,6 +1207,7 @@ walk_children:

+  		     top_level_objs > 1);

+  	splice_array(p, jepdecoders, jplatform, "endpoint decoders",

+  		     top_level_objs > 1);

+ +	splice_array(p, jregions, jplatform, "regions", top_level_objs > 1);

+  

+  	util_display_json_array(stdout, jplatform, flags);

+  

+ @@ -1082,6 +1221,7 @@ err:

+  	json_object_put(jbusdecoders);

+  	json_object_put(jportdecoders);

+  	json_object_put(jepdecoders);

+ +	json_object_put(jregions);

+  	json_object_put(jplatform);

+  	return -ENOMEM;

+  }

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index c913daf..609433c 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -13,9 +13,11 @@ struct cxl_filter_params {

+  	const char *port_filter;

+  	const char *endpoint_filter;

+  	const char *decoder_filter;

+ +	const char *region_filter;

+  	bool single;

+  	bool endpoints;

+  	bool decoders;

+ +	bool regions;

+  	bool targets;

+  	bool memdevs;

+  	bool ports;

+ @@ -33,6 +35,8 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,

+  						const char *ident,

+  						const char *serial);

+ +struct cxl_region *util_cxl_region_filter(struct cxl_region *region,

+ +					    const char *__ident);

+  

+  enum cxl_port_filter_mode {

+  	CXL_PF_SINGLE,

+ diff --git a/cxl/json.c b/cxl/json.c

+ index ae9c812..70cf286 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -524,6 +524,120 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	return jdecoder;

+  }

+  

+ +void util_cxl_mappings_append_json(struct json_object *jregion,

+ +				  struct cxl_region *region,

+ +				  unsigned long flags)

+ +{

+ +	struct json_object *jobj, *jmappings;

+ +	struct cxl_memdev_mapping *mapping;

+ +	unsigned int val, nr_mappings;

+ +	const char *devname;

+ +

+ +	nr_mappings = cxl_region_get_interleave_ways(region);

+ +	if (!nr_mappings || (nr_mappings == UINT_MAX))

+ +		return;

+ +

+ +	if (!(flags & UTIL_JSON_TARGETS))

+ +		return;

+ +

+ +	jmappings = json_object_new_array();

+ +	if (!jmappings)

+ +		return;

+ +

+ +	cxl_mapping_foreach(region, mapping) {

+ +		struct json_object *jmapping;

+ +		struct cxl_decoder *decoder;

+ +

+ +		jmapping = json_object_new_object();

+ +		if (!jmapping)

+ +			continue;

+ +

+ +		val = cxl_mapping_get_position(mapping);

+ +		if (val < UINT_MAX) {

+ +			jobj = json_object_new_int(val);

+ +			if (jobj)

+ +				json_object_object_add(jmapping, "position",

+ +						       jobj);

+ +		}

+ +

+ +		decoder = cxl_mapping_get_decoder(mapping);

+ +		if (!decoder)

+ +			continue;

+ +

+ +		devname = cxl_decoder_get_devname(decoder);

+ +		jobj = json_object_new_string(devname);

+ +		if (jobj)

+ +			json_object_object_add(jmapping, "decoder", jobj);

+ +

+ +		json_object_array_add(jmappings, jmapping);

+ +	}

+ +

+ +	json_object_object_add(jregion, "mappings", jmappings);

+ +}

+ +

+ +struct json_object *util_cxl_region_to_json(struct cxl_region *region,

+ +					     unsigned long flags)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct json_object *jregion, *jobj;

+ +	u64 val;

+ +

+ +	jregion = json_object_new_object();

+ +	if (!jregion)

+ +		return NULL;

+ +

+ +	jobj = json_object_new_string(devname);

+ +	if (jobj)

+ +		json_object_object_add(jregion, "region", jobj);

+ +

+ +	val = cxl_region_get_resource(region);

+ +	if (val < ULLONG_MAX) {

+ +		jobj = util_json_object_hex(val, flags);

+ +		if (jobj)

+ +			json_object_object_add(jregion, "resource", jobj);

+ +	}

+ +

+ +	val = cxl_region_get_size(region);

+ +	if (val < ULLONG_MAX) {

+ +		jobj = util_json_object_size(val, flags);

+ +		if (jobj)

+ +			json_object_object_add(jregion, "size", jobj);

+ +	}

+ +

+ +	val = cxl_region_get_interleave_ways(region);

+ +	if (val < INT_MAX) {

+ +		jobj = json_object_new_int(val);

+ +		if (jobj)

+ +			json_object_object_add(jregion,

+ +					       "interleave_ways", jobj);

+ +	}

+ +

+ +	val = cxl_region_get_interleave_granularity(region);

+ +	if (val < INT_MAX) {

+ +		jobj = json_object_new_int(val);

+ +		if (jobj)

+ +			json_object_object_add(jregion,

+ +					       "interleave_granularity", jobj);

+ +	}

+ +

+ +	if (cxl_region_decode_is_committed(region))

+ +		jobj = json_object_new_string("commit");

+ +	else

+ +		jobj = json_object_new_string("reset");

+ +	if (jobj)

+ +		json_object_object_add(jregion, "decode_state", jobj);

+ +

+ +	if (!cxl_region_is_enabled(region)) {

+ +		jobj = json_object_new_string("disabled");

+ +		if (jobj)

+ +			json_object_object_add(jregion, "state", jobj);

+ +	}

+ +

+ +	util_cxl_mappings_append_json(jregion, region, flags);

+ +

+ +	return jregion;

+ +}

+ +

+  void util_cxl_targets_append_json(struct json_object *jdecoder,

+  				  struct cxl_decoder *decoder,

+  				  const char *ident, const char *serial,

+ diff --git a/cxl/json.h b/cxl/json.h

+ index 9a5a845..eb7572b 100644

+ --- a/cxl/json.h

+ +++ b/cxl/json.h

+ @@ -15,6 +15,11 @@ struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint,

+  					      unsigned long flags);

+  struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  					     unsigned long flags);

+ +struct json_object *util_cxl_region_to_json(struct cxl_region *region,

+ +					     unsigned long flags);

+ +void util_cxl_mappings_append_json(struct json_object *jregion,

+ +				  struct cxl_region *region,

+ +				  unsigned long flags);

+  void util_cxl_targets_append_json(struct json_object *jdecoder,

+  				  struct cxl_decoder *decoder,

+  				  const char *ident, const char *serial,

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 1b5f583..88ca9d9 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -41,7 +41,10 @@ static const struct option options[] = {

+  	OPT_BOOLEAN('D', "decoders", &param.decoders,

+  		    "include CXL decoder info"),

+  	OPT_BOOLEAN('T', "targets", &param.targets,

+ -		    "include CXL target data with decoders or ports"),

+ +		    "include CXL target data with decoders, ports, or regions"),

+ +	OPT_STRING('r', "region", &param.region_filter, "region name",

+ +		   "filter by CXL region name(s)"),

+ +	OPT_BOOLEAN('R', "regions", &param.regions, "include CXL regions"),

+  	OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),

+  	OPT_BOOLEAN('u', "human", &param.human,

+  		    "use human friendly number formats"),

+ @@ -58,7 +61,7 @@ static const struct option options[] = {

+  static int num_list_flags(void)

+  {

+  	return !!param.memdevs + !!param.buses + !!param.ports +

+ -	       !!param.endpoints + !!param.decoders;

+ +	       !!param.endpoints + !!param.decoders + !!param.regions;

+  }

+  

+  int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+ @@ -92,18 +95,14 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  			param.endpoints = true;

+  		if (param.decoder_filter)

+  			param.decoders = true;

+ -		if (num_list_flags() == 0) {

+ -			/*

+ -			 * TODO: We likely want to list regions by default if

+ -			 * nothing was explicitly asked for. But until we have

+ -			 * region support, print this error asking for devices

+ -			 * explicitly.  Once region support is added, this TODO

+ -			 * can be removed.

+ -			 */

+ -			error("please specify entities to list, e.g. using -m/-M\n");

+ -			usage_with_options(u, options);

+ -		}

+  		param.single = true;

+ +		if (param.region_filter)

+ +			param.regions = true;

+ +	}

+ +

+ +	/* List regions by default */

+ +	if (num_list_flags() == 0) {

+ +		param.regions = true;

+  	}

+  

+  	log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,644 @@ 

+ From cafe4b2d4970b0d7f2193abb9cb32f58c03cbe3b Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:09 -0600

+ Subject: [PATCH 194/217] libcxl: add low level APIs for region creation

+ 

+ Add libcxl APIs to create a region under a given root decoder, and to

+ set different attributes for the new region. These allow setting the

+ size, interleave_ways, interleave_granularity, uuid, and the target

+ devices for the newly minted cxl_region object.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-7-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  69 ++++++

+  cxl/lib/libcxl.c                 | 381 ++++++++++++++++++++++++++++++-

+  cxl/lib/libcxl.sym               |  16 ++

+  cxl/lib/private.h                |   2 +

+  cxl/libcxl.h                     |  23 +-

+  5 files changed, 488 insertions(+), 3 deletions(-)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 7a38ce4..50b0c9c 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -508,6 +508,75 @@ device to represent the root of a PCI device hierarchy. The

+  cxl_target_get_physical_node() helper returns the device name of that

+  companion object in the PCI hierarchy.

+  

+ +==== REGIONS

+ +A CXL region is composed of one or more slices of CXL memdevs, with configurable

+ +interleave settings - both the number of interleave ways, and the interleave

+ +granularity. In terms of hierarchy, it is the child of a CXL root decoder. A root

+ +decoder (recall that this corresponds to an ACPI CEDT.CFMWS 'window'), may have

+ +multiple child regions, but a region is strictly tied to one root decoder.

+ +

+ +The slices that compose a region are called mappings. A mapping is a

+ +tuple of 'memdev', 'endpoint decoder', and the 'position'.

+ +

+ +===== REGION: Enumeration

+ +----

+ +struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder);

+ +struct cxl_region *cxl_region_get_next(struct cxl_region *region);

+ +

+ +#define cxl_region_foreach(decoder, region)                                    \

+ +	for (region = cxl_region_get_first(decoder); region != NULL;           \

+ +	     region = cxl_region_get_next(region))

+ +

+ +#define cxl_region_foreach_safe(decoder, region, _region)                      \

+ +	for (region = cxl_region_get_first(decoder),                           \

+ +	     _region = region ? cxl_region_get_next(region) : NULL;            \

+ +	     region != NULL;                                                   \

+ +	     region = _region,                                                 \

+ +	     _region = _region ? cxl_region_get_next(_region) : NULL)

+ +----

+ +

+ +===== REGION: Attributes

+ +----

+ +int cxl_region_get_id(struct cxl_region *region);

+ +const char *cxl_region_get_devname(struct cxl_region *region);

+ +void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu);

+ +unsigned long long cxl_region_get_size(struct cxl_region *region);

+ +unsigned long long cxl_region_get_resource(struct cxl_region *region);

+ +unsigned int cxl_region_get_interleave_ways(struct cxl_region *region);

+ +unsigned int cxl_region_get_interleave_granularity(struct cxl_region *region);

+ +struct cxl_decoder *cxl_region_get_target_decoder(struct cxl_region *region,

+ +						  int position);

+ +int cxl_region_set_size(struct cxl_region *region, unsigned long long size);

+ +int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu);

+ +int cxl_region_set_interleave_ways(struct cxl_region *region,

+ +				   unsigned int ways);

+ +int cxl_region_set_interleave_granularity(struct cxl_region *region,

+ +					  unsigned int granularity);

+ +int cxl_region_set_target(struct cxl_region *region, int position,

+ +			  struct cxl_decoder *decoder);

+ +int cxl_region_clear_target(struct cxl_region *region, int position);

+ +int cxl_region_clear_all_targets(struct cxl_region *region);

+ +int cxl_region_decode_commit(struct cxl_region *region);

+ +int cxl_region_decode_reset(struct cxl_region *region);

+ +----

+ +

+ +A region's resource attribute is the Host Physical Address at which the region's

+ +address space starts. The region's address space is a subset of the parent root

+ +decoder's address space.

+ +

+ +The interleave ways is the number of component memdevs participating in the

+ +region.

+ +

+ +The interleave granularity depends on the root decoder's granularity, and must

+ +follow the interleave math rules defined in the CXL spec.

+ +

+ +Regions have a list of targets 0..N, which are programmed with the name of an

+ +endpoint decoder under each participating memdev.

+ +

+ +The 'decode_commit' and 'decode_reset' attributes reserve and free DPA space

+ +on a given memdev by allocating an endpoint decoder, and programming it based

+ +on the region's interleave geometry.

+ +

+  include::../../copyright.txt[]

+  

+  SEE ALSO

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index ad98188..fd2ea4f 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -17,6 +17,7 @@

+  #include <ccan/minmax/minmax.h>

+  #include <ccan/array_size/array_size.h>

+  #include <ccan/short_types/short_types.h>

+ +#include <ccan/container_of/container_of.h>

+  

+  #include <util/log.h>

+  #include <util/list.h>

+ @@ -420,6 +421,40 @@ CXL_EXPORT int cxl_region_enable(struct cxl_region *region)

+  	return 0;

+  }

+  

+ +static int cxl_region_delete_name(struct cxl_decoder *decoder,

+ +				  const char *devname)

+ +{

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	char *path = decoder->dev_buf;

+ +	int rc;

+ +

+ +	sprintf(path, "%s/delete_region", decoder->dev_path);

+ +	rc = sysfs_write_attr(ctx, path, devname);

+ +	if (rc != 0) {

+ +		err(ctx, "error deleting region: %s\n", strerror(-rc));

+ +		return rc;

+ +	}

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_delete(struct cxl_region *region)

+ +{

+ +	struct cxl_decoder *decoder = cxl_region_get_decoder(region);

+ +	const char *devname = cxl_region_get_devname(region);

+ +	int rc;

+ +

+ +	if (cxl_region_is_enabled(region))

+ +		return -EBUSY;

+ +

+ +	rc = cxl_region_delete_name(decoder, devname);

+ +	if (rc != 0)

+ +		return rc;

+ +

+ +	decoder->regions_init = 0;

+ +	free_region(region, &decoder->regions);

+ +	return 0;

+ +}

+ +

+  static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)

+  {

+  	const char *devname = devpath_to_devname(cxlregion_base);

+ @@ -599,6 +634,258 @@ cxl_region_get_interleave_granularity(struct cxl_region *region)

+  	return region->interleave_granularity;

+  }

+  

+ +CXL_EXPORT struct cxl_decoder *

+ +cxl_region_get_target_decoder(struct cxl_region *region, int position)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int len = region->buf_len, rc;

+ +	char *path = region->dev_buf;

+ +	struct cxl_decoder *decoder;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	if (snprintf(path, len, "%s/target%d", region->dev_path, position) >=

+ +	    len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return NULL;

+ +	}

+ +

+ +	rc = sysfs_read_attr(ctx, path, buf);

+ +	if (rc < 0) {

+ +		err(ctx, "%s: error reading target%d: %s\n", devname,

+ +		    position, strerror(-rc));

+ +		return NULL;

+ +	}

+ +

+ +	decoder = cxl_decoder_get_by_name(ctx, buf);

+ +	if (!decoder) {

+ +		err(ctx, "%s: error locating decoder for target%d\n", devname,

+ +		    position);

+ +		return NULL;

+ +	}

+ +	return decoder;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_set_size(struct cxl_region *region,

+ +				   unsigned long long size)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int len = region->buf_len, rc;

+ +	char *path = region->dev_buf;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	if (size == 0) {

+ +		dbg(ctx, "%s: cannot use %s to delete a region\n", __func__,

+ +		    devname);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (snprintf(path, len, "%s/size", region->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	sprintf(buf, "%#llx\n", size);

+ +	rc = sysfs_write_attr(ctx, path, buf);

+ +	if (rc < 0)

+ +		return rc;

+ +

+ +	region->size = size;

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int len = region->buf_len, rc;

+ +	char *path = region->dev_buf;

+ +	char uuid[SYSFS_ATTR_SIZE];

+ +

+ +	if (snprintf(path, len, "%s/uuid", region->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	uuid_unparse(uu, uuid);

+ +	rc = sysfs_write_attr(ctx, path, uuid);

+ +	if (rc != 0)

+ +		return rc;

+ +	memcpy(region->uuid, uu, sizeof(uuid_t));

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_set_interleave_ways(struct cxl_region *region,

+ +					      unsigned int ways)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int len = region->buf_len, rc;

+ +	char *path = region->dev_buf;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	if (snprintf(path, len, "%s/interleave_ways",

+ +		     region->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	sprintf(buf, "%u\n", ways);

+ +	rc = sysfs_write_attr(ctx, path, buf);

+ +	if (rc < 0)

+ +		return rc;

+ +

+ +	region->interleave_ways = ways;

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_set_interleave_granularity(struct cxl_region *region,

+ +						     unsigned int granularity)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int len = region->buf_len, rc;

+ +	char *path = region->dev_buf;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	if (snprintf(path, len, "%s/interleave_granularity",

+ +		     region->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	sprintf(buf, "%u\n", granularity);

+ +	rc = sysfs_write_attr(ctx, path, buf);

+ +	if (rc < 0)

+ +		return rc;

+ +

+ +	region->interleave_granularity = granularity;

+ +

+ +	return 0;

+ +}

+ +

+ +static int region_write_target(struct cxl_region *region, int position,

+ +			       struct cxl_decoder *decoder)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int len = region->buf_len, rc;

+ +	char *path = region->dev_buf;

+ +	const char *dec_name = "";

+ +

+ +	if (decoder)

+ +		dec_name = cxl_decoder_get_devname(decoder);

+ +

+ +	if (snprintf(path, len, "%s/target%d", region->dev_path, position) >=

+ +	    len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	rc = sysfs_write_attr(ctx, path, dec_name);

+ +	if (rc < 0)

+ +		return rc;

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_set_target(struct cxl_region *region, int position,

+ +				     struct cxl_decoder *decoder)

+ +{

+ +	if (!decoder)

+ +		return -ENXIO;

+ +

+ +	return region_write_target(region, position, decoder);

+ +}

+ +

+ +CXL_EXPORT int cxl_region_clear_target(struct cxl_region *region, int position)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int rc;

+ +

+ +	if (cxl_region_is_enabled(region)) {

+ +		err(ctx, "%s: can't clear targets on an active region\n",

+ +		    devname);

+ +		return -EBUSY;

+ +	}

+ +

+ +	rc = region_write_target(region, position, NULL);

+ +	if (rc) {

+ +		err(ctx, "%s: error clearing target%d: %s\n",

+ +		    devname, position, strerror(-rc));

+ +		return rc;

+ +	}

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_clear_all_targets(struct cxl_region *region)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	unsigned int ways, i;

+ +	int rc;

+ +

+ +	if (cxl_region_is_enabled(region)) {

+ +		err(ctx, "%s: can't clear targets on an active region\n",

+ +		    devname);

+ +		return -EBUSY;

+ +	}

+ +

+ +	ways = cxl_region_get_interleave_ways(region);

+ +	if (ways == 0 || ways == UINT_MAX)

+ +		return -ENXIO;

+ +

+ +	for (i = 0; i < ways; i++) {

+ +		rc = region_write_target(region, i, NULL);

+ +		if (rc) {

+ +			err(ctx, "%s: error clearing target%d: %s\n",

+ +			    devname, i, strerror(-rc));

+ +			return rc;

+ +		}

+ +	}

+ +

+ +	return 0;

+ +}

+ +

+ +static int set_region_decode(struct cxl_region *region,

+ +			     enum cxl_decode_state decode_state)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	struct cxl_ctx *ctx = cxl_region_get_ctx(region);

+ +	int len = region->buf_len, rc;

+ +	char *path = region->dev_buf;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +

+ +	if (snprintf(path, len, "%s/commit", region->dev_path) >= len) {

+ +		err(ctx, "%s: buffer too small!\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	sprintf(buf, "%d\n", decode_state);

+ +	rc = sysfs_write_attr(ctx, path, buf);

+ +	if (rc < 0)

+ +		return rc;

+ +

+ +	region->decode_state = decode_state;

+ +

+ +	return 0;

+ +}

+ +

+ +CXL_EXPORT int cxl_region_decode_commit(struct cxl_region *region)

+ +{

+ +	return set_region_decode(region, CXL_DECODE_COMMIT);

+ +}

+ +

+ +CXL_EXPORT int cxl_region_decode_reset(struct cxl_region *region)

+ +{

+ +	return set_region_decode(region, CXL_DECODE_RESET);

+ +}

+ +

+  static struct cxl_decoder *__cxl_port_match_decoder(struct cxl_port *port,

+  						    const char *ident)

+  {

+ @@ -633,8 +920,8 @@ static struct cxl_decoder *cxl_port_find_decoder(struct cxl_port *port,

+  	return NULL;

+  }

+  

+ -static struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,

+ -						   const char *ident)

+ +CXL_EXPORT struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,

+ +						       const char *ident)

+  {

+  	struct cxl_bus *bus;

+  

+ @@ -1399,6 +1686,18 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  	} else

+  		decoder->mode = CXL_DECODER_MODE_NONE;

+  

+ +	sprintf(path, "%s/interleave_granularity", cxldecoder_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		decoder->interleave_granularity = UINT_MAX;

+ +	else

+ +		decoder->interleave_granularity = strtoul(buf, NULL, 0);

+ +

+ +	sprintf(path, "%s/interleave_ways", cxldecoder_base);

+ +	if (sysfs_read_attr(ctx, path, buf) < 0)

+ +		decoder->interleave_ways = UINT_MAX;

+ +	else

+ +		decoder->interleave_ways = strtoul(buf, NULL, 0);

+ +

+  	switch (port->type) {

+  	case CXL_PORT_ENDPOINT:

+  		sprintf(path, "%s/dpa_resource", cxldecoder_base);

+ @@ -1731,6 +2030,66 @@ CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder)

+  	return decoder->locked;

+  }

+  

+ +CXL_EXPORT unsigned int

+ +cxl_decoder_get_interleave_granularity(struct cxl_decoder *decoder)

+ +{

+ +	return decoder->interleave_granularity;

+ +}

+ +

+ +CXL_EXPORT unsigned int

+ +cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder)

+ +{

+ +	return decoder->interleave_ways;

+ +}

+ +

+ +CXL_EXPORT struct cxl_region *

+ +cxl_decoder_create_pmem_region(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	char *path = decoder->dev_buf;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +	struct cxl_region *region;

+ +	int rc;

+ +

+ +	sprintf(path, "%s/create_pmem_region", decoder->dev_path);

+ +	rc = sysfs_read_attr(ctx, path, buf);

+ +	if (rc < 0) {

+ +		err(ctx, "failed to read new region name: %s\n",

+ +		    strerror(-rc));

+ +		return NULL;

+ +	}

+ +

+ +	rc = sysfs_write_attr(ctx, path, buf);

+ +	if (rc < 0) {

+ +		err(ctx, "failed to write new region name: %s\n",

+ +		    strerror(-rc));

+ +		return NULL;

+ +	}

+ +

+ +	/* Force a re-init of regions so that the new one can be discovered */

+ +	decoder->regions_init = 0;

+ +

+ +	/* create_region was successful, walk to the new region */

+ +	cxl_region_foreach(decoder, region) {

+ +		const char *devname = cxl_region_get_devname(region);

+ +

+ +		if (strcmp(devname, buf) == 0)

+ +			goto found;

+ +	}

+ +

+ +	/*

+ +	 * If walking to the region we just created failed, something has gone

+ +	 * very wrong. Attempt to delete it to avoid leaving a dangling region

+ +	 * id behind.

+ +	 */

+ +	err(ctx, "failed to add new region to libcxl\n");

+ +	cxl_region_delete_name(decoder, buf);

+ +	return NULL;

+ +

+ + found:

+ +	return region;

+ +}

+ +

+  CXL_EXPORT int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder)

+  {

+  	return decoder->nr_targets;

+ @@ -1741,6 +2100,24 @@ CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder)

+  	return devpath_to_devname(decoder->dev_path);

+  }

+  

+ +CXL_EXPORT struct cxl_memdev *

+ +cxl_decoder_get_memdev(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_endpoint *ep;

+ +

+ +	if (!port)

+ +		return NULL;

+ +	if (!cxl_port_is_endpoint(port))

+ +		return NULL;

+ +

+ +	ep = container_of(port, struct cxl_endpoint, port);

+ +	if (!ep)

+ +		return NULL;

+ +

+ +	return cxl_endpoint_get_memdev(ep);

+ +}

+ +

+  CXL_EXPORT struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder)

+  {

+  	return list_top(&decoder->targets, struct cxl_target, list);

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index e410298..cb23a0b 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -140,6 +140,7 @@ global:

+  	cxl_decoder_is_mem_capable;

+  	cxl_decoder_is_accelmem_capable;

+  	cxl_decoder_is_locked;

+ +	cxl_decoder_create_pmem_region;

+  	cxl_target_get_first;

+  	cxl_target_get_next;

+  	cxl_target_get_decoder;

+ @@ -183,6 +184,7 @@ global:

+  	cxl_region_is_enabled;

+  	cxl_region_disable;

+  	cxl_region_enable;

+ +	cxl_region_delete;

+  	cxl_region_get_ctx;

+  	cxl_region_get_decoder;

+  	cxl_region_get_id;

+ @@ -192,9 +194,23 @@ global:

+  	cxl_region_get_resource;

+  	cxl_region_get_interleave_ways;

+  	cxl_region_get_interleave_granularity;

+ +	cxl_region_get_target_decoder;

+ +	cxl_region_set_size;

+ +	cxl_region_set_uuid;

+ +	cxl_region_set_interleave_ways;

+ +	cxl_region_set_interleave_granularity;

+ +	cxl_region_set_target;

+ +	cxl_region_clear_target;

+ +	cxl_region_clear_all_targets;

+ +	cxl_region_decode_commit;

+ +	cxl_region_decode_reset;

+  	cxl_mapping_get_first;

+  	cxl_mapping_get_next;

+  	cxl_mapping_get_decoder;

+  	cxl_mapping_get_region;

+  	cxl_mapping_get_position;

+ +	cxl_decoder_get_by_name;

+ +	cxl_decoder_get_memdev;

+ +	cxl_decoder_get_interleave_granularity;

+ +	cxl_decoder_get_interleave_ways;

+  } LIBCXL_2;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 5e2fdd5..8bc9620 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -110,6 +110,8 @@ struct cxl_decoder {

+  	int nr_targets;

+  	int id;

+  	enum cxl_decoder_mode mode;

+ +	unsigned int interleave_ways;

+ +	unsigned int interleave_granularity;

+  	bool pmem_capable;

+  	bool volatile_capable;

+  	bool mem_capable;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 19d94e4..69d9c09 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -195,7 +195,13 @@ bool cxl_decoder_is_volatile_capable(struct cxl_decoder *decoder);

+  bool cxl_decoder_is_mem_capable(struct cxl_decoder *decoder);

+  bool cxl_decoder_is_accelmem_capable(struct cxl_decoder *decoder);

+  bool cxl_decoder_is_locked(struct cxl_decoder *decoder);

+ -

+ +unsigned int

+ +cxl_decoder_get_interleave_granularity(struct cxl_decoder *decoder);

+ +unsigned int cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder);

+ +struct cxl_region *cxl_decoder_create_pmem_region(struct cxl_decoder *decoder);

+ +struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,

+ +					    const char *ident);

+ +struct cxl_memdev *cxl_decoder_get_memdev(struct cxl_decoder *decoder);

+  #define cxl_decoder_foreach(port, decoder)                                     \

+  	for (decoder = cxl_decoder_get_first(port); decoder != NULL;           \

+  	     decoder = cxl_decoder_get_next(decoder))

+ @@ -244,6 +250,7 @@ int cxl_region_decode_is_committed(struct cxl_region *region);

+  int cxl_region_is_enabled(struct cxl_region *region);

+  int cxl_region_disable(struct cxl_region *region);

+  int cxl_region_enable(struct cxl_region *region);

+ +int cxl_region_delete(struct cxl_region *region);

+  struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region);

+  struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region);

+  int cxl_region_get_id(struct cxl_region *region);

+ @@ -253,6 +260,20 @@ unsigned long long cxl_region_get_size(struct cxl_region *region);

+  unsigned long long cxl_region_get_resource(struct cxl_region *region);

+  unsigned int cxl_region_get_interleave_ways(struct cxl_region *region);

+  unsigned int cxl_region_get_interleave_granularity(struct cxl_region *region);

+ +struct cxl_decoder *cxl_region_get_target_decoder(struct cxl_region *region,

+ +						  int position);

+ +int cxl_region_set_size(struct cxl_region *region, unsigned long long size);

+ +int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu);

+ +int cxl_region_set_interleave_ways(struct cxl_region *region,

+ +				   unsigned int ways);

+ +int cxl_region_set_interleave_granularity(struct cxl_region *region,

+ +					  unsigned int granularity);

+ +int cxl_region_set_target(struct cxl_region *region, int position,

+ +			  struct cxl_decoder *decoder);

+ +int cxl_region_clear_target(struct cxl_region *region, int position);

+ +int cxl_region_clear_all_targets(struct cxl_region *region);

+ +int cxl_region_decode_commit(struct cxl_region *region);

+ +int cxl_region_decode_reset(struct cxl_region *region);

+  

+  #define cxl_region_foreach(decoder, region)                                    \

+  	for (region = cxl_region_get_first(decoder); region != NULL;           \

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,829 @@ 

+ From 21b089025178442baa7b59823a7fd264b4c075a8 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:10 -0600

+ Subject: [PATCH 195/217] cxl: add a 'create-region' command

+ 

+ Add a 'create-region' command to cxl-cli that walks the platform's CXL

+ hierarchy to find an appropriate root decoder based on any options

+ provided, and uses libcxl APIs to create a 'region' that is comprehended

+ by libnvdimm and ndctl.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-8-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/bus-option.txt         |   5 +

+  Documentation/cxl/cxl-create-region.txt  | 112 +++++

+  Documentation/cxl/meson.build            |   2 +

+  Documentation/cxl/region-description.txt |   7 +

+  cxl/builtin.h                            |   1 +

+  cxl/cxl.c                                |   1 +

+  cxl/filter.h                             |   4 +-

+  cxl/json.c                               |   9 +

+  cxl/meson.build                          |   1 +

+  cxl/region.c                             | 550 +++++++++++++++++++++++

+  10 files changed, 691 insertions(+), 1 deletion(-)

+  create mode 100644 Documentation/cxl/bus-option.txt

+  create mode 100644 Documentation/cxl/cxl-create-region.txt

+  create mode 100644 Documentation/cxl/region-description.txt

+  create mode 100644 cxl/region.c

+ 

+ diff --git a/Documentation/cxl/bus-option.txt b/Documentation/cxl/bus-option.txt

+ new file mode 100644

+ index 0000000..02e2f08

+ --- /dev/null

+ +++ b/Documentation/cxl/bus-option.txt

+ @@ -0,0 +1,5 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +-b::

+ +--bus=::

+ +	Restrict the operation to the specified bus.

+ diff --git a/Documentation/cxl/cxl-create-region.txt b/Documentation/cxl/cxl-create-region.txt

+ new file mode 100644

+ index 0000000..6b740d5

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-create-region.txt

+ @@ -0,0 +1,112 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-create-region(1)

+ +====================

+ +

+ +NAME

+ +----

+ +cxl-create-region - Assemble a CXL region by setting up attributes of its

+ +constituent CXL memdevs.

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl create-region [<options>]'

+ +

+ +include::region-description.txt[]

+ +

+ +For create-region, a size can optionally be specified, but if not, the maximum

+ +possible size for each memdev will be used up to the available decode capacity

+ +in the system for the given memory type. For persistent regions a UUID can

+ +optionally be specified, but if not, one will be generated.

+ +

+ +If the region-creation operation is successful, a region object will be

+ +emitted on stdout in JSON format (see examples). If the specified arguments

+ +cannot be satisfied with a legal configuration, then an appropriate error will

+ +be emitted on stderr.

+ +

+ +EXAMPLE

+ +-------

+ +----

+ +#cxl create - region - m - d decoder0 .1 - w 2 - g 1024 mem0 mem1

+ +{

+ +  "region":"region0",

+ +  "resource":"0xc90000000",

+ +  "size":"512.00 MiB (536.87 MB)",

+ +  "interleave_ways":2,

+ +  "interleave_granularity":1024,

+ +  "mappings":[

+ +    {

+ +      "position":1,

+ +      "decoder":"decoder4.0"

+ +    },

+ +    {

+ +      "position":0,

+ +      "decoder":"decoder3.0"

+ +    }

+ +  ]

+ +}

+ +created 1 region

+ +----

+ +

+ +OPTIONS

+ +-------

+ +<target(s)>::

+ +The CXL targets that should be used to form the region. The number of

+ +'target' arguments must match the '--ways' option (if provided). The

+ +targets are memdev names such as 'mem0', 'mem1' etc.

+ +

+ +include::bus-option.txt[]

+ +

+ +-m::

+ +--memdevs::

+ +	Indicate that the non-option arguments for 'target(s)' refer to memdev

+ +	names. Currently this is the only option supported, and must be

+ +	specified.

+ +

+ +-s::

+ +--size=::

+ +	Specify the total size for the new region. This is optional, and by

+ +	default, the maximum possible size will be used. The maximum possible

+ +	size is gated by both the contiguous free HPA space remaining in the

+ +	root decoder, and the available DPA space in the component memdevs.

+ +

+ +-t::

+ +--type=::

+ +	Specify the region type - 'pmem' or 'ram'. Defaults to 'pmem'.

+ +

+ +-U::

+ +--uuid=::

+ +	Specify a UUID for the new region. This shouldn't usually need to be

+ +	specified, as one will be generated by default.

+ +

+ +-w::

+ +--ways=::

+ +	The number of interleave ways for the new region's interleave. This

+ +	should be equal to the number of memdevs specified in --memdevs, if

+ +	--memdevs is being supplied. If --ways is not specified, it will be

+ +	determined based on the number of memdev targets provided.

+ +

+ +-g::

+ +--granularity=::

+ +	The interleave granularity for the new region. Must match the selected

+ +	root decoder's (if provided) granularity. If the root decoder is

+ +	interleaved across more than one host-bridge then this value must match

+ +	that granularity. Otherwise, for non-interleaved decode windows, any

+ +	granularity can be specified as long as all devices support that setting.

+ +

+ +-d::

+ +--decoder=::

+ +	The root decoder that the region should be created under. If not

+ +	supplied, the first cross-host bridge (if available), decoder that

+ +	supports the largest interleave will be chosen.

+ +

+ +include::human-option.txt[]

+ +

+ +include::debug-option.txt[]

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-list[1],

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index 423be90..340cdee 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -23,6 +23,7 @@ filedeps = [

+    'memdev-option.txt',

+    'labels-options.txt',

+    'debug-option.txt',

+ +  'region-description.txt',

+  ]

+  

+  cxl_manpages = [

+ @@ -39,6 +40,7 @@ cxl_manpages = [

+    'cxl-set-partition.txt',

+    'cxl-reserve-dpa.txt',

+    'cxl-free-dpa.txt',

+ +  'cxl-create-region.txt',

+  ]

+  

+  foreach man : cxl_manpages

+ diff --git a/Documentation/cxl/region-description.txt b/Documentation/cxl/region-description.txt

+ new file mode 100644

+ index 0000000..d7e3077

+ --- /dev/null

+ +++ b/Documentation/cxl/region-description.txt

+ @@ -0,0 +1,7 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +DESCRIPTION

+ +-----------

+ +A CXL region is composed of one or more slices of CXL memdevs, with configurable

+ +interleave settings - both the number of interleave ways, and the interleave

+ +granularity.

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index 9e6fc62..843bada 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -18,4 +18,5 @@ int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx);

+  #endif /* _CXL_BUILTIN_H_ */

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index ef4cda9..f0afcfe 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -72,6 +72,7 @@ static struct cmd_struct commands[] = {

+  	{ "enable-port", .c_fn = cmd_enable_port },

+  	{ "set-partition", .c_fn = cmd_set_partition },

+  	{ "disable-bus", .c_fn = cmd_disable_bus },

+ +	{ "create-region", .c_fn = cmd_create_region },

+  };

+  

+  int main(int argc, const char **argv)

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index 609433c..d22d8b1 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -35,8 +35,10 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,

+  struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,

+  						const char *ident,

+  						const char *serial);

+ -struct cxl_region *util_cxl_region_filter(struct cxl_region *region,

+ +struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder,

+  					    const char *__ident);

+ +struct cxl_region *util_cxl_region_filter(struct cxl_region *region,

+ +					  const char *__ident);

+  

+  enum cxl_port_filter_mode {

+  	CXL_PF_SINGLE,

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 70cf286..9dc99df 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -547,6 +547,7 @@ void util_cxl_mappings_append_json(struct json_object *jregion,

+  	cxl_mapping_foreach(region, mapping) {

+  		struct json_object *jmapping;

+  		struct cxl_decoder *decoder;

+ +		struct cxl_memdev *memdev;

+  

+  		jmapping = json_object_new_object();

+  		if (!jmapping)

+ @@ -564,6 +565,14 @@ void util_cxl_mappings_append_json(struct json_object *jregion,

+  		if (!decoder)

+  			continue;

+  

+ +		memdev = cxl_decoder_get_memdev(decoder);

+ +		if (memdev) {

+ +			devname = cxl_memdev_get_devname(memdev);

+ +			jobj = json_object_new_string(devname);

+ +			if (jobj)

+ +				json_object_object_add(jmapping, "memdev", jobj);

+ +		}

+ +

+  		devname = cxl_decoder_get_devname(decoder);

+  		jobj = json_object_new_string(devname);

+  		if (jobj)

+ diff --git a/cxl/meson.build b/cxl/meson.build

+ index d63dcb1..f2474aa 100644

+ --- a/cxl/meson.build

+ +++ b/cxl/meson.build

+ @@ -3,6 +3,7 @@ cxl_src = [

+    'list.c',

+    'port.c',

+    'bus.c',

+ +  'region.c',

+    'memdev.c',

+    'json.c',

+    'filter.c',

+ diff --git a/cxl/region.c b/cxl/region.c

+ new file mode 100644

+ index 0000000..2791ac9

+ --- /dev/null

+ +++ b/cxl/region.c

+ @@ -0,0 +1,550 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */

+ +#include <stdio.h>

+ +#include <errno.h>

+ +#include <stdlib.h>

+ +#include <unistd.h>

+ +#include <limits.h>

+ +#include <util/log.h>

+ +#include <uuid/uuid.h>

+ +#include <util/json.h>

+ +#include <util/size.h>

+ +#include <cxl/libcxl.h>

+ +#include <json-c/json.h>

+ +#include <util/parse-options.h>

+ +#include <ccan/minmax/minmax.h>

+ +#include <ccan/short_types/short_types.h>

+ +

+ +#include "filter.h"

+ +#include "json.h"

+ +

+ +static struct region_params {

+ +	const char *bus;

+ +	const char *size;

+ +	const char *ways;

+ +	const char *granularity;

+ +	const char *type;

+ +	const char *root_decoder;

+ +	const char *region;

+ +	bool memdevs;

+ +	bool force;

+ +	bool human;

+ +	bool debug;

+ +} param;

+ +

+ +struct parsed_params {

+ +	u64 size;

+ +	u64 ep_min_size;

+ +	unsigned int ways;

+ +	unsigned int granularity;

+ +	const char **targets;

+ +	int num_targets;

+ +	struct cxl_decoder *root_decoder;

+ +	enum cxl_decoder_mode mode;

+ +};

+ +

+ +enum region_actions {

+ +	ACTION_CREATE,

+ +};

+ +

+ +static struct log_ctx rl;

+ +

+ +#define BASE_OPTIONS() \

+ +OPT_STRING('b', "bus", &param.bus, "bus name", \

+ +	   "Limit operation to the specified bus"), \

+ +OPT_STRING('d', "decoder", &param.root_decoder, "root decoder name", \

+ +	   "Limit to / use the specified root decoder"), \

+ +OPT_BOOLEAN(0, "debug", &param.debug, "turn on debug")

+ +

+ +#define CREATE_OPTIONS() \

+ +OPT_STRING('s', "size", &param.size, \

+ +	   "size in bytes or with a K/M/G etc. suffix", \

+ +	   "total size desired for the resulting region."), \

+ +OPT_STRING('w', "ways", &param.ways, \

+ +	   "number of interleave ways", \

+ +	   "number of memdevs participating in the regions interleave set"), \

+ +OPT_STRING('g', "granularity", \

+ +	   &param.granularity, "interleave granularity", \

+ +	   "granularity of the interleave set"), \

+ +OPT_STRING('t', "type", &param.type, \

+ +	   "region type", "region type - 'pmem' or 'ram'"), \

+ +OPT_BOOLEAN('m', "memdevs", &param.memdevs, \

+ +	    "non-option arguments are memdevs"), \

+ +OPT_BOOLEAN('u', "human", &param.human, "use human friendly number formats")

+ +

+ +static const struct option create_options[] = {

+ +	BASE_OPTIONS(),

+ +	CREATE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +

+ +

+ +static int parse_create_options(int argc, const char **argv,

+ +				struct parsed_params *p)

+ +{

+ +	int i;

+ +

+ +	if (!param.root_decoder) {

+ +		log_err(&rl, "no root decoder specified\n");

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (param.type) {

+ +		p->mode = cxl_decoder_mode_from_ident(param.type);

+ +		if (p->mode == CXL_DECODER_MODE_NONE) {

+ +			log_err(&rl, "unsupported type: %s\n", param.type);

+ +			return -EINVAL;

+ +		}

+ +	} else {

+ +		p->mode = CXL_DECODER_MODE_PMEM;

+ +	}

+ +

+ +	if (param.size) {

+ +		p->size = parse_size64(param.size);

+ +		if (p->size == ULLONG_MAX) {

+ +			log_err(&rl, "Invalid size: %s\n", param.size);

+ +			return -EINVAL;

+ +		}

+ +	}

+ +

+ +	if (param.ways) {

+ +		unsigned long ways = strtoul(param.ways, NULL, 0);

+ +

+ +		if (ways == ULONG_MAX || (int)ways <= 0) {

+ +			log_err(&rl, "Invalid interleave ways: %s\n",

+ +				param.ways);

+ +			return -EINVAL;

+ +		}

+ +		p->ways = ways;

+ +	} else if (argc) {

+ +		p->ways = argc;

+ +	} else {

+ +		log_err(&rl,

+ +			"couldn't determine interleave ways from options or arguments\n");

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (param.granularity) {

+ +		unsigned long granularity = strtoul(param.granularity, NULL, 0);

+ +

+ +		if (granularity == ULONG_MAX || (int)granularity <= 0) {

+ +			log_err(&rl, "Invalid interleave granularity: %s\n",

+ +				param.granularity);

+ +			return -EINVAL;

+ +		}

+ +		p->granularity = granularity;

+ +	}

+ +

+ +

+ +	if (argc > (int)p->ways) {

+ +		for (i = p->ways; i < argc; i++)

+ +			log_err(&rl, "extra argument: %s\n", p->targets[i]);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (argc < (int)p->ways) {

+ +		log_err(&rl,

+ +			"too few target arguments (%d) for interleave ways (%u)\n",

+ +			argc, p->ways);

+ +		return -EINVAL;

+ +	}

+ +

+ +	if (p->size && p->ways) {

+ +		if (p->size % p->ways) {

+ +			log_err(&rl,

+ +				"size (%lu) is not an integral multiple of interleave-ways (%u)\n",

+ +				p->size, p->ways);

+ +			return -EINVAL;

+ +		}

+ +	}

+ +

+ +	/*

+ +	 * For all practical purposes, -m is the default target type, but

+ +	 * hold off on actively making that decision until a second target

+ +	 * option is available.

+ +	 */

+ +	if (!param.memdevs) {

+ +		log_err(&rl,

+ +			"must specify option for target object types (-m)\n");

+ +		return -EINVAL;

+ +	}

+ +

+ +	return 0;

+ +}

+ +

+ +static int parse_region_options(int argc, const char **argv,

+ +				struct cxl_ctx *ctx, enum region_actions action,

+ +				const struct option *options,

+ +				struct parsed_params *p, const char *usage)

+ +{

+ +	const char * const u[] = {

+ +		usage,

+ +		NULL

+ +	};

+ +

+ +	argc = parse_options(argc, argv, options, u, 0);

+ +	p->targets = argv;

+ +	p->num_targets = argc;

+ +

+ +	if (param.debug) {

+ +		cxl_set_log_priority(ctx, LOG_DEBUG);

+ +		rl.log_priority = LOG_DEBUG;

+ +	} else

+ +		rl.log_priority = LOG_INFO;

+ +

+ +	switch(action) {

+ +	case ACTION_CREATE:

+ +		return parse_create_options(argc, argv, p);

+ +	default:

+ +		return 0;

+ +	}

+ +}

+ +

+ +/**

+ + * validate_memdev() - match memdev with the target provided,

+ + *                     and determine its size contribution

+ + * @memdev: cxl_memdev being tested for a match against the named target

+ + * @target: target memdev

+ + * @p:      params structure

+ + *

+ + * This is called for each memdev in the system, and only returns 'true' if

+ + * the memdev name matches the target argument being tested. Additionally,

+ + * it sets an ep_min_size attribute that always contains the size of the

+ + * smallest target in the provided list. This is used during the automatic

+ + * size determination later, to ensure that all targets contribute equally

+ + * to the region in case of unevenly sized memdevs.

+ + */

+ +static bool validate_memdev(struct cxl_memdev *memdev, const char *target,

+ +			    struct parsed_params *p)

+ +{

+ +	const char *devname = cxl_memdev_get_devname(memdev);

+ +	u64 size;

+ +

+ +	if (strcmp(devname, target) != 0)

+ +		return false;

+ +

+ +	size = cxl_memdev_get_pmem_size(memdev);

+ +	if (!p->ep_min_size)

+ +		p->ep_min_size = size;

+ +	else

+ +		p->ep_min_size = min(p->ep_min_size, size);

+ +

+ +	return true;

+ +}

+ +

+ +static int validate_config_memdevs(struct cxl_ctx *ctx, struct parsed_params *p)

+ +{

+ +	unsigned int i, matched = 0;

+ +

+ +	for (i = 0; i < p->ways; i++) {

+ +		struct cxl_memdev *memdev;

+ +

+ +		cxl_memdev_foreach(ctx, memdev)

+ +			if (validate_memdev(memdev, p->targets[i], p))

+ +				matched++;

+ +	}

+ +	if (matched != p->ways) {

+ +		log_err(&rl,

+ +			"one or more memdevs not found in CXL topology\n");

+ +		return -ENXIO;

+ +	}

+ +

+ +	return 0;

+ +}

+ +

+ +static int validate_decoder(struct cxl_decoder *decoder,

+ +			    struct parsed_params *p)

+ +{

+ +	const char *devname = cxl_decoder_get_devname(decoder);

+ +

+ +	switch(p->mode) {

+ +	case CXL_DECODER_MODE_RAM:

+ +		if (!cxl_decoder_is_volatile_capable(decoder)) {

+ +			log_err(&rl, "%s is not volatile capable\n", devname);

+ +			return -EINVAL;

+ +		}

+ +		break;

+ +	case CXL_DECODER_MODE_PMEM:

+ +		if (!cxl_decoder_is_pmem_capable(decoder)) {

+ +			log_err(&rl, "%s is not pmem capable\n", devname);

+ +			return -EINVAL;

+ +		}

+ +		break;

+ +	default:

+ +		log_err(&rl, "unknown type: %s\n", param.type);

+ +		return -EINVAL;

+ +	}

+ +

+ +	/* TODO check if the interleave config is possible under this decoder */

+ +

+ +	return 0;

+ +}

+ +

+ +static int create_region_validate_config(struct cxl_ctx *ctx,

+ +					 struct parsed_params *p)

+ +{

+ +	struct cxl_bus *bus;

+ +	int rc;

+ +

+ +	cxl_bus_foreach(ctx, bus) {

+ +		struct cxl_decoder *decoder;

+ +		struct cxl_port *port;

+ +

+ +		if (!util_cxl_bus_filter(bus, param.bus))

+ +			continue;

+ +

+ +		port = cxl_bus_get_port(bus);

+ +		if (!cxl_port_is_root(port))

+ +			continue;

+ +

+ +		cxl_decoder_foreach (port, decoder) {

+ +			if (util_cxl_decoder_filter(decoder,

+ +						    param.root_decoder)) {

+ +				p->root_decoder = decoder;

+ +				goto found;

+ +			}

+ +		}

+ +	}

+ +

+ +found:

+ +	if (p->root_decoder == NULL) {

+ +		log_err(&rl, "%s not found in CXL topology\n",

+ +			param.root_decoder);

+ +		return -ENXIO;

+ +	}

+ +

+ +	rc = validate_decoder(p->root_decoder, p);

+ +	if (rc)

+ +		return rc;

+ +

+ +	return validate_config_memdevs(ctx, p);

+ +}

+ +

+ +static struct cxl_decoder *

+ +cxl_memdev_target_find_decoder(struct cxl_ctx *ctx, const char *memdev_name)

+ +{

+ +	struct cxl_endpoint *ep = NULL;

+ +	struct cxl_decoder *decoder;

+ +	struct cxl_memdev *memdev;

+ +	struct cxl_port *port;

+ +

+ +	cxl_memdev_foreach(ctx, memdev) {

+ +		const char *devname = cxl_memdev_get_devname(memdev);

+ +

+ +		if (strcmp(devname, memdev_name) != 0)

+ +			continue;

+ +

+ +		ep = cxl_memdev_get_endpoint(memdev);

+ +	}

+ +

+ +	if (!ep) {

+ +		log_err(&rl, "could not get an endpoint for %s\n",

+ +			memdev_name);

+ +		return NULL;

+ +	}

+ +

+ +	port = cxl_endpoint_get_port(ep);

+ +	if (!port) {

+ +		log_err(&rl, "could not get a port for %s\n",

+ +			memdev_name);

+ +		return NULL;

+ +	}

+ +

+ +	cxl_decoder_foreach(port, decoder)

+ +		if (cxl_decoder_get_size(decoder) == 0)

+ +			return decoder;

+ +

+ +	log_err(&rl, "could not get a free decoder for %s\n", memdev_name);

+ +	return NULL;

+ +}

+ +

+ +#define try(prefix, op, dev, p) \

+ +do { \

+ +	int __rc = prefix##_##op(dev, p); \

+ +	if (__rc) { \

+ +		log_err(&rl, "%s: " #op " failed: %s\n", \

+ +				prefix##_get_devname(dev), \

+ +				strerror(abs(__rc))); \

+ +		rc = __rc; \

+ +		goto err_delete; \

+ +	} \

+ +} while (0)

+ +

+ +static int cxl_region_determine_granularity(struct cxl_region *region,

+ +					    struct parsed_params *p)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	unsigned int granularity, ways;

+ +

+ +	/* Default granularity will be the root decoder's granularity */

+ +	granularity = cxl_decoder_get_interleave_granularity(p->root_decoder);

+ +	if (granularity == 0 || granularity == UINT_MAX) {

+ +		log_err(&rl, "%s: unable to determine root decoder granularity\n",

+ +			devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	/* If no user-supplied granularity, just use the default */

+ +	if (!p->granularity)

+ +		return granularity;

+ +

+ +	ways = cxl_decoder_get_interleave_ways(p->root_decoder);

+ +	if (ways == 0 || ways == UINT_MAX) {

+ +		log_err(&rl, "%s: unable to determine root decoder ways\n",

+ +			devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	/* For ways == 1, any user-supplied granularity is fine */

+ +	if (ways == 1)

+ +		return p->granularity;

+ +

+ +	/*

+ +	 * For ways > 1, only allow the same granularity as the selected

+ +	 * root decoder

+ +	 */

+ +	if (p->granularity == granularity)

+ +		return granularity;

+ +

+ +	log_err(&rl,

+ +		"%s: For an x%d root, only root decoder granularity (%d) permitted\n",

+ +		devname, ways, granularity);

+ +	return -EINVAL;

+ +}

+ +

+ +static int create_region(struct cxl_ctx *ctx, int *count,

+ +			 struct parsed_params *p)

+ +{

+ +	unsigned long flags = UTIL_JSON_TARGETS;

+ +	struct json_object *jregion;

+ +	unsigned int i, granularity;

+ +	struct cxl_region *region;

+ +	const char *devname;

+ +	uuid_t uuid;

+ +	u64 size;

+ +	int rc;

+ +

+ +	rc = create_region_validate_config(ctx, p);

+ +	if (rc)

+ +		return rc;

+ +

+ +	if (p->size) {

+ +		size = p->size;

+ +	} else if (p->ep_min_size) {

+ +		size = p->ep_min_size * p->ways;

+ +	} else {

+ +		log_err(&rl, "%s: unable to determine region size\n", __func__);

+ +		return -ENXIO;

+ +	}

+ +

+ +	if (p->mode == CXL_DECODER_MODE_PMEM) {

+ +		region = cxl_decoder_create_pmem_region(p->root_decoder);

+ +		if (!region) {

+ +			log_err(&rl, "failed to create region under %s\n",

+ +				param.root_decoder);

+ +			return -ENXIO;

+ +		}

+ +	} else {

+ +		log_err(&rl, "region type '%s' not supported yet\n",

+ +			param.type);

+ +		return -EOPNOTSUPP;

+ +	}

+ +

+ +	devname = cxl_region_get_devname(region);

+ +

+ +	rc = cxl_region_determine_granularity(region, p);

+ +	if (rc < 0)

+ +		goto err_delete;

+ +	granularity = rc;

+ +

+ +	uuid_generate(uuid);

+ +	try(cxl_region, set_interleave_granularity, region, granularity);

+ +	try(cxl_region, set_interleave_ways, region, p->ways);

+ +	try(cxl_region, set_uuid, region, uuid);

+ +	try(cxl_region, set_size, region, size);

+ +

+ +	for (i = 0; i < p->ways; i++) {

+ +		struct cxl_decoder *ep_decoder = NULL;

+ +

+ +		ep_decoder = cxl_memdev_target_find_decoder(ctx, p->targets[i]);

+ +		if (!ep_decoder) {

+ +			rc = -ENXIO;

+ +			goto err_delete;

+ +		}

+ +		if (cxl_decoder_get_mode(ep_decoder) != p->mode) {

+ +			/*

+ +			 * The memdev_target_find_decoder() helper returns a free

+ +			 * decoder whose size has been checked for 0.

+ +			 * Thus it is safe to change the mode here if needed.

+ +			 */

+ +			try(cxl_decoder, set_dpa_size, ep_decoder, 0);

+ +			try(cxl_decoder, set_mode, ep_decoder, p->mode);

+ +		}

+ +		try(cxl_decoder, set_dpa_size, ep_decoder, size/p->ways);

+ +		rc = cxl_region_set_target(region, i, ep_decoder);

+ +		if (rc) {

+ +			log_err(&rl, "%s: failed to set target%d to %s\n",

+ +				devname, i, p->targets[i]);

+ +			goto err_delete;

+ +		}

+ +	}

+ +

+ +	rc = cxl_region_decode_commit(region);

+ +	if (rc) {

+ +		log_err(&rl, "%s: failed to commit decode: %s\n", devname,

+ +			strerror(-rc));

+ +		goto err_delete;

+ +	}

+ +

+ +	rc = cxl_region_enable(region);

+ +	if (rc) {

+ +		log_err(&rl, "%s: failed to enable: %s\n", devname,

+ +			strerror(-rc));

+ +		goto err_delete;

+ +	}

+ +	*count = 1;

+ +

+ +	if (isatty(1))

+ +		flags |= UTIL_JSON_HUMAN;

+ +	jregion = util_cxl_region_to_json(region, flags);

+ +	if (jregion)

+ +		printf("%s\n", json_object_to_json_string_ext(jregion,

+ +					JSON_C_TO_STRING_PRETTY));

+ +

+ +	return 0;

+ +

+ +err_delete:

+ +	cxl_region_delete(region);

+ +	return rc;

+ +}

+ +

+ +static int region_action(int argc, const char **argv, struct cxl_ctx *ctx,

+ +			 enum region_actions action,

+ +			 const struct option *options, struct parsed_params *p,

+ +			 int *count, const char *u)

+ +{

+ +	int rc = -ENXIO;

+ +

+ +	log_init(&rl, "cxl region", "CXL_REGION_LOG");

+ +	rc = parse_region_options(argc, argv, ctx, action, options, p, u);

+ +	if (rc)

+ +		return rc;

+ +

+ +	if (action == ACTION_CREATE)

+ +		return create_region(ctx, count, p);

+ +

+ +	return rc;

+ +}

+ +

+ +int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	const char *u = "cxl create-region <target0> ... [<options>]";

+ +	struct parsed_params p = { 0 };

+ +	int rc, count = 0;

+ +

+ +	rc = region_action(argc, argv, ctx, ACTION_CREATE, create_options, &p,

+ +			   &count, u);

+ +	log_info(&rl, "created %d region%s\n", count, count == 1 ? "" : "s");

+ +	return rc == 0 ? 0 : EXIT_FAILURE;

+ +}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,459 @@ 

+ From 93122376250a8a5cfae635e9729c34dfaa0fd116 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:11 -0600

+ Subject: [PATCH 196/217] cxl: add commands to {enable,disable,destroy}-region

+ 

+ With a template from cxl-create-region in place, add its friends:

+ 

+   cxl enable-region

+   cxl disable-region

+   cxl destroy-region

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-9-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-destroy-region.txt |  41 +++++

+  Documentation/cxl/cxl-disable-region.txt |  36 +++++

+  Documentation/cxl/cxl-enable-region.txt  |  36 +++++

+  Documentation/cxl/decoder-option.txt     |   6 +

+  Documentation/cxl/meson.build            |   4 +

+  cxl/builtin.h                            |   3 +

+  cxl/cxl.c                                |   3 +

+  cxl/region.c                             | 193 ++++++++++++++++++++++-

+  8 files changed, 321 insertions(+), 1 deletion(-)

+  create mode 100644 Documentation/cxl/cxl-destroy-region.txt

+  create mode 100644 Documentation/cxl/cxl-disable-region.txt

+  create mode 100644 Documentation/cxl/cxl-enable-region.txt

+  create mode 100644 Documentation/cxl/decoder-option.txt

+ 

+ diff --git a/Documentation/cxl/cxl-destroy-region.txt b/Documentation/cxl/cxl-destroy-region.txt

+ new file mode 100644

+ index 0000000..74f4093

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-destroy-region.txt

+ @@ -0,0 +1,41 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-destroy-region(1)

+ +=====================

+ +

+ +NAME

+ +----

+ +cxl-destroy-region - destroy specified region(s).

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl destroy-region <region> [<options>]'

+ +

+ +include::region-description.txt[]

+ +

+ +EXAMPLE

+ +-------

+ +----

+ +# cxl destroy-region all

+ +destroyed 2 regions

+ +----

+ +

+ +OPTIONS

+ +-------

+ +include::bus-option.txt[]

+ +

+ +-f::

+ +--force::

+ +	Force a destroy operation even if the region is active.

+ +	This will attempt to disable the region first.

+ +

+ +include::decoder-option.txt[]

+ +

+ +include::debug-option.txt[]

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-list[1], linkcxl:cxl-create-region[1]

+ diff --git a/Documentation/cxl/cxl-disable-region.txt b/Documentation/cxl/cxl-disable-region.txt

+ new file mode 100644

+ index 0000000..6a39aee

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-disable-region.txt

+ @@ -0,0 +1,36 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-disable-region(1)

+ +=====================

+ +

+ +NAME

+ +----

+ +cxl-disable-region - disable specified region(s).

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl disable-region <region> [<options>]'

+ +

+ +include::region-description.txt[]

+ +

+ +EXAMPLE

+ +-------

+ +----

+ +# cxl disable-region all

+ +disabled 2 regions

+ +----

+ +

+ +OPTIONS

+ +-------

+ +include::bus-option.txt[]

+ +

+ +include::decoder-option.txt[]

+ +

+ +include::debug-option.txt[]

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-list[1], linkcxl:cxl-enable-region[1]

+ diff --git a/Documentation/cxl/cxl-enable-region.txt b/Documentation/cxl/cxl-enable-region.txt

+ new file mode 100644

+ index 0000000..f6ef00f

+ --- /dev/null

+ +++ b/Documentation/cxl/cxl-enable-region.txt

+ @@ -0,0 +1,36 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +cxl-enable-region(1)

+ +=====================

+ +

+ +NAME

+ +----

+ +cxl-enable-region - enable specified region(s).

+ +

+ +SYNOPSIS

+ +--------

+ +[verse]

+ +'cxl enable-region <region> [<options>]'

+ +

+ +include::region-description.txt[]

+ +

+ +EXAMPLE

+ +-------

+ +----

+ +# cxl enable-region all

+ +enabled 2 regions

+ +----

+ +

+ +OPTIONS

+ +-------

+ +include::bus-option.txt[]

+ +

+ +include::decoder-option.txt[]

+ +

+ +include::debug-option.txt[]

+ +

+ +include::../copyright.txt[]

+ +

+ +SEE ALSO

+ +--------

+ +linkcxl:cxl-list[1], linkcxl:cxl-disable-region[1]

+ diff --git a/Documentation/cxl/decoder-option.txt b/Documentation/cxl/decoder-option.txt

+ new file mode 100644

+ index 0000000..e638d6e

+ --- /dev/null

+ +++ b/Documentation/cxl/decoder-option.txt

+ @@ -0,0 +1,6 @@

+ +// SPDX-License-Identifier: GPL-2.0

+ +

+ +-d::

+ +--decoder=::

+ +	The root decoder to limit the operation to. Only regions that are

+ +	children of the specified decoder will be acted upon.

+ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build

+ index 340cdee..147ea71 100644

+ --- a/Documentation/cxl/meson.build

+ +++ b/Documentation/cxl/meson.build

+ @@ -24,6 +24,7 @@ filedeps = [

+    'labels-options.txt',

+    'debug-option.txt',

+    'region-description.txt',

+ +  'decoder-option.txt',

+  ]

+  

+  cxl_manpages = [

+ @@ -41,6 +42,9 @@ cxl_manpages = [

+    'cxl-reserve-dpa.txt',

+    'cxl-free-dpa.txt',

+    'cxl-create-region.txt',

+ +  'cxl-disable-region.txt',

+ +  'cxl-enable-region.txt',

+ +  'cxl-destroy-region.txt',

+  ]

+  

+  foreach man : cxl_manpages

+ diff --git a/cxl/builtin.h b/cxl/builtin.h

+ index 843bada..b28c221 100644

+ --- a/cxl/builtin.h

+ +++ b/cxl/builtin.h

+ @@ -19,4 +19,7 @@ int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx);

+  int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_enable_region(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_disable_region(int argc, const char **argv, struct cxl_ctx *ctx);

+ +int cmd_destroy_region(int argc, const char **argv, struct cxl_ctx *ctx);

+  #endif /* _CXL_BUILTIN_H_ */

+ diff --git a/cxl/cxl.c b/cxl/cxl.c

+ index f0afcfe..dd1be7a 100644

+ --- a/cxl/cxl.c

+ +++ b/cxl/cxl.c

+ @@ -73,6 +73,9 @@ static struct cmd_struct commands[] = {

+  	{ "set-partition", .c_fn = cmd_set_partition },

+  	{ "disable-bus", .c_fn = cmd_disable_bus },

+  	{ "create-region", .c_fn = cmd_create_region },

+ +	{ "enable-region", .c_fn = cmd_enable_region },

+ +	{ "disable-region", .c_fn = cmd_disable_region },

+ +	{ "destroy-region", .c_fn = cmd_destroy_region },

+  };

+  

+  int main(int argc, const char **argv)

+ diff --git a/cxl/region.c b/cxl/region.c

+ index 2791ac9..b22d3c8 100644

+ --- a/cxl/region.c

+ +++ b/cxl/region.c

+ @@ -45,6 +45,9 @@ struct parsed_params {

+  

+  enum region_actions {

+  	ACTION_CREATE,

+ +	ACTION_ENABLE,

+ +	ACTION_DISABLE,

+ +	ACTION_DESTROY,

+  };

+  

+  static struct log_ctx rl;

+ @@ -78,7 +81,22 @@ static const struct option create_options[] = {

+  	OPT_END(),

+  };

+  

+ +static const struct option enable_options[] = {

+ +	BASE_OPTIONS(),

+ +	OPT_END(),

+ +};

+  

+ +static const struct option disable_options[] = {

+ +	BASE_OPTIONS(),

+ +	OPT_END(),

+ +};

+ +

+ +static const struct option destroy_options[] = {

+ +	BASE_OPTIONS(),

+ +	OPT_BOOLEAN('f', "force", &param.force,

+ +		    "destroy region even if currently active"),

+ +	OPT_END(),

+ +};

+  

+  static int parse_create_options(int argc, const char **argv,

+  				struct parsed_params *p)

+ @@ -519,12 +537,122 @@ err_delete:

+  	return rc;

+  }

+  

+ +static int destroy_region(struct cxl_region *region)

+ +{

+ +	const char *devname = cxl_region_get_devname(region);

+ +	unsigned int ways, i;

+ +	int rc;

+ +

+ +	/* First, unbind/disable the region if needed */

+ +	if (cxl_region_is_enabled(region)) {

+ +		if (param.force) {

+ +			rc = cxl_region_disable(region);

+ +			if (rc) {

+ +				log_err(&rl, "%s: error disabling region: %s\n",

+ +					devname, strerror(-rc));

+ +				return rc;

+ +			}

+ +		} else {

+ +			log_err(&rl, "%s active. Disable it or use --force\n",

+ +				devname);

+ +			return -EBUSY;

+ +		}

+ +	}

+ +

+ +	/* Reset the region decode in preparation for removal */

+ +	rc = cxl_region_decode_reset(region);

+ +	if (rc) {

+ +		log_err(&rl, "%s: failed to reset decode: %s\n", devname,

+ +			strerror(-rc));

+ +		return rc;

+ +	}

+ +

+ +	/* Reset all endpoint decoders and region targets */

+ +	ways = cxl_region_get_interleave_ways(region);

+ +	if (ways == 0 || ways == UINT_MAX) {

+ +		log_err(&rl, "%s: error getting interleave ways\n", devname);

+ +		return -ENXIO;

+ +	}

+ +

+ +	for (i = 0; i < ways; i++) {

+ +		struct cxl_decoder *ep_decoder;

+ +

+ +		ep_decoder = cxl_region_get_target_decoder(region, i);

+ +		if (!ep_decoder)

+ +			return -ENXIO;

+ +

+ +		rc = cxl_region_clear_target(region, i);

+ +		if (rc) {

+ +			log_err(&rl, "%s: clearing target%d failed: %s\n",

+ +				devname, i, strerror(abs(rc)));

+ +			return rc;

+ +		}

+ +

+ +		rc = cxl_decoder_set_dpa_size(ep_decoder, 0);

+ +		if (rc) {

+ +			log_err(&rl, "%s: set_dpa_size failed: %s\n",

+ +				cxl_decoder_get_devname(ep_decoder),

+ +				strerror(abs(rc)));

+ +			return rc;

+ +		}

+ +	}

+ +

+ +	/* Finally, delete the region */

+ +	return cxl_region_delete(region);

+ +}

+ +

+ +static int do_region_xable(struct cxl_region *region, enum region_actions action)

+ +{

+ +	switch (action) {

+ +	case ACTION_ENABLE:

+ +		return cxl_region_enable(region);

+ +	case ACTION_DISABLE:

+ +		return cxl_region_disable(region);

+ +	case ACTION_DESTROY:

+ +		return destroy_region(region);

+ +	default:

+ +		return -EINVAL;

+ +	}

+ +}

+ +

+ +static int decoder_region_action(struct parsed_params *p,

+ +				 struct cxl_decoder *decoder,

+ +				 enum region_actions action, int *count)

+ +{

+ +	struct cxl_region *region, *_r;

+ +	int rc = 0, err_rc = 0;

+ +

+ +	cxl_region_foreach_safe (decoder, region, _r) {

+ +		int i, match = 0;

+ +

+ +		for (i = 0; i < p->num_targets; i++) {

+ +			if (util_cxl_region_filter(region, p->targets[i])) {

+ +				match = 1;

+ +				break;

+ +			}

+ +		}

+ +		if (!match)

+ +			continue;

+ +

+ +		rc = do_region_xable(region, action);

+ +		if (rc == 0) {

+ +			*count += 1;

+ +		} else {

+ +			log_err(&rl, "%s: failed: %s\n",

+ +				cxl_region_get_devname(region), strerror(-rc));

+ +			err_rc = rc;

+ +		}

+ +	}

+ +	return err_rc ? err_rc : rc;

+ +}

+ +

+  static int region_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  			 enum region_actions action,

+  			 const struct option *options, struct parsed_params *p,

+  			 int *count, const char *u)

+  {

+ -	int rc = -ENXIO;

+ +	int rc = 0, err_rc = 0;

+ +	struct cxl_bus *bus;

+  

+  	log_init(&rl, "cxl region", "CXL_REGION_LOG");

+  	rc = parse_region_options(argc, argv, ctx, action, options, p, u);

+ @@ -534,6 +662,33 @@ static int region_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  	if (action == ACTION_CREATE)

+  		return create_region(ctx, count, p);

+  

+ +	cxl_bus_foreach(ctx, bus) {

+ +		struct cxl_decoder *decoder;

+ +		struct cxl_port *port;

+ +

+ +		if (!util_cxl_bus_filter(bus, param.bus))

+ +			continue;

+ +

+ +		port = cxl_bus_get_port(bus);

+ +		if (!cxl_port_is_root(port))

+ +			continue;

+ +

+ +		cxl_decoder_foreach (port, decoder) {

+ +			decoder = util_cxl_decoder_filter(decoder,

+ +							  param.root_decoder);

+ +			if (!decoder)

+ +				continue;

+ +			rc = decoder_region_action(p, decoder, action, count);

+ +			if (rc)

+ +				err_rc = rc;

+ +		}

+ +	}

+ +

+ +	if (err_rc) {

+ +		log_err(&rl, "one or more failures, last failure: %s\n",

+ +			strerror(-err_rc));

+ +		return err_rc;

+ +	}

+  	return rc;

+  }

+  

+ @@ -548,3 +703,39 @@ int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx)

+  	log_info(&rl, "created %d region%s\n", count, count == 1 ? "" : "s");

+  	return rc == 0 ? 0 : EXIT_FAILURE;

+  }

+ +

+ +int cmd_enable_region(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	const char *u = "cxl enable-region <region0> ... [<options>]";

+ +	struct parsed_params p = { 0 };

+ +	int rc, count = 0;

+ +

+ +	rc = region_action(argc, argv, ctx, ACTION_ENABLE, enable_options, &p,

+ +			   &count, u);

+ +	log_info(&rl, "enabled %d region%s\n", count, count == 1 ? "" : "s");

+ +	return rc == 0 ? 0 : EXIT_FAILURE;

+ +}

+ +

+ +int cmd_disable_region(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	const char *u = "cxl disable-region <region0> ... [<options>]";

+ +	struct parsed_params p = { 0 };

+ +	int rc, count = 0;

+ +

+ +	rc = region_action(argc, argv, ctx, ACTION_DISABLE, disable_options, &p,

+ +			   &count, u);

+ +	log_info(&rl, "disabled %d region%s\n", count, count == 1 ? "" : "s");

+ +	return rc == 0 ? 0 : EXIT_FAILURE;

+ +}

+ +

+ +int cmd_destroy_region(int argc, const char **argv, struct cxl_ctx *ctx)

+ +{

+ +	const char *u = "cxl destroy-region <region0> ... [<options>]";

+ +	struct parsed_params p = { 0 };

+ +	int rc, count = 0;

+ +

+ +	rc = region_action(argc, argv, ctx, ACTION_DESTROY, destroy_options, &p,

+ +			   &count, u);

+ +	log_info(&rl, "destroyed %d region%s\n", count, count == 1 ? "" : "s");

+ +	return rc == 0 ? 0 : EXIT_FAILURE;

+ +}

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,39 @@ 

+ From fade1a8039446ed1aa8656f49121886c71d221a4 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:12 -0600

+ Subject: [PATCH 197/217] cxl/list: make memdevs and regions the default

+  listing

+ 

+ Instead of only listing regions by default (which can often be empty if

+ no regions have been configured), change the default listing mode to

+ both memdevs and regions. This will allow a plain 'cxl-list' to be a

+ quick health check of whether all the expected memdevs have enumerated

+ correctly, and see any regions that have been configured.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-10-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/list.c | 3 ++-

+  1 file changed, 2 insertions(+), 1 deletion(-)

+ 

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 88ca9d9..5f604ec 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -100,9 +100,10 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  			param.regions = true;

+  	}

+  

+ -	/* List regions by default */

+ +	/* List regions and memdevs by default */

+  	if (num_list_flags() == 0) {

+  		param.regions = true;

+ +		param.memdevs = true;

+  	}

+  

+  	log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,173 @@ 

+ From 11ca099b52ec339b7464946db144e60399ffa344 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:13 -0600

+ Subject: [PATCH 198/217] test: add a cxl-create-region test

+ 

+ Add a unit test to exercise the cxl-create-region command with different

+ combinations of memdevs and decoders, using cxl_test based mocked

+ devices.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-11-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/cxl-create-region.sh | 125 ++++++++++++++++++++++++++++++++++++++

+  test/meson.build          |   2 +

+  2 files changed, 127 insertions(+)

+  create mode 100644 test/cxl-create-region.sh

+ 

+ diff --git a/test/cxl-create-region.sh b/test/cxl-create-region.sh

+ new file mode 100644

+ index 0000000..66df38f

+ --- /dev/null

+ +++ b/test/cxl-create-region.sh

+ @@ -0,0 +1,125 @@

+ +#!/bin/bash

+ +# SPDX-License-Identifier: GPL-2.0

+ +# Copyright (C) 2022 Intel Corporation. All rights reserved.

+ +

+ +. $(dirname $0)/common

+ +

+ +rc=1

+ +

+ +set -ex

+ +

+ +trap 'err $LINENO' ERR

+ +

+ +check_prereq "jq"

+ +

+ +modprobe -r cxl_test

+ +modprobe cxl_test

+ +udevadm settle

+ +

+ +destroy_regions()

+ +{

+ +	if [[ "$*" ]]; then

+ +		$CXL destroy-region -f -b cxl_test "$@"

+ +	else

+ +		$CXL destroy-region -f -b cxl_test all

+ +	fi

+ +}

+ +

+ +create_x1_region()

+ +{

+ +	mem="$1"

+ +

+ +	# find a pmem capable root decoder for this mem

+ +	decoder=$($CXL list -b cxl_test -D -d root -m "$mem" |

+ +		  jq -r ".[] |

+ +		  select(.pmem_capable == true) |

+ +		  select(.nr_targets == 1) |

+ +		  .decoder")

+ +

+ +	if [[ ! $decoder ]]; then

+ +		echo "no suitable decoder found for $mem, skipping"

+ +		return

+ +	fi

+ +

+ +	# create region

+ +	region=$($CXL create-region -d "$decoder" -m "$mem" | jq -r ".region")

+ +

+ +	if [[ ! $region ]]; then

+ +		echo "create-region failed for $decoder / $mem"

+ +		err "$LINENO"

+ +	fi

+ +

+ +	# cycle disable/enable

+ +	$CXL disable-region --bus=cxl_test "$region"

+ +	$CXL enable-region --bus=cxl_test "$region"

+ +

+ +	# cycle destroying and creating the same region

+ +	destroy_regions "$region"

+ +	region=$($CXL create-region -d "$decoder" -m "$mem" | jq -r ".region")

+ +

+ +	if [[ ! $region ]]; then

+ +		echo "create-region failed for $decoder / $mem"

+ +		err "$LINENO"

+ +	fi

+ +	destroy_regions "$region"

+ +}

+ +

+ +create_subregions()

+ +{

+ +	slice=$((256 << 20))

+ +	mem="$1"

+ +

+ +	# find a pmem capable root decoder for this mem

+ +	decoder=$($CXL list -b cxl_test -D -d root -m "$mem" |

+ +		  jq -r ".[] |

+ +		  select(.pmem_capable == true) |

+ +		  select(.nr_targets == 1) |

+ +		  .decoder")

+ +

+ +	if [[ ! $decoder ]]; then

+ +		echo "no suitable decoder found for $mem, skipping"

+ +		return

+ +	fi

+ +

+ +	size="$($CXL list -m "$mem" | jq -r '.[].pmem_size')"

+ +	if [[ ! $size ]]; then

+ +		echo "$mem: unable to determine size"

+ +		err "$LINENO"

+ +	fi

+ +

+ +	num_regions=$((size / slice))

+ +

+ +	declare -a regions

+ +	for (( i = 0; i < num_regions; i++ )); do

+ +		regions[$i]=$($CXL create-region -d "$decoder" -m "$mem" -s "$slice" | jq -r ".region")

+ +		if [[ ! ${regions[$i]} ]]; then

+ +			echo "create sub-region failed for $decoder / $mem"

+ +			err "$LINENO"

+ +		fi

+ +		udevadm settle

+ +	done

+ +

+ +	echo "created $num_regions subregions:"

+ +	for (( i = 0; i < num_regions; i++ )); do

+ +		echo "${regions[$i]}"

+ +	done

+ +

+ +	for (( i = (num_regions - 1); i >= 0; i-- )); do

+ +		destroy_regions "${regions[$i]}"

+ +	done

+ +}

+ +

+ +# test reading labels directly through cxl-cli

+ +readarray -t mems < <("$CXL" list -b cxl_test -M | jq -r '.[].memdev')

+ +

+ +for mem in ${mems[@]}; do

+ +	create_x1_region "$mem"

+ +done

+ +

+ +# test multiple subregions under the same decoder, using slices of the same memdev

+ +# to test out back-to-back pmem DPA allocations on memdevs

+ +for mem in ${mems[@]}; do

+ +	create_subregions "$mem"

+ +done

+ +

+ +modprobe -r cxl_test

+ diff --git a/test/meson.build b/test/meson.build

+ index b382f46..5953c28 100644

+ --- a/test/meson.build

+ +++ b/test/meson.build

+ @@ -153,6 +153,7 @@ track_uuid = find_program('track-uuid.sh')

+  cxl_topo = find_program('cxl-topology.sh')

+  cxl_sysfs = find_program('cxl-region-sysfs.sh')

+  cxl_labels = find_program('cxl-labels.sh')

+ +cxl_create_region = find_program('cxl-create-region.sh')

+  

+  tests = [

+    [ 'libndctl',               libndctl,		  'ndctl' ],

+ @@ -180,6 +181,7 @@ tests = [

+    [ 'cxl-topology.sh',	      cxl_topo,		  'cxl'   ],

+    [ 'cxl-region-sysfs.sh',    cxl_sysfs,	  'cxl'   ],

+    [ 'cxl-labels.sh',          cxl_labels,	  'cxl'   ],

+ +  [ 'cxl-create-region.sh',   cxl_create_region,  'cxl'   ],

+  ]

+  

+  if get_option('destructive').enabled()

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,240 @@ 

+ From bf0c44e79c0db04b0c1eea884022dfbdc011b979 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Mon, 15 Aug 2022 13:22:14 -0600

+ Subject: [PATCH 199/217] cxl/decoder: add a max_available_extent attribute

+ 

+ Add a max_available_extent attribute to cxl_decoder. In order to aid in

+ its calculation, change the order of regions in the root decoder's list

+ to be sorted by start HPA of the region.

+ 

+ Additionally, emit this attribute in decoder listings, and consult it

+ for available space before creating a new region.

+ 

+ Link: https://lore.kernel.org/r/20220815192214.545800-12-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/json.c         |  8 +++++

+  cxl/lib/libcxl.c   | 84 +++++++++++++++++++++++++++++++++++++++++++++-

+  cxl/lib/libcxl.sym |  1 +

+  cxl/lib/private.h  |  1 +

+  cxl/libcxl.h       |  3 ++

+  cxl/region.c       | 14 +++++++-

+  6 files changed, 109 insertions(+), 2 deletions(-)

+ 

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 9dc99df..9cec58b 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -499,6 +499,14 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	}

+  

+  	if (cxl_port_is_root(port) && cxl_decoder_is_mem_capable(decoder)) {

+ +		size = cxl_decoder_get_max_available_extent(decoder);

+ +		if (size < ULLONG_MAX) {

+ +			jobj = util_json_object_size(size, flags);

+ +			if (jobj)

+ +				json_object_object_add(jdecoder,

+ +						       "max_available_extent",

+ +						       jobj);

+ +		}

+  		if (cxl_decoder_is_pmem_capable(decoder)) {

+  			jobj = json_object_new_boolean(true);

+  			if (jobj)

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index fd2ea4f..c7dc2b0 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -455,6 +455,16 @@ CXL_EXPORT int cxl_region_delete(struct cxl_region *region)

+  	return 0;

+  }

+  

+ +static int region_start_cmp(struct cxl_region *r1, struct cxl_region *r2)

+ +{

+ +	if (r1->start == r2->start)

+ +		return 0;

+ +	else if (r1->start < r2->start)

+ +		return -1;

+ +	else

+ +		return 1;

+ +}

+ +

+  static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)

+  {

+  	const char *devname = devpath_to_devname(cxlregion_base);

+ @@ -539,7 +549,7 @@ static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)

+  			break;

+  		}

+  

+ -	list_add(&decoder->regions, &region->list);

+ +	list_add_sorted(&decoder->regions, region, list, region_start_cmp);

+  

+  	return region;

+  err:

+ @@ -1618,6 +1628,70 @@ cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint)

+  	return NULL;

+  }

+  

+ +static bool cxl_region_is_configured(struct cxl_region *region)

+ +{

+ +	return region->size && (region->decode_state != CXL_DECODE_RESET);

+ +}

+ +

+ +/**

+ + * cxl_decoder_calc_max_available_extent() - calculate max available free space

+ + * @decoder - the root decoder to calculate the free extents for

+ + *

+ + * The add_cxl_region() function  adds regions to the parent decoder's list

+ + * sorted by the region's start HPAs. It can also be assumed that regions have

+ + * no overlapped / aliased HPA space. Therefore, calculating each extent is as

+ + * simple as walking the region list in order, and subtracting the previous

+ + * region's end HPA from the next region's start HPA (and taking into account

+ + * the decoder's start and end HPAs as well).

+ + */

+ +static unsigned long long

+ +cxl_decoder_calc_max_available_extent(struct cxl_decoder *decoder)

+ +{

+ +	u64 prev_end, decoder_end, cur_extent, max_extent = 0;

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	struct cxl_region *region;

+ +

+ +	if (!cxl_port_is_root(port)) {

+ +		err(ctx, "%s: not a root decoder\n",

+ +		    cxl_decoder_get_devname(decoder));

+ +		return ULLONG_MAX;

+ +	}

+ +

+ +	/*

+ +	 * Preload prev_end with an imaginary region that ends just before

+ +	 * the decoder's start, so that the extent calculation for the

+ +	 * first region Just Works

+ +	 */

+ +	prev_end = decoder->start - 1;

+ +

+ +	cxl_region_foreach(decoder, region) {

+ +		if (!cxl_region_is_configured(region))

+ +			continue;

+ +

+ +		/*

+ +		 * region->start - prev_end would get the difference in

+ +		 * addresses, but a difference of 1 in addresses implies

+ +		 * an extent of 0. Hence the '-1'.

+ +		 */

+ +		cur_extent = region->start - prev_end - 1;

+ +		max_extent = max(max_extent, cur_extent);

+ +		prev_end = region->start + region->size - 1;

+ +	}

+ +

+ +	/*

+ +	 * Finally, consider the extent after the last region, up to the end

+ +	 * of the decoder's address space, if any. If there were no regions,

+ +	 * this simply reduces to decoder->size.

+ +	 * Subtracting two addrs gets us a 'size' directly, no need for +/- 1.

+ +	 */

+ +	decoder_end = decoder->start + decoder->size - 1;

+ +	cur_extent = decoder_end - prev_end;

+ +	max_extent = max(max_extent, cur_extent);

+ +

+ +	return max_extent;

+ +}

+ +

+  static int decoder_id_cmp(struct cxl_decoder *d1, struct cxl_decoder *d2)

+  {

+  	return d1->id - d2->id;

+ @@ -1748,6 +1822,8 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)

+  			if (sysfs_read_attr(ctx, path, buf) == 0)

+  				*(flag->flag) = !!strtoul(buf, NULL, 0);

+  		}

+ +		decoder->max_available_extent =

+ +			cxl_decoder_calc_max_available_extent(decoder);

+  		break;

+  	}

+  	}

+ @@ -1912,6 +1988,12 @@ cxl_decoder_get_dpa_size(struct cxl_decoder *decoder)

+  	return decoder->dpa_size;

+  }

+  

+ +CXL_EXPORT unsigned long long

+ +cxl_decoder_get_max_available_extent(struct cxl_decoder *decoder)

+ +{

+ +	return decoder->max_available_extent;

+ +}

+ +

+  CXL_EXPORT int cxl_decoder_set_dpa_size(struct cxl_decoder *decoder,

+  					unsigned long long size)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index cb23a0b..549f88d 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -213,4 +213,5 @@ global:

+  	cxl_decoder_get_memdev;

+  	cxl_decoder_get_interleave_granularity;

+  	cxl_decoder_get_interleave_ways;

+ +	cxl_decoder_get_max_available_extent;

+  } LIBCXL_2;

+ diff --git a/cxl/lib/private.h b/cxl/lib/private.h

+ index 8bc9620..437eade 100644

+ --- a/cxl/lib/private.h

+ +++ b/cxl/lib/private.h

+ @@ -104,6 +104,7 @@ struct cxl_decoder {

+  	u64 size;

+  	u64 dpa_resource;

+  	u64 dpa_size;

+ +	u64 max_available_extent;

+  	void *dev_buf;

+  	size_t buf_len;

+  	char *dev_path;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 69d9c09..61c7fc4 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -134,6 +134,9 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder);

+  unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder);

+ +unsigned long long

+ +cxl_decoder_get_max_available_extent(struct cxl_decoder *decoder);

+ +

+  enum cxl_decoder_mode {

+  	CXL_DECODER_MODE_NONE,

+  	CXL_DECODER_MODE_MIXED,

+ diff --git a/cxl/region.c b/cxl/region.c

+ index b22d3c8..a30313c 100644

+ --- a/cxl/region.c

+ +++ b/cxl/region.c

+ @@ -438,9 +438,9 @@ static int create_region(struct cxl_ctx *ctx, int *count,

+  	struct json_object *jregion;

+  	unsigned int i, granularity;

+  	struct cxl_region *region;

+ +	u64 size, max_extent;

+  	const char *devname;

+  	uuid_t uuid;

+ -	u64 size;

+  	int rc;

+  

+  	rc = create_region_validate_config(ctx, p);

+ @@ -455,6 +455,18 @@ static int create_region(struct cxl_ctx *ctx, int *count,

+  		log_err(&rl, "%s: unable to determine region size\n", __func__);

+  		return -ENXIO;

+  	}

+ +	max_extent = cxl_decoder_get_max_available_extent(p->root_decoder);

+ +	if (max_extent == ULLONG_MAX) {

+ +		log_err(&rl, "%s: unable to determine max extent\n",

+ +			cxl_decoder_get_devname(p->root_decoder));

+ +		return -EINVAL;

+ +	}

+ +	if (size > max_extent) {

+ +		log_err(&rl,

+ +			"%s: region size %#lx exceeds max available space\n",

+ +			cxl_decoder_get_devname(p->root_decoder), size);

+ +		return -ENOSPC;

+ +	}

+  

+  	if (p->mode == CXL_DECODER_MODE_PMEM) {

+  		region = cxl_decoder_create_pmem_region(p->root_decoder);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,108 @@ 

+ From 8b61e8e75443d79d22bf6e74e6b0e36acdd605c3 Mon Sep 17 00:00:00 2001

+ From: Matthew Ho <sunfishho12@gmail.com>

+ Date: Fri, 12 Aug 2022 15:15:53 -0700

+ Subject: [PATCH 200/217] cxl: Add list verbose option to the cxl command

+ 

+ This adds the new subcommands cxl list -v, cxl list -vv, and cxl list -vvv.

+ 

+ cxl list -v is now equivalent to cxl list -RMBDPT, cxl list -vv is

+ equivalent to cxl list -RMBDPTi, and cxl list -vvv is equivalent to

+ cxl list -RMBDPTiHI. These additions make it easier to list all of the CXL

+ devices without having to remember which subcommand must be appended for each

+ type of device.

+ 

+ Link: https://lore.kernel.org/r/20220812221553.92278-1-sunfishho12@gmail.com

+ Reviewed-by: Adam Manzanares <a.manzanares@samsung.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Acked-by: Davidlohr Bueso <dave@stgolabs.net>

+ Signed-off-by: Matthew Ho <sunfishho12@gmail.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/cxl-list.txt | 18 ++++++++++++++++++

+  cxl/filter.h                   |  1 +

+  cxl/list.c                     | 21 +++++++++++++++++++++

+  3 files changed, 40 insertions(+)

+ 

+ diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt

+ index b88940a..14a2b4b 100644

+ --- a/Documentation/cxl/cxl-list.txt

+ +++ b/Documentation/cxl/cxl-list.txt

+ @@ -344,6 +344,24 @@ OPTIONS

+  --region::

+  	Specify CXL region device name(s), or device id(s), to filter the listing.

+  

+ +-v::

+ +--verbose::

+ +	Increase verbosity of the output. This can be specified

+ +	multiple times to be even more verbose on the

+ +	informational and miscellaneous output, and can be used

+ +	to override omitted flags for showing specific

+ +	information. Note that cxl list --verbose --verbose is

+ +	equivalent to cxl list -vv.

+ +	- *-v*

+ +	  Enable --memdevs, --regions, --buses,

+ +	  --ports, --decoders, and --targets.

+ +	- *-vv*

+ +	  Everything *-v* provides, plus include disabled

+ +	  devices with --idle.

+ +	- *-vvv*

+ +	  Everything *-vv* provides, plus enable

+ +	  --health and --partition.

+ +

+  --debug::

+  	If the cxl tool was built with debug enabled, turn on debug

+  	messages.

+ diff --git a/cxl/filter.h b/cxl/filter.h

+ index d22d8b1..256df49 100644

+ --- a/cxl/filter.h

+ +++ b/cxl/filter.h

+ @@ -26,6 +26,7 @@ struct cxl_filter_params {

+  	bool human;

+  	bool health;

+  	bool partition;

+ +	int verbose;

+  	struct log_ctx ctx;

+  };

+  

+ diff --git a/cxl/list.c b/cxl/list.c

+ index 5f604ec..8c48fbb 100644

+ --- a/cxl/list.c

+ +++ b/cxl/list.c

+ @@ -52,6 +52,8 @@ static const struct option options[] = {

+  		    "include memory device health information"),

+  	OPT_BOOLEAN('I', "partition", &param.partition,

+  		    "include memory device partition information"),

+ +	OPT_INCR('v', "verbose", &param.verbose,

+ +		 "increase output detail"),

+  #ifdef ENABLE_DEBUG

+  	OPT_BOOLEAN(0, "debug", &debug, "debug list walk"),

+  #endif

+ @@ -106,6 +108,25 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)

+  		param.memdevs = true;

+  	}

+  

+ +	switch(param.verbose){

+ +	default:

+ +	case 3:

+ +		param.health = true;

+ +		param.partition = true;

+ +		/* fallthrough */

+ +	case 2:

+ +		param.idle = true;

+ +		/* fallthrough */

+ +	case 1:

+ +		param.buses = true;

+ +		param.ports = true;

+ +		param.decoders = true;

+ +		param.targets = true;

+ +		/*fallthrough*/

+ +	case 0:

+ +		break;

+ +	}

+ +

+  	log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");

+  	if (debug) {

+  		cxl_set_log_priority(ctx, LOG_DEBUG);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,57 @@ 

+ From 05a60dc4992bc4698ceff8e6737192ed818e7e34 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Fri, 5 Aug 2022 13:37:56 -0700

+ Subject: [PATCH 201/217] cxl/test: Validate endpoint interleave geometry

+ 

+ Check that endpoint interleave geometry settings are updated once the

+ endpoint decoders are associated with a region.

+ 

+ Link: https://lore.kernel.org/r/165973187660.1528532.13832323649814892720.stgit@dwillia2-xfh.jf.intel.com

+ Reported-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/cxl-region-sysfs.sh | 20 ++++++++++++++++++--

+  1 file changed, 18 insertions(+), 2 deletions(-)

+ 

+ diff --git a/test/cxl-region-sysfs.sh b/test/cxl-region-sysfs.sh

+ index 2582edb..110e037 100644

+ --- a/test/cxl-region-sysfs.sh

+ +++ b/test/cxl-region-sysfs.sh

+ @@ -44,8 +44,8 @@ uuidgen > /sys/bus/cxl/devices/$region/uuid

+  # setup interleave geometry

+  nr_targets=${#endpoint[@]}

+  echo $nr_targets > /sys/bus/cxl/devices/$region/interleave_ways

+ -g=$(cat /sys/bus/cxl/devices/$decoder/interleave_granularity)

+ -echo $g > /sys/bus/cxl/devices/$region/interleave_granularity

+ +r_ig=$(cat /sys/bus/cxl/devices/$decoder/interleave_granularity)

+ +echo $r_ig > /sys/bus/cxl/devices/$region/interleave_granularity

+  echo $((nr_targets * (256<<20))) > /sys/bus/cxl/devices/$region/size

+  

+  # grab the list of memdevs grouped by host-bridge interleave position

+ @@ -96,6 +96,22 @@ do

+  done

+  echo "$region added ${#endpoint[@]} targets: ${endpoint[@]}"

+  

+ +# validate all endpoint decoders have the correct setting

+ +region_size=$(cat /sys/bus/cxl/devices/$region/size)

+ +region_base=$(cat /sys/bus/cxl/devices/$region/resource)

+ +for i in ${endpoint[@]}

+ +do

+ +	iw=$(cat /sys/bus/cxl/devices/$i/interleave_ways)

+ +	ig=$(cat /sys/bus/cxl/devices/$i/interleave_granularity)

+ +	[ $iw -ne $nr_targets ] && err "$LINENO: decoder: $i iw: $iw targets: $nr_targets"

+ +	[ $ig -ne $r_ig] && err "$LINENO: decoder: $i ig: $ig root ig: $r_ig"

+ +

+ +	sz=$(cat /sys/bus/cxl/devices/$i/size)

+ +	res=$(cat /sys/bus/cxl/devices/$i/start)

+ +	[ $sz -ne $region_size ] && err "$LINENO: decoder: $i sz: $sz region_size: $region_size"

+ +	[ $res -ne $region_base ] && err "$LINENO: decoder: $i base: $res region_base: $region_base"

+ +done

+ +

+  # walk up the topology and commit all decoders

+  echo 1 > /sys/bus/cxl/devices/$region/commit

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,49 @@ 

+ From 0ee9ca3f6423a2af8ade983f596274f6fcfe66d6 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Fri, 5 Aug 2022 13:38:03 -0700

+ Subject: [PATCH 202/217] cxl/list: Add interleave parameters to decoder

+  listings

+ 

+ Emit interleave_ways and interleave_granularity in decoder output.

+ 

+ Link: https://lore.kernel.org/r/165973188300.1528532.222988685552982872.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/json.c | 20 ++++++++++++++++++++

+  1 file changed, 20 insertions(+)

+ 

+ diff --git a/cxl/json.c b/cxl/json.c

+ index 9cec58b..ada1dbe 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -466,6 +466,26 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  			json_object_object_add(jdecoder, "size", jobj);

+  	}

+  

+ +	val = cxl_decoder_get_interleave_ways(decoder);

+ +	if (val < UINT_MAX) {

+ +		jobj = json_object_new_int(val);

+ +		if (jobj)

+ +			json_object_object_add(jdecoder, "interleave_ways",

+ +					       jobj);

+ +

+ +		/* granularity is a don't care if not interleaving */

+ +		if (val > 1) {

+ +			val = cxl_decoder_get_interleave_granularity(decoder);

+ +			if (val < UINT_MAX) {

+ +				jobj = json_object_new_int(val);

+ +				if (jobj)

+ +					json_object_object_add(

+ +						jdecoder,

+ +						"interleave_granularity", jobj);

+ +			}

+ +		}

+ +	}

+ +

+  	if (size == 0) {

+  		jobj = json_object_new_string("disabled");

+  		if (jobj)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,140 @@ 

+ From dba61cf8bb9bb96cde8dcf2c9a2dcc663074698b Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Fri, 5 Aug 2022 13:38:08 -0700

+ Subject: [PATCH 203/217] cxl/list: Add region to decoder listings

+ 

+ While decoders can be matched with regions by physical address, or filtered

+ by region, it is also useful to get a plain listing of the association.

+ 

+ Link: https://lore.kernel.org/r/165973188860.1528532.17427805440366364536.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt |  7 +++++++

+  cxl/json.c                       |  8 ++++++++

+  cxl/lib/libcxl.c                 | 34 ++++++++++++++++++++++++++++++++

+  cxl/lib/libcxl.sym               |  1 +

+  cxl/libcxl.h                     |  1 +

+  5 files changed, 51 insertions(+)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 50b0c9c..6756d2f 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -398,6 +398,7 @@ int cxl_decoder_set_dpa_size(struct cxl_decoder *decoder, unsigned long long siz

+  const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);

+  int cxl_decoder_get_id(struct cxl_decoder *decoder);

+  int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);

+ +struct cxl_region *cxl_decoder_get_region(struct cxl_decoder *decoder);

+  

+  enum cxl_decoder_target_type {

+         CXL_DECODER_TTYPE_UNKNOWN,

+ @@ -446,6 +447,12 @@ Platform firmware may setup the CXL decode hierarchy before the OS

+  boots, and may additionally require that the OS not change the decode

+  settings. This property is indicated by the cxl_decoder_is_locked() API.

+  

+ +When a decoder is associated with a region cxl_decoder_get_region()

+ +returns that region object. Note that it is only applicable to switch

+ +and endpoint decoders as root decoders have a 1:N relationship with

+ +regions.  Use cxl_region_foreach() for the similar functionality for

+ +root decoders.

+ +

+  ==== TARGETS

+  A root or switch level decoder takes an SPA (system-physical-address) as

+  input and routes it to a downstream port. Which downstream port depends

+ diff --git a/cxl/json.c b/cxl/json.c

+ index ada1dbe..c3d9299 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -442,6 +442,7 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  	const char *devname = cxl_decoder_get_devname(decoder);

+  	struct cxl_port *port = cxl_decoder_get_port(decoder);

+  	struct json_object *jdecoder, *jobj;

+ +	struct cxl_region *region;

+  	u64 val, size;

+  

+  	jdecoder = json_object_new_object();

+ @@ -486,6 +487,13 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,

+  		}

+  	}

+  

+ +	region = cxl_decoder_get_region(decoder);

+ +	if (region) {

+ +		jobj = json_object_new_string(cxl_region_get_devname(region));

+ +		if (jobj)

+ +			json_object_object_add(jdecoder, "region", jobj);

+ +	}

+ +

+  	if (size == 0) {

+  		jobj = json_object_new_string("disabled");

+  		if (jobj)

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index c7dc2b0..ff85b23 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -2124,6 +2124,40 @@ cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder)

+  	return decoder->interleave_ways;

+  }

+  

+ +CXL_EXPORT struct cxl_region *

+ +cxl_decoder_get_region(struct cxl_decoder *decoder)

+ +{

+ +	struct cxl_port *port = cxl_decoder_get_port(decoder);

+ +	struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);

+ +	char *path = decoder->dev_buf;

+ +	char buf[SYSFS_ATTR_SIZE];

+ +	struct cxl_region *region;

+ +	struct cxl_decoder *iter;

+ +	int rc;

+ +

+ +	if (cxl_port_is_root(port))

+ +		return NULL;

+ +

+ +	sprintf(path, "%s/region", decoder->dev_path);

+ +	rc = sysfs_read_attr(ctx, path, buf);

+ +	if (rc < 0) {

+ +		err(ctx, "failed to read region name: %s\n", strerror(-rc));

+ +		return NULL;

+ +	}

+ +

+ +	if (strcmp(buf, "") == 0)

+ +		return NULL;

+ +

+ +	while (!cxl_port_is_root(port))

+ +		port = cxl_port_get_parent(port);

+ +

+ +	cxl_decoder_foreach(port, iter)

+ +		cxl_region_foreach(iter, region)

+ +			if (strcmp(cxl_region_get_devname(region), buf) == 0)

+ +				return region;

+ +	return NULL;

+ +}

+ +

+  CXL_EXPORT struct cxl_region *

+  cxl_decoder_create_pmem_region(struct cxl_decoder *decoder)

+  {

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 549f88d..385a8f0 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -214,4 +214,5 @@ global:

+  	cxl_decoder_get_interleave_granularity;

+  	cxl_decoder_get_interleave_ways;

+  	cxl_decoder_get_max_available_extent;

+ +	cxl_decoder_get_region;

+  } LIBCXL_2;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 61c7fc4..2498fa1 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -201,6 +201,7 @@ bool cxl_decoder_is_locked(struct cxl_decoder *decoder);

+  unsigned int

+  cxl_decoder_get_interleave_granularity(struct cxl_decoder *decoder);

+  unsigned int cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder);

+ +struct cxl_region *cxl_decoder_get_region(struct cxl_decoder *decoder);

+  struct cxl_region *cxl_decoder_create_pmem_region(struct cxl_decoder *decoder);

+  struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx,

+  					    const char *ident);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,59 @@ 

+ From 81ad0ed44690596a846ac39da0b2fd966973fc21 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Fri, 5 Aug 2022 13:38:14 -0700

+ Subject: [PATCH 204/217] cxl/list: Filter decoders by region

+ 

+ With a region name in hand, it is useful to be able to filter all the

+ decoders in the topology that are mapping that region.

+ 

+ Link: https://lore.kernel.org/r/165973189465.1528532.9072953032089147905.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/filter.c | 23 +++++++++++++++++++++++

+  1 file changed, 23 insertions(+)

+ 

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 38ece55..9a3de8c 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -652,6 +652,26 @@ struct cxl_region *util_cxl_region_filter(struct cxl_region *region,

+  

+  }

+  

+ +static struct cxl_decoder *

+ +util_cxl_decoder_filter_by_region(struct cxl_decoder *decoder,

+ +				  const char *__ident)

+ +{

+ +	struct cxl_region *region;

+ +

+ +	if (!__ident)

+ +		return decoder;

+ +

+ +	region = cxl_decoder_get_region(decoder);

+ +	if (!region)

+ +		return NULL;

+ +

+ +	region = util_cxl_region_filter(region, __ident);

+ +	if (!region)

+ +		return NULL;

+ +

+ +	return decoder;

+ +}

+ +

+  static unsigned long params_to_flags(struct cxl_filter_params *param)

+  {

+  	unsigned long flags = 0;

+ @@ -790,6 +810,9 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,

+  		if (!util_cxl_decoder_filter_by_memdev(

+  			    decoder, p->memdev_filter, p->serial_filter))

+  			goto walk_children;

+ +		if (!util_cxl_decoder_filter_by_region(decoder,

+ +						       p->region_filter))

+ +			goto walk_children;

+  		if (!p->idle && cxl_decoder_get_size(decoder) == 0)

+  			continue;

+  		jdecoder = util_cxl_decoder_to_json(decoder, flags);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,90 @@ 

+ From 2ceddb91d3a0d70a59242b3a9dab401be6e5c825 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Fri, 5 Aug 2022 13:38:20 -0700

+ Subject: [PATCH 205/217] cxl/list: Add 'depth' to port listings

+ 

+ Simplify the task of determining how deep a port is in the hierarchy by

+ just emitting what libcxl already counted. This is useful for validating

+ interleave math.

+ 

+ Link: https://lore.kernel.org/r/165973190022.1528532.6351628365510289908.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  Documentation/cxl/lib/libcxl.txt | 1 +

+  cxl/json.c                       | 4 ++++

+  cxl/lib/libcxl.c                 | 5 +++++

+  cxl/lib/libcxl.sym               | 1 +

+  cxl/libcxl.h                     | 1 +

+  5 files changed, 12 insertions(+)

+ 

+ diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt

+ index 6756d2f..fd2962a 100644

+ --- a/Documentation/cxl/lib/libcxl.txt

+ +++ b/Documentation/cxl/lib/libcxl.txt

+ @@ -290,6 +290,7 @@ int cxl_port_is_enabled(struct cxl_port *port);

+  bool cxl_port_is_root(struct cxl_port *port);

+  bool cxl_port_is_switch(struct cxl_port *port);

+  bool cxl_port_is_endpoint(struct cxl_port *port);

+ +int cxl_port_get_depth(struct cxl_port *port);

+  bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);

+  int cxl_port_get_nr_dports(struct cxl_port *port);

+  ----

+ diff --git a/cxl/json.c b/cxl/json.c

+ index c3d9299..63c1751 100644

+ --- a/cxl/json.c

+ +++ b/cxl/json.c

+ @@ -769,6 +769,10 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,

+  	if (jobj)

+  		json_object_object_add(jport, "host", jobj);

+  

+ +	jobj = json_object_new_int(cxl_port_get_depth(port));

+ +	if (jobj)

+ +		json_object_object_add(jport, "depth", jobj);

+ +

+  	if (!cxl_port_is_enabled(port)) {

+  		jobj = json_object_new_string("disabled");

+  		if (jobj)

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index ff85b23..021d59f 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -2417,6 +2417,11 @@ CXL_EXPORT bool cxl_port_is_endpoint(struct cxl_port *port)

+  	return port->type == CXL_PORT_ENDPOINT;

+  }

+  

+ +CXL_EXPORT int cxl_port_get_depth(struct cxl_port *port)

+ +{

+ +	return port->depth;

+ +}

+ +

+  CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port)

+  {

+  	struct cxl_bus *bus;

+ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym

+ index 385a8f0..8bb91e0 100644

+ --- a/cxl/lib/libcxl.sym

+ +++ b/cxl/lib/libcxl.sym

+ @@ -96,6 +96,7 @@ global:

+  	cxl_port_get_parent;

+  	cxl_port_is_root;

+  	cxl_port_is_switch;

+ +	cxl_port_get_depth;

+  	cxl_port_to_bus;

+  	cxl_port_is_endpoint;

+  	cxl_port_to_endpoint;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 2498fa1..9fe4e99 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -90,6 +90,7 @@ int cxl_port_is_enabled(struct cxl_port *port);

+  struct cxl_port *cxl_port_get_parent(struct cxl_port *port);

+  bool cxl_port_is_root(struct cxl_port *port);

+  bool cxl_port_is_switch(struct cxl_port *port);

+ +int cxl_port_get_depth(struct cxl_port *port);

+  struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);

+  bool cxl_port_is_endpoint(struct cxl_port *port);

+  struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port);

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,63 @@ 

+ From bcc9897b38be91df38f81fb3105d2351f7941377 Mon Sep 17 00:00:00 2001

+ From: Dan Williams <dan.j.williams@intel.com>

+ Date: Fri, 5 Aug 2022 13:38:26 -0700

+ Subject: [PATCH 206/217] cxl/test: Validate switch port settings in

+  cxl-region-sysfs.sh

+ 

+ A recent kernel fix to add the missing update of endpoint decoder HPA range

+ settings regressed switch decoder HPA range settings. Add validation for

+ switch port settings to avoid regressions like that going forward.

+ 

+ Link: https://lore.kernel.org/r/165973190625.1528532.12244196912617964754.stgit@dwillia2-xfh.jf.intel.com

+ Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  test/cxl-region-sysfs.sh | 32 ++++++++++++++++++++++++++++++++

+  1 file changed, 32 insertions(+)

+ 

+ diff --git a/test/cxl-region-sysfs.sh b/test/cxl-region-sysfs.sh

+ index 110e037..ae0f556 100644

+ --- a/test/cxl-region-sysfs.sh

+ +++ b/test/cxl-region-sysfs.sh

+ @@ -112,6 +112,38 @@ do

+  	[ $res -ne $region_base ] && err "$LINENO: decoder: $i base: $res region_base: $region_base"

+  done

+  

+ +# validate all switch decoders have the correct settings

+ +nr_switches=$((nr_targets/2))

+ +nr_host_bridges=$((nr_switches/2))

+ +nr_switch_decoders=$((nr_switches + nr_host_bridges))

+ +

+ +json=$($CXL list -D -r $region -d switch)

+ +readarray -t switch_decoders < <(echo $json | jq -r ".[].decoder")

+ +

+ +[ ${#switch_decoders[@]} -ne $nr_switch_decoders ] && err \

+ +"$LINENO: expected $nr_switch_decoders got ${#switch_decoders[@]} switch decoders"

+ +

+ +for i in ${switch_decoders[@]}

+ +do

+ +	decoder=$(echo $json | jq -r ".[] | select(.decoder == \"$i\")")

+ +	id=${i#decoder}

+ +	port_id=${id%.*}

+ +	depth=$($CXL list -p $port_id -S | jq -r ".[].depth")

+ +	iw=$(echo $decoder | jq -r ".interleave_ways")

+ +	ig=$(echo $decoder | jq -r ".interleave_granularity")

+ +

+ +	[ $iw -ne 2 ] && err "$LINENO: decoder: $i iw: $iw targets: 2"

+ +	[ $ig -ne $((r_ig << depth)) ] && err \

+ +	"$LINENO: decoder: $i ig: $ig switch_ig: $((r_ig << depth))"

+ +

+ +	res=$(echo $decoder | jq -r ".resource")

+ +	sz=$(echo $decoder | jq -r ".size")

+ +	[ $sz -ne $region_size ] && err \

+ +	"$LINENO: decoder: $i sz: $sz region_size: $region_size"

+ +	[ $res -ne $region_base ] && err \

+ +	"$LINENO: decoder: $i base: $res region_base: $region_base"

+ +done

+ +

+  # walk up the topology and commit all decoders

+  echo 1 > /sys/bus/cxl/devices/$region/commit

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,34 @@ 

+ From ed56d6053c532f43a8bbd109a87e754a43def845 Mon Sep 17 00:00:00 2001

+ From: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>

+ Date: Thu, 11 Aug 2022 19:36:53 -0500

+ Subject: [PATCH 207/217] meson: fix modprobedatadir default value

+ 

+ The modprobedatadir is now set as a meson option, but without a

+ default value.

+ 

+ Set the default value if modprobedatadir is not set.

+ 

+ Link: https://lore.kernel.org/r/20220812003653.53992-1-miguel.bernal.marin@linux.intel.com

+ Fixes: 524ad09d5eda ("meson: make modprobedatadir an option")

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  contrib/meson.build | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/contrib/meson.build b/contrib/meson.build

+ index ad63a50..48aa7c0 100644

+ --- a/contrib/meson.build

+ +++ b/contrib/meson.build

+ @@ -26,6 +26,6 @@ endif

+  

+  modprobedatadir = get_option('modprobedatadir')

+  if modprobedatadir == ''

+ -  modprobedatadir = get_option('modprobedatadir')

+ +  modprobedatadir = sysconfdir + '/modprobe.d/'

+  endif

+  install_data('nvdimm-security.conf', install_dir : modprobedatadir)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,49 @@ 

+ From 6f8695fdda4aa8889d2f335e785efb9bfeaef6c5 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 15 Jun 2022 16:48:09 -0600

+ Subject: [PATCH 208/217] ndctl: move developer scripts from contrib/ to

+  scripts/

+ 

+ Allow for scripts/ to be the defacto location for scripts and tooling

+ that may be useful for developers of ndctl, but isn't distributed or

+ installed. Move such scripts currently in contrib/ to scripts/.

+ 

+ Link: https://lore.kernel.org/r/20220615224813.523053-2-vishal.l.verma@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  {contrib => scripts}/daxctl-qemu-hmat-setup | 0

+  {contrib => scripts}/do_abidiff             | 0

+  {contrib => scripts}/prepare-release.sh     | 2 +-

+  3 files changed, 1 insertion(+), 1 deletion(-)

+  rename {contrib => scripts}/daxctl-qemu-hmat-setup (100%)

+  rename {contrib => scripts}/do_abidiff (100%)

+  rename {contrib => scripts}/prepare-release.sh (99%)

+ 

+ diff --git a/contrib/daxctl-qemu-hmat-setup b/scripts/daxctl-qemu-hmat-setup

+ similarity index 100%

+ rename from contrib/daxctl-qemu-hmat-setup

+ rename to scripts/daxctl-qemu-hmat-setup

+ diff --git a/contrib/do_abidiff b/scripts/do_abidiff

+ similarity index 100%

+ rename from contrib/do_abidiff

+ rename to scripts/do_abidiff

+ diff --git a/contrib/prepare-release.sh b/scripts/prepare-release.sh

+ similarity index 99%

+ rename from contrib/prepare-release.sh

+ rename to scripts/prepare-release.sh

+ index fb5cfe3..97ab964 100755

+ --- a/contrib/prepare-release.sh

+ +++ b/scripts/prepare-release.sh

+ @@ -186,7 +186,7 @@ check_libtool_vers "libdaxctl"

+  gen_lists ${last_ref}..HEAD~1

+  

+  # For ABI diff purposes, use the latest fixes tag

+ -contrib/do_abidiff ${last_fix}..HEAD

+ +scripts/do_abidiff ${last_fix}..HEAD

+  

+  # once everything passes, update the git-version

+  sed -i -e "s/DEF_VER=[0-9]\+.*/DEF_VER=${next_ref#v}/" git-version

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,31 @@ 

+ From 426fa7f6c0ad7db9c6b18ef9b2247be224e0ea01 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 15 Jun 2022 16:48:10 -0600

+ Subject: [PATCH 209/217] ndctl: remove obsolete m4 directory

+ 

+ With the conversion to meson, the m4 directory, which may have held

+ symlinks to libtool.m4 and friends, is no longer needed. Remove it.

+ 

+ Link: https://lore.kernel.org/r/20220615224813.523053-3-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  m4/.gitignore | 6 ------

+  1 file changed, 6 deletions(-)

+  delete mode 100644 m4/.gitignore

+ 

+ diff --git a/m4/.gitignore b/m4/.gitignore

+ deleted file mode 100644

+ index 8bab51c..0000000

+ --- a/m4/.gitignore

+ +++ /dev/null

+ @@ -1,6 +0,0 @@

+ -libtool.m4

+ -ltoptions.m4

+ -ltsugar.m4

+ -ltversion.m4

+ -lt~obsolete.m4

+ -

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,32 @@ 

+ From fcc3f6fa2989fbd2ce210c282fabf0bf3821d834 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 15 Jun 2022 16:48:11 -0600

+ Subject: [PATCH 210/217] ndctl: update .gitignore

+ 

+ Add a few files and dirs to .gitignore:

+   - cscope.* (since we already ignore 'tags')

+   - release/ (created by scripts/prepare_release)

+   - scripts/docsurgeon_parser.sh (parser generated by argbash)

+ 

+ Link: https://lore.kernel.org/r/20220615224813.523053-4-vishal.l.verma@intel.com

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  .gitignore | 3 +++

+  1 file changed, 3 insertions(+)

+ 

+ diff --git a/.gitignore b/.gitignore

+ index aa0ce8e..eeb275f 100644

+ --- a/.gitignore

+ +++ b/.gitignore

+ @@ -1,5 +1,8 @@

+  build/

+ +release/

+  rhel/ndctl.spec

+  sles/ndctl.spec

+  *.swp

+  tags

+ +cscope.*

+ +scripts/docsurgeon_parser.sh

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,30 @@ 

+ From 411651adc693e55a521ba312e1e64876519b0379 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 15 Jun 2022 16:48:12 -0600

+ Subject: [PATCH 211/217] scripts: fix contrib/do_abidiff for updated fedpkg

+ 

+ A recent fedpkg update wants --name instead of --module-name.

+ 

+ Link: https://lore.kernel.org/r/20220615224813.523053-5-vishal.l.verma@intel.com

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  scripts/do_abidiff | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/scripts/do_abidiff b/scripts/do_abidiff

+ index 0bd7a16..e8c3a65 100755

+ --- a/scripts/do_abidiff

+ +++ b/scripts/do_abidiff

+ @@ -29,7 +29,7 @@ build_rpm()

+  	version="$(./git-version)"

+  	release="f$(basename $(readlink -f /etc/mock/default.cfg) | cut -d- -f2)"

+  	git archive  --format=tar --prefix="ndctl-${version}/" HEAD | gzip > ndctl-${version}.tar.gz

+ -	fedpkg --release $release --module-name ndctl mockbuild

+ +	fedpkg --release $release --name=ndctl mockbuild

+  	[ "$?" -eq 0 ] || err "error building $ref"

+  	mkdir -p release/rel_${ref}/

+  	cp results_ndctl/*/*/*.x86_64.rpm release/rel_${ref}/

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,66 @@ 

+ From 9ce0fa95778a76d2334848e2629d111c4d636515 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Wed, 15 Jun 2022 16:48:13 -0600

+ Subject: [PATCH 212/217] scripts: update release helper scripts for meson and

+  cxl

+ 

+ The prepare-release.sh and do_abidiff scripts perform sanity checking

+ for library versioning and also guard against accidental ABI breakage

+ by comparing the current release with the previous using 'abipkgdiff'

+ from libabigail. Teach the scripts about libcxl, so that it too can

+ participate in the above checks.

+ 

+ Additionally, move the checks over to the new meson regime. This does

+ break any checking for the older autotools based build, but that should

+ be okay.

+ 

+ Link: https://lore.kernel.org/r/20220615224813.523053-6-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  scripts/do_abidiff         | 3 ++-

+  scripts/prepare-release.sh | 3 ++-

+  2 files changed, 4 insertions(+), 2 deletions(-)

+ 

+ diff --git a/scripts/do_abidiff b/scripts/do_abidiff

+ index e8c3a65..ec3e344 100755

+ --- a/scripts/do_abidiff

+ +++ b/scripts/do_abidiff

+ @@ -53,7 +53,7 @@ do_diff()

+  	local old_lib="$(find . -regex "./release/rel_${old}/${pkg}-libs-[0-9]+.*" | head -1)"

+  	local new_lib="$(find . -regex "./release/rel_${new}/${pkg}-libs-[0-9]+.*" | head -1)"

+  

+ -	[ -n "$pkg" ] || err "specify a package for diff (ndctl, daxctl)"

+ +	[ -n "$pkg" ] || err "specify a package for diff (ndctl, daxctl, cxl)"

+  	[ -n "$old_base" ] || err "$pkg: old_base empty, possible build failure"

+  	[ -n "$new_base" ] || err "$pkg: new_base empty, possible build failure"

+  

+ @@ -75,3 +75,4 @@ build_rpm $old > release/buildlog_$old 2>&1

+  build_rpm $new > release/buildlog_$new 2>&1

+  do_diff ndctl

+  do_diff daxctl

+ +do_diff cxl

+ diff --git a/scripts/prepare-release.sh b/scripts/prepare-release.sh

+ index 97ab964..8901b50 100755

+ --- a/scripts/prepare-release.sh

+ +++ b/scripts/prepare-release.sh

+ @@ -100,7 +100,7 @@ gen_lists()

+  }

+  

+  # Check libtool versions in Makefile.am.in

+ -# $1: lib name (currently libndctl or libdaxctl)

+ +# $1: lib name (currently libndctl, libdaxctl, or libcxl)

+  check_libtool_vers()

+  {

+  	local lib="$1"

+ @@ -181,6 +181,7 @@ next_fix=$(next_fix "$last_fix")

+  

+  check_libtool_vers "libndctl"

+  check_libtool_vers "libdaxctl"

+ +check_libtool_vers "libcxl"

+  

+  # HEAD~1 because HEAD would be the release commit

+  gen_lists ${last_ref}..HEAD~1

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,48 @@ 

+ From 9a993ce24fdd5de45774b65211570dd514cdf61d Mon Sep 17 00:00:00 2001

+ From: Luis Chamberlain <mcgrof@kernel.org>

+ Date: Wed, 17 Aug 2022 18:23:04 -0700

+ Subject: [PATCH 213/217] meson.build: be specific for library path

+ 

+ If you run the typical configure script on a typical linux software

+ project say with ./configure --prefix=/usr/ then the libdir defaults

+ to /usr/lib/ however this is not true with meson.

+ 

+ With meson the current libdir path follows the one set by the prefix,

+ and so with the current setup with prefix forced by default to /usr/

+ we end up with libdir set to /usr/ as well and so libraries built

+ and installed also placed into /usr/ as well, not /usr/lib/ as we

+ would typically expect.

+ 

+ So you if you use today's defaults you end up with the libraries placed

+ into /usr/ and then a simple error such as:

+ 

+ cxl: error while loading shared libraries: libcxl.so.1: cannot open shared object file: No such file or directory

+ 

+ Folks may have overlooked this as their old library is still usable.

+ 

+ Fix this by forcing the default library path to /usr/lib, and so

+ requiring users to set both prefix and libdir if they want to

+ customize both.

+ 

+ Link: https://lore.kernel.org/r/Yv2UeCIcA00lJC5j@bombadil.infradead.org

+ Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  meson.build | 1 +

+  1 file changed, 1 insertion(+)

+ 

+ diff --git a/meson.build b/meson.build

+ index aecf461..802b38c 100644

+ --- a/meson.build

+ +++ b/meson.build

+ @@ -9,6 +9,7 @@ project('ndctl', 'c',

+    default_options : [

+      'c_std=gnu99',

+      'prefix=/usr',

+ +    'libdir=/usr/lib',

+      'sysconfdir=/etc',

+      'localstatedir=/var',

+    ],

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,39 @@ 

+ From cc2766399882001880a899e723c7bd968e60f100 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 23 Aug 2022 01:45:25 -0600

+ Subject: [PATCH 214/217] cxl/region: fix a dereferecnce after NULL check

+ 

+ A NULL check in region_action() implies that 'decoder' might be NULL, but

+ later we dereference it during cxl_decoder_foreach(). The NULL check is

+ valid because it was the filter result being checked, however, while

+ doing this, the original 'decoder' variable was being clobbered.

+ 

+ Check the filter results independently of the original decoder variable.

+ 

+ Link: https://lore.kernel.org/r/20220823074527.404435-2-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/region.c | 5 ++---

+  1 file changed, 2 insertions(+), 3 deletions(-)

+ 

+ diff --git a/cxl/region.c b/cxl/region.c

+ index a30313c..334fcc2 100644

+ --- a/cxl/region.c

+ +++ b/cxl/region.c

+ @@ -686,9 +686,8 @@ static int region_action(int argc, const char **argv, struct cxl_ctx *ctx,

+  			continue;

+  

+  		cxl_decoder_foreach (port, decoder) {

+ -			decoder = util_cxl_decoder_filter(decoder,

+ -							  param.root_decoder);

+ -			if (!decoder)

+ +			if (!util_cxl_decoder_filter(decoder,

+ +						     param.root_decoder))

+  				continue;

+  			rc = decoder_region_action(p, decoder, action, count);

+  			if (rc)

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,50 @@ 

+ From 4750c7f50050195bbd427da69037645916a59b24 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 23 Aug 2022 01:45:26 -0600

+ Subject: [PATCH 215/217] libcxl: fox a resource leak and a forward NULL check

+ 

+ Static analysis reports a couple of issues in add_cxl_region(). Firstly,

+ 'path' wasn't freed in the success case, only in the error case.

+ Secondly, the error handling after 'calloc()'ing the region object

+ erroneously jumped to the error path which tried to free the region object.

+ 

+ Add a new error label to just free 'path' and return for this exit case.

+ 

+ Link: https://lore.kernel.org/r/20220823074527.404435-3-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/lib/libcxl.c | 4 +++-

+  1 file changed, 3 insertions(+), 1 deletion(-)

+ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 021d59f..e8c5d44 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -482,7 +482,7 @@ static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)

+  

+  	region = calloc(1, sizeof(*region));

+  	if (!region)

+ -		goto err;

+ +		goto err_path;

+  

+  	region->id = id;

+  	region->ctx = ctx;

+ @@ -551,11 +551,13 @@ static void *add_cxl_region(void *parent, int id, const char *cxlregion_base)

+  

+  	list_add_sorted(&decoder->regions, region, list, region_start_cmp);

+  

+ +	free(path);

+  	return region;

+  err:

+  	free(region->dev_path);

+  	free(region->dev_buf);

+  	free(region);

+ +err_path:

+  	free(path);

+  	return NULL;

+  }

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,33 @@ 

+ From 934d2b34b616566163d80f5844b371ecf88d646a Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 23 Aug 2022 01:45:27 -0600

+ Subject: [PATCH 216/217] cxl/filter: Fix an uninitialized pointer dereference

+ 

+ Static analysis points out that there was a chance that 'jdecoder' could

+ be used while uninitialized in walk_decoders(). Initialize it to NULL to

+ avoid this.

+ 

+ Link: https://lore.kernel.org/r/20220823074527.404435-4-vishal.l.verma@intel.com

+ Cc: Dan Williams <dan.j.williams@intel.com>

+ Reviewed-by: Dan Williams <dan.j.williams@intel.com>

+ Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

+ ---

+  cxl/filter.c | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/cxl/filter.c b/cxl/filter.c

+ index 9a3de8c..56c6599 100644

+ --- a/cxl/filter.c

+ +++ b/cxl/filter.c

+ @@ -796,7 +796,7 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,

+  	cxl_decoder_foreach(port, decoder) {

+  		const char *devname = cxl_decoder_get_devname(decoder);

+  		struct json_object *jchildregions = NULL;

+ -		struct json_object *jdecoder;

+ +		struct json_object *jdecoder = NULL;

+  

+  		if (!p->decoders)

+  			goto walk_children;

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,133 @@ 

+ From c9c9db39354ea0c3f737378186318e9b7908e3a7 Mon Sep 17 00:00:00 2001

+ From: Vishal Verma <vishal.l.verma@intel.com>

+ Date: Tue, 23 Aug 2022 18:44:35 -0600

+ Subject: [PATCH 217/217] ndctl: release v74

+ 

+ This release incorporates functionality up to the 6.0 kernel.

+ 

+ Highlights include CXL region management, enhancements to cxl-list,

+ cxl_test based unit tests for topology enumeration, and region and

+ label operations, misc build fixes, iniparser include resolution,

+ fixes in config parsing for ndctl-monitor, and misc documentation

+ and unit test updates.

+ 

+ Commands:

+   cxl-create-region: new command (also {enable,disable,destroy}-region)

+   cxl-list: add -v / -vv etc. options for verbosity control

+   cxl-list: new filtering options, endpoint decoder DPA listings

+   cxl-list: add decoder interleave settings, and mode

+   cxl-list: add port depth

+   cxl-list: Auto-enable 'single' mode for port listings

+   cxl-set-partition: Accept 'ram' as an alias for 'volatile'

+   cxl-disable-bus: new command

+   cxl-{reserve,free}-dpa: new commands

+   ndctl-xable-namespace: zero namespace fixes

+   ndctl-monitor: fix config parsing

+   daxctl-reconfigure-device: fix systemd escaping for policy config

+ 

+ Tests:

+   cxl-topology.sh: new test for CXL topology enumeration

+   cxl-region-sysfs.sh: new test for the low-level CXL region ABI

+   cxl-create-region.sh: new test for region management

+   cxl-labels.sh: new test for label management commands

+ 

+ APIs:

+   cxl_bus_disable_invalidate

+   cxl_decoder_create_pmem_region

+   cxl_decoder_get_by_name

+   cxl_decoder_get_dpa_resource

+   cxl_decoder_get_dpa_size

+   cxl_decoder_get_interleave_granularity

+   cxl_decoder_get_interleave_ways

+   cxl_decoder_get_last

+   cxl_decoder_get_max_available_extent

+   cxl_decoder_get_memdev

+   cxl_decoder_get_mode

+   cxl_decoder_get_prev

+   cxl_decoder_get_region

+   cxl_decoder_set_dpa_size

+   cxl_decoder_set_mode

+   cxl_mapping_get_decoder

+   cxl_mapping_get_first

+   cxl_mapping_get_next

+   cxl_mapping_get_position

+   cxl_mapping_get_region

+   cxl_port_get_depth

+   cxl_region_clear_all_targets

+   cxl_region_clear_target

+   cxl_region_decode_commit

+   cxl_region_decode_is_committed

+   cxl_region_decode_reset

+   cxl_region_delete

+   cxl_region_disable

+   cxl_region_enable

+   cxl_region_get_ctx

+   cxl_region_get_decoder

+   cxl_region_get_devname

+   cxl_region_get_first

+   cxl_region_get_id

+   cxl_region_get_interleave_granularity

+   cxl_region_get_interleave_ways

+   cxl_region_get_next

+   cxl_region_get_resource

+   cxl_region_get_size

+   cxl_region_get_target_decoder

+   cxl_region_get_uuid

+   cxl_region_is_enabled

+   cxl_region_set_interleave_granularity

+   cxl_region_set_interleave_ways

+   cxl_region_set_size

+   cxl_region_set_target

+   cxl_region_set_uuid

+ ---

+  git-version | 2 +-

+  meson.build | 8 ++++----

+  2 files changed, 5 insertions(+), 5 deletions(-)

+ 

+ diff --git a/git-version b/git-version

+ index bdea9a9..7d76fa1 100755

+ --- a/git-version

+ +++ b/git-version

+ @@ -19,7 +19,7 @@ dirty() {

+  	fi

+  }

+  

+ -DEF_VER=72

+ +DEF_VER=74

+  

+  LF='

+  '

+ diff --git a/meson.build b/meson.build

+ index 802b38c..20a646d 100644

+ --- a/meson.build

+ +++ b/meson.build

+ @@ -1,5 +1,5 @@

+  project('ndctl', 'c',

+ -  version : '73',

+ +  version : '74',

+    license : [

+      'GPL-2.0',

+      'LGPL-2.1',

+ @@ -292,16 +292,16 @@ config_h = configure_file(

+  add_project_arguments('-include', 'config.h', language : 'c')

+  

+  LIBNDCTL_CURRENT=26

+ -LIBNDCTL_REVISION=0

+ +LIBNDCTL_REVISION=1

+  LIBNDCTL_AGE=20

+  

+  LIBDAXCTL_CURRENT=6

+  LIBDAXCTL_REVISION=1

+  LIBDAXCTL_AGE=5

+  

+ -LIBCXL_CURRENT=2

+ +LIBCXL_CURRENT=3

+  LIBCXL_REVISION=0

+ -LIBCXL_AGE=1

+ +LIBCXL_AGE=2

+  

+  root_inc = include_directories(['.', 'ndctl', ])

+  

+ -- 

+ 2.27.0

+ 

@@ -0,0 +1,273 @@ 

+ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c

+ index 8d39d2c..ba265ed 100644

+ --- a/cxl/lib/libcxl.c

+ +++ b/cxl/lib/libcxl.c

+ @@ -1483,7 +1483,7 @@ struct cel_entry {

+  	__le16 effect;

+  } __attribute__((packed));

+  

+ -CXL_EXPORT int cxl_memdev_get_cel_log(struct cxl_memdev *memdev)

+ +CXL_EXPORT int cxl_memdev_get_cel_log(struct cxl_memdev *memdev, const char* uuid)

+  {

+  	struct cxl_cmd *cmd;

+  	struct cxl_mbox_get_log *get_log_input;

+ @@ -1491,6 +1491,12 @@ CXL_EXPORT int cxl_memdev_get_cel_log(struct cxl_memdev *memdev)

+  	int no_cel_entries;

+  	int rc = 0;

+  

+ +	if (!uuid) {

+ +		fprintf(stderr, "%s: Please specify log uuid argument\n",

+ +				cxl_memdev_get_devname(memdev));

+ +		return -EINVAL;

+ +	}

+ +

+  	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_LOG);

+  	if (!cmd) {

+  		fprintf(stderr, "%s: cxl_memdev_get_cel_log returned Null output\n",

+ @@ -1499,7 +1505,7 @@ CXL_EXPORT int cxl_memdev_get_cel_log(struct cxl_memdev *memdev)

+  	}

+  

+  	get_log_input = (void *) cmd->send_cmd->in.payload;

+ -	uuid_parse(CEL_UUID, get_log_input->uuid);

+ +	uuid_parse(uuid, get_log_input->uuid);

+  	get_log_input->offset = 0;

+  	get_log_input->length = cmd->memdev->payload_max;

+  

+ @@ -2021,7 +2027,9 @@ struct cxl_dram_event_record {

+  	u8 row[3];

+  	__le16 column;

+  	u8 correction_mask[0x20];

+ -	u8 reserved[0x17];

+ +        u8 component_identifier[0x10];

+ +        u8 sub_channel;

+ +	u8 reserved[0x6];

+  } __attribute__((packed));

+  

+  struct cxl_memory_module_record {

+ @@ -2160,6 +2168,16 @@ CXL_EXPORT int cxl_memdev_get_event_records(struct cxl_memdev *memdev, u8 event_

+  			fprintf(stdout, "%*srow: 0x%02x%02x%02x\n", indent+2, "", dram_event->row[0],

+  				dram_event->row[1], dram_event->row[2]);

+  			fprintf(stdout, "%*scolumn: 0x%x\n", indent+2, "", le16_to_cpu(dram_event->column));

+ +			for (int i=0; i < 4; i++) {

+ +				fprintf(stdout, "%*scorrection mask[%d]: 0x", indent+2, "", i);

+ +				for (int j=0; j < 8; j++) {

+ +					fprintf(stdout, "%02x", dram_event->correction_mask[i*j+j]);

+ +				}

+ +				fprintf(stdout, "\n");

+ +			}

+ +			fprintf(stdout, "%*scomponent identifier: 0x%02x%02x%02x\n", indent+2, "",

+ +				dram_event->component_identifier[0], dram_event->component_identifier[1],

+ +				dram_event->component_identifier[2]);

+  		}

+  	}

+  

+ @@ -6272,14 +6290,12 @@ out:

+  	return 0;

+  }

+  

+ -

+  #define CXL_MEM_COMMAND_ID_HEALTH_COUNTERS_GET CXL_MEM_COMMAND_ID_RAW

+  #define CXL_MEM_COMMAND_ID_HEALTH_COUNTERS_GET_OPCODE 52737

+  #define CXL_MEM_COMMAND_ID_HEALTH_COUNTERS_GET_PAYLOAD_OUT_SIZE 40

+  

+ -

+  struct cxl_mbox_health_counters_get_out {

+ -	__le32 temperature_threshold_exceeded;

+ +	__le32 critical_over_temperature_exceeded;

+  	__le32 power_on_events;

+  	__le32 power_on_hours;

+  	__le32 cxl_mem_link_crc_errors;

+ @@ -6289,6 +6305,12 @@ struct cxl_mbox_health_counters_get_out {

+  	__le32 num_ddr_double_ecc_errors;

+  	__le32 link_recovery_events;

+  	__le32 time_in_throttled;

+ +	__le32 over_temperature_warning_level_exceeded;

+ +	__le32 critical_under_temperature_exceeded;

+ +	__le32 under_temperature_warning_level_exceeded;

+ +	__le32 rx_retry_request;

+ +	__le32 rcmd_qs0_hi_threshold_detect;

+ +	__le32 rcmd_qs1_hi_threshold_detect;

+  }  __attribute__((packed));

+  

+  CXL_EXPORT int cxl_memdev_health_counters_get(struct cxl_memdev *memdev)

+ @@ -6327,16 +6349,22 @@ CXL_EXPORT int cxl_memdev_health_counters_get(struct cxl_memdev *memdev)

+  

+  	health_counters_get_out = (void *)cmd->send_cmd->out.payload;

+  	fprintf(stdout, "============================= get health counters ==============================\n");

+ -	fprintf(stdout, "Number of times temperature has exceeded threshold: %d\n", le32_to_cpu(health_counters_get_out->temperature_threshold_exceeded));

+ -	fprintf(stdout, "Number of Power On events: %d\n", le32_to_cpu(health_counters_get_out->power_on_events));

+ -	fprintf(stdout, "Number of Power On hours: %d\n", le32_to_cpu(health_counters_get_out->power_on_hours));

+ -	fprintf(stdout, "Number of CXL.mem Link CRC errors: %d\n", le32_to_cpu(health_counters_get_out->cxl_mem_link_crc_errors));

+ -	fprintf(stdout, "Number of CXL.io Link LCRC errors: %d\n", le32_to_cpu(health_counters_get_out->cxl_io_link_lcrc_errors));

+ -	fprintf(stdout, "Number of CXL.io Link ECRC errors: %d\n", le32_to_cpu(health_counters_get_out->cxl_io_link_ecrc_errors));

+ -	fprintf(stdout, "Number of DDR single ECC errors: %d\n", le32_to_cpu(health_counters_get_out->num_ddr_single_ecc_errors));

+ -	fprintf(stdout, "Number of DDR double ECC errors: %d\n", le32_to_cpu(health_counters_get_out->num_ddr_double_ecc_errors));

+ -	fprintf(stdout, "Number of Link recovery events: %d\n", le32_to_cpu(health_counters_get_out->link_recovery_events));

+ -	fprintf(stdout, "Amount of time spent in throttled state (in seconds): %d\n", le32_to_cpu(health_counters_get_out->time_in_throttled));

+ +	fprintf(stdout, "0: CRITICAL_OVER_TEMPERATURE_EXCEEDED = %d\n", le32_to_cpu(health_counters_get_out->critical_over_temperature_exceeded));

+ +	fprintf(stdout, "1: OVER_TEMPERATURE_WARNING_LEVEL_EXCEEDED = %d\n", le32_to_cpu(health_counters_get_out->over_temperature_warning_level_exceeded));

+ +	fprintf(stdout, "2: CRITICAL_UNDER_TEMPERATURE_EXCEEDED = %d\n", le32_to_cpu(health_counters_get_out->critical_under_temperature_exceeded));

+ +	fprintf(stdout, "3: UNDER_TEMPERATURE_WARNING_LEVEL_EXCEEDED = %d\n", le32_to_cpu(health_counters_get_out->under_temperature_warning_level_exceeded));

+ +	fprintf(stdout, "4: POWER_ON_EVENTS = %d\n", le32_to_cpu(health_counters_get_out->power_on_events));

+ +	fprintf(stdout, "5: POWER_ON_HOURS = %d\n", le32_to_cpu(health_counters_get_out->power_on_hours));

+ +	fprintf(stdout, "6: CXL_MEM_LINK_CRC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->cxl_mem_link_crc_errors));

+ +	fprintf(stdout, "7: CXL_IO_LINK_LCRC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->cxl_io_link_lcrc_errors));

+ +	fprintf(stdout, "8: CXL_IO_LINK_ECRC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->cxl_io_link_ecrc_errors));

+ +	fprintf(stdout, "9: NUM_DDR_SINGLE_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_single_ecc_errors));

+ +	fprintf(stdout, "10: NUM_DDR_DOUBLE_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_double_ecc_errors));

+ +	fprintf(stdout, "11: LINK_RECOVERY_EVENTS = %d\n", le32_to_cpu(health_counters_get_out->link_recovery_events));

+ +	fprintf(stdout, "12: TIME_IN_THROTTLED = %d\n", le32_to_cpu(health_counters_get_out->time_in_throttled));

+ +	fprintf(stdout, "13: RX_RETRY_REQUEST = %d\n", le32_to_cpu(health_counters_get_out->rx_retry_request));

+ +	fprintf(stdout, "14: RCMD_QS0_HI_THRESHOLD_DETECT = %d\n", le32_to_cpu(health_counters_get_out->rcmd_qs0_hi_threshold_detect));

+ +	fprintf(stdout, "15: RCMD_QS1_HI_THRESHOLD_DETECT = %d\n", le32_to_cpu(health_counters_get_out->rcmd_qs1_hi_threshold_detect));

+  

+  out:

+  	cxl_cmd_unref(cmd);

+ @@ -9964,6 +9992,31 @@ out:

+  	return rc;

+  }

+  

+ +struct cxl_dimm_slot_info_out {

+ +	u8 num_dimm_slots;

+ +	u8 rsvd[3];

+ +	u8 slot0_spd_i2c_addr;

+ +	u8 slot0_channel_id;

+ +	u8 slot0_dimm_silk_screen;

+ +	u8 slot0_dimm_present;

+ +	u8 rsvd1[12];

+ +	u8 slot1_spd_i2c_addr;

+ +	u8 slot1_channel_id;

+ +	u8 slot1_dimm_silk_screen;

+ +	u8 slot1_dimm_present;

+ +	u8 rsvd2[12];

+ +	u8 slot2_spd_i2c_addr;

+ +	u8 slot2_channel_id;

+ +	u8 slot2_dimm_silk_screen;

+ +	u8 slot2_dimm_present;

+ +	u8 rsvd3[12];

+ +	u8 slot3_spd_i2c_addr;

+ +	u8 slot3_channel_id;

+ +	u8 slot3_dimm_silk_screen;

+ +	u8 slot3_dimm_present;

+ +	u8 rsvd4[12];

+ +}  __attribute__((packed));

+ +

+  #define CXL_MEM_COMMAND_ID_DIMM_SLOT_INFO CXL_MEM_COMMAND_ID_RAW

+  #define CXL_MEM_COMMAND_ID_DIMM_SLOT_INFO_OPCODE 0xC520

+  #define CXL_MEM_COMMAND_ID_DIMM_SLOT_INFO_PAYLOAD_IN_SIZE 0

+ @@ -9973,10 +10026,12 @@ CXL_EXPORT int cxl_memdev_dimm_slot_info(struct cxl_memdev *memdev)

+  	struct cxl_cmd *cmd;

+  	struct cxl_mem_query_commands *query;

+  	struct cxl_command_info *cinfo;

+ -	u8 *dimm_slot_info;

+ +	struct cxl_dimm_slot_info_out *dimm_slot_info;

+ +	u8 *dimm_slots;

+  	int rc = 0;

+  	int offset = 0;

+ -

+ +	int indent = 2;

+ +	char silk_screen_char;

+  

+  	cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DIMM_SLOT_INFO_OPCODE);

+  	if (!cmd) {

+ @@ -10018,20 +10073,52 @@ CXL_EXPORT int cxl_memdev_dimm_slot_info(struct cxl_memdev *memdev)

+  		return -EINVAL;

+  	}

+  

+ -	dimm_slot_info = (u8*)cmd->send_cmd->out.payload;

+ +	dimm_slot_info = (void *)cmd->send_cmd->out.payload;

+ +	dimm_slots = (u8*)cmd->send_cmd->out.payload;

+  	fprintf(stdout, "=========================== DIMM SLOT INFO ============================\n");

+  	fprintf(stdout, "Output Payload:\n");

+  	for(int i=0; i<cmd->send_cmd->out.size; i++){

+  		if (i % 16 == 0)

+  		{

+ -			fprintf(stdout, "\n%04x  %02x ", i+offset, dimm_slot_info[i]);

+ +			fprintf(stdout, "\n%04x  %02x ", i+offset, dimm_slots[i]);

+  		}

+  		else

+  		{

+ -			fprintf(stdout, "%02x ", dimm_slot_info[i]);

+ +			fprintf(stdout, "%02x ", dimm_slots[i]);

+  		}

+  	}

+ -	fprintf(stdout, "\n");

+ +	fprintf(stdout, "\n\n");

+ +

+ +	// Decoding slot info data.

+ +	fprintf(stdout, "\n\n====== DIMM SLOTS INFO DECODE ============\n");

+ +

+ +	fprintf(stdout, "Number of DIMM Slots: %d\n", dimm_slot_info->num_dimm_slots);

+ +	fprintf(stdout, "DIMM SPD Index: 0\n");

+ +	fprintf(stdout, "%*sDIMM Present: 0x%x\n", indent+2, "", dimm_slot_info->slot0_dimm_present);

+ +	silk_screen_char = dimm_slot_info->slot0_dimm_silk_screen;

+ +	fprintf(stdout, "%*sDIMM Silk Screen: %c\n", indent+2, "", silk_screen_char);

+ +	fprintf(stdout, "%*sChannel ID: 0x%x\n", indent+2, "", dimm_slot_info->slot0_channel_id);

+ +	fprintf(stdout, "%*sI2C Address: 0x%x\n", indent+2, "", dimm_slot_info->slot0_spd_i2c_addr);

+ +	fprintf(stdout, "DIMM SPD Index: 1\n");

+ +	fprintf(stdout, "%*sDIMM Present: 0x%x\n", indent+2, "", dimm_slot_info->slot1_dimm_present);

+ +	silk_screen_char = dimm_slot_info->slot1_dimm_silk_screen;

+ +	fprintf(stdout, "%*sDIMM Silk Screen: %c\n", indent+2, "", silk_screen_char);

+ +	fprintf(stdout, "%*sChannel ID: 0x%x\n", indent+2, "", dimm_slot_info->slot1_channel_id);

+ +	fprintf(stdout, "%*sI2C Address: 0x%x\n", indent+2, "", dimm_slot_info->slot1_spd_i2c_addr);

+ +	fprintf(stdout, "DIMM SPD Index: 2\n");

+ +	fprintf(stdout, "%*sDIMM Present: 0x%x\n", indent+2, "", dimm_slot_info->slot2_dimm_present);

+ +	silk_screen_char = dimm_slot_info->slot2_dimm_silk_screen;

+ +	fprintf(stdout, "%*sDIMM Silk Screen: %c\n", indent+2, "", silk_screen_char);

+ +	fprintf(stdout, "%*sChannel ID: 0x%x\n", indent+2, "", dimm_slot_info->slot2_channel_id);

+ +	fprintf(stdout, "%*sI2C Address: 0x%x\n", indent+2, "", dimm_slot_info->slot2_spd_i2c_addr);

+ +	fprintf(stdout, "DIMM SPD Index: 3\n");

+ +	fprintf(stdout, "%*sDIMM Present: 0x%x\n", indent+2, "", dimm_slot_info->slot3_dimm_present);

+ +	silk_screen_char = dimm_slot_info->slot3_dimm_silk_screen;

+ +	fprintf(stdout, "%*sDIMM Silk Screen: %c\n", indent+2, "", silk_screen_char);

+ +	fprintf(stdout, "%*sChannel ID: 0x%x\n", indent+2, "", dimm_slot_info->slot3_channel_id);

+ +	fprintf(stdout, "%*sI2C Address: 0x%x\n", indent+2, "", dimm_slot_info->slot3_spd_i2c_addr);

+ +

+ +	fprintf(stdout, "\n\n");

+  out:

+  	cxl_cmd_unref(cmd);

+  	return rc;

+ diff --git a/cxl/libcxl.h b/cxl/libcxl.h

+ index 0c24579..6583af5 100644

+ --- a/cxl/libcxl.h

+ +++ b/cxl/libcxl.h

+ @@ -63,7 +63,7 @@ int cxl_memdev_transfer_fw(struct cxl_memdev *memdev, u8 action,

+  int cxl_memdev_activate_fw(struct cxl_memdev *memdev, u8 action,

+  	u8 slot);

+  int cxl_memdev_get_supported_logs(struct cxl_memdev *memdev);

+ -int cxl_memdev_get_cel_log(struct cxl_memdev *memdev);

+ +int cxl_memdev_get_cel_log(struct cxl_memdev *memdev, const char *uuid);

+  int cxl_memdev_get_event_interrupt_policy(struct cxl_memdev *memdev);

+  int cxl_memdev_set_event_interrupt_policy(struct cxl_memdev *memdev, u32 int_policy);

+  int cxl_memdev_get_timestamp(struct cxl_memdev *memdev);

+ diff --git a/cxl/memdev.c b/cxl/memdev.c

+ index 64ba7e0..fba1f75 100644

+ --- a/cxl/memdev.c

+ +++ b/cxl/memdev.c

+ @@ -84,8 +84,17 @@ static const struct option cmd_get_supported_logs_options[] = {

+    OPT_END(),

+  };

+  

+ +static struct _log_uuid {

+ +	const char* uuid;

+ +} log_uuid;

+ +

+ +#define LOG_UUID_OPTIONS() \

+ +OPT_STRING('l', "log_uuid", &log_uuid.uuid, "log-uuid", \

+ +  "CEL Log UUID")

+ +

+  static const struct option cmd_get_cel_log_options[] = {

+    BASE_OPTIONS(),

+ +  LOG_UUID_OPTIONS(),

+    OPT_END(),

+  };

+  

+ @@ -2247,7 +2256,7 @@ static int action_cmd_get_cel_log(struct cxl_memdev *memdev, struct action_conte

+      return -EBUSY;

+    }

+  

+ -  return cxl_memdev_get_cel_log(memdev);

+ +  return cxl_memdev_get_cel_log(memdev, log_uuid.uuid);

+  }

+  

+  static int action_cmd_get_supported_logs(struct cxl_memdev *memdev, struct action_context *actx)

file modified
+332 -85
@@ -1,9 +1,8 @@ 

  Name:		ndctl

  Version:	71.1

- Release:	4.2%{?dist}

+ Release:	8.1%{?dist}

  Summary:	Manage "libnvdimm" subsystem devices (Non-volatile Memory)

  License:	GPLv2

- Group:		System Environment/Base

  Url:		https://github.com/pmem/ndctl

  Source0:	https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz

  
@@ -13,33 +12,215 @@ 

  Patch0:         elake-diff-ea014c0-3ff031d.patch

  # Normal patch generated from `git format-patch`

  Patch1:         elake-c5d4db-7fcbe3.patch

+ # Another `git diff` patch

+ Patch2:         elake-diff-bafc29a0-df411ebe.patch

  %else

- Patch0:		modprobe-link-user-keyring-before-loadkeys.patch

- Patch1:		fb13dfb-zero_info_block-skip-seed-devices.patch

- Patch2:		daef3a3-libndctl-Unify-adding-dimms-for-papr-and-nfit-families.patch

- Patch3:		f081f30-papr-Add-support-to-parse-save_fail-flag-for-dimm.patch

- Patch4:		fe831b5-Use-page-size-as-alignment-value.patch

- Patch5:		e086106-libndctl-papr-Fix-probe-for-papr-scm-compatible-nvdimms.patch

- Patch6:		c521093-ndctl-scrub-Stop-translating-return-values.patch

- Patch7:		4e646fa-ndctl-scrub-Reread-scrub-engine-status-at-start.patch

- Patch8:		9bd2994-ndctl-namespace-Skip-seed-namespaces-when-processing-all-namespaces.patch

- Patch9:		07011a3-ndctl-namespace-Suppress-ENXIO-when-processing-all-namespaces.patch

- Patch10:	80e0d88-namespace-action-Drop-zero-namespace-checks.patch

- Patch11:	aa99000-libndctl-papr-Add-support-for-reporting-shutdown-count.patch

- Patch12:	edcd9b7-libndctl-intel-Indicate-supported-smart-inject-types.patch

- Patch13:	9ef460e-libndctl-papr-Add-limited-support-for-inject-smart.patch

- Patch14:	6e85cac-ndtest-ack-shutdown-count-Skip-the-test-on-ndtest.patch

+ Patch0: 0003-ndctl-test-Fix-btt-expect-table-compile-warning.patch

+ Patch1: 0004-ndctl-test-Cleanup-unnecessary-out-label.patch

+ Patch2: 0005-ndctl-test-Fix-device-dax-mremap-test.patch

+ Patch3: 0006-ndctl-test-Exercise-soft_offline_page-corner-cases.patch

+ Patch4: 0007-msft-Add-xlat_firmware_status-for-JEDEC-Byte-Address.patch

+ Patch5: 0008-ndctl-namespace-Fix-disable-namespace-accounting-rel.patch

+ Patch6: 0009-zero_info_block-skip-seed-devices.patch

+ Patch7: 0010-ndctl-update-.gitignore.patch

+ Patch8: 0011-ndctl-test-add-checking-the-presence-of-jq-command-a.patch

+ Patch9: 0012-Expose-ndctl_bus_nfit_translate_spa-as-a-public-func.patch

+ Patch10: 0013-test-libndctl-Use-ndctl_region_set_ro-to-change-disk.patch

+ Patch11: 0014-daxctl-fail-reconfigure-device-based-on-kernel-onlin.patch

+ Patch12: 0015-libdaxctl-add-an-API-to-check-if-a-device-is-active.patch

+ Patch13: 0016-libndctl-check-for-active-system-ram-before-disablin.patch

+ Patch14: 0017-daxctl-emit-counts-of-total-and-online-memblocks.patch

+ Patch15: 0018-libndctl-Unify-adding-dimms-for-papr-and-nfit-famili.patch

+ Patch16: 0019-test-Don-t-skip-tests-if-nfit-modules-are-missing.patch

+ Patch17: 0020-papr-Add-support-to-parse-save_fail-flag-for-dimm.patch

+ Patch18: 0021-Use-page-size-as-alignment-value.patch

+ Patch19: 0022-libndctl-Remove-redundant-checks-and-assignments.patch

+ Patch20: 0023-ndctl-Update-nvdimm-mailing-list-address.patch

+ Patch21: 0024-libndctl-papr-Fix-probe-for-papr-scm-compatible-nvdi.patch

+ Patch22: 0025-ndctl-scrub-Stop-translating-return-values.patch

+ Patch23: 0026-ndctl-scrub-Reread-scrub-engine-status-at-start.patch

+ Patch24: 0027-ndctl-dimm-Fix-label-index-block-calculations.patch

+ Patch25: 0028-ndctl-namespace-Skip-seed-namespaces-when-processing.patch

+ Patch26: 0029-ndctl-namespace-Suppress-ENXIO-when-processing-all-n.patch

+ Patch27: 0030-namespace-action-Drop-zero-namespace-checks.patch

+ Patch28: 0031-ndctl-add-.clang-format.patch

+ Patch29: 0032-cxl-add-a-cxl-utility-and-libcxl-library.patch

+ Patch30: 0033-cxl-add-a-local-copy-of-the-cxl_mem-UAPI-header.patch

+ Patch31: 0034-util-add-the-struct_size-helper-from-the-kernel.patch

+ Patch32: 0035-libcxl-add-support-for-command-query-and-submission.patch

+ Patch33: 0036-libcxl-add-support-for-the-Identify-Device-command.patch

+ Patch34: 0037-libcxl-add-GET_HEALTH_INFO-mailbox-command-and-acces.patch

+ Patch35: 0038-libcxl-add-support-for-the-GET_LSA-command.patch

+ Patch36: 0039-libcxl-add-label_size-to-cxl_memdev-and-an-API-to-re.patch

+ Patch37: 0040-libcxl-add-representation-for-an-nvdimm-bridge-objec.patch

+ Patch38: 0041-libcxl-add-interfaces-for-label-operations.patch

+ Patch39: 0042-cxl-add-commands-to-read-write-and-zero-labels.patch

+ Patch40: 0043-Documentation-cxl-add-library-API-documentation.patch

+ Patch41: 0044-ndctl-Add-CXL-packages-to-the-RPM-spec.patch

+ Patch42: 0045-cxl-cli-add-bash-completion.patch

+ Patch43: 0046-cxl-add-health-information-to-cxl-list.patch

+ Patch44: 0047-ndctl-install-bash-completion-symlinks.patch

+ Patch45: 0048-scripts-Add-a-man-page-template-generator.patch

+ Patch46: 0049-daxctl-Add-Soft-Reservation-theory-of-operation.patch

+ Patch47: 0061-libcxl-fix-potential-NULL-dereference-in-cxl_memdev_.patch

+ Patch48: 0064-ndctl-release-v72.patch

+ Patch49: 0067-ndctl-add-repology-graphic-to-README.md.patch

+ Patch50: 0068-Documentation-ndctl-fix-self-reference-of-ndctl-disa.patch

+ Patch51: 0069-ndctl-docs-Clarify-update-firwmware-activation-overf.patch

+ Patch52: 0070-ndctl-test-Prepare-for-BLK-aperture-support-removal.patch

+ Patch53: 0071-ndctl-test-Move-reset-to-function-in-common.patch

+ Patch54: 0072-ndctl-test-Initialize-the-label-area-by-default.patch

+ Patch55: 0073-ndctl-test-Skip-BLK-flags-checks.patch

+ Patch56: 0074-ndctl-test-Move-sector-mode-to-a-different-region.patch

+ Patch57: 0075-ndctl-Deprecate-BLK-aperture-support.patch

+ Patch58: 0076-ndctl-test-Fix-support-for-missing-dax_pmem_compat-m.patch

+ Patch59: 0077-util-Distribute-filter-and-json-helpers-to-per-tool-.patch

+ Patch60: 0078-Documentation-Drop-attrs.adoc-include.patch

+ Patch61: 0079-build-Drop-unnecessary-tool-config.h-includes.patch

+ Patch62: 0080-test-Prepare-out-of-line-builds.patch

+ Patch63: 0081-ndctl-Drop-executable-bit-for-bash-completion-script.patch

+ Patch64: 0082-build-Add-meson-build-infrastructure.patch

+ Patch65: 0083-build-Add-meson-rpmbuild-support.patch

+ Patch66: 0084-ndctl-Jettison-autotools.patch

+ Patch67: 0085-ndctl-build-Default-asciidoctor-to-enabled.patch

+ Patch68: 0086-ndctl-update-README.md-for-meson-build.patch

+ Patch69: 0087-test-Add-suite-identifiers-to-tests.patch

+ Patch70: 0088-ndctl-Rename-util_filter-to-ndctl_filter.patch

+ Patch71: 0089-build-Add-tags.patch

+ Patch72: 0090-json-Add-support-for-json_object_new_uint64.patch

+ Patch73: 0091-cxl-json-Cleanup-object-leak-false-positive.patch

+ Patch74: 0092-cxl-list-Support-multiple-memdev-device-name-filter-.patch

+ Patch75: 0093-cxl-list-Support-comma-separated-lists.patch

+ Patch76: 0094-cxl-list-Introduce-cxl_filter_walk.patch

+ Patch77: 0095-cxl-list-Emit-device-serial-numbers.patch

+ Patch78: 0096-cxl-list-Add-filter-by-serial-support.patch

+ Patch79: 0097-cxl-lib-Rename-nvdimm-bridge-to-pmem.patch

+ Patch80: 0098-cxl-list-Cleanup-options-definitions.patch

+ Patch81: 0099-Documentation-Enhance-libcxl-memdev-API-documentatio.patch

+ Patch82: 0100-cxl-list-Add-bus-objects.patch

+ Patch83: 0101-util-json-Warn-on-stderr-about-empty-list-results.patch

+ Patch84: 0102-util-sysfs-Uplevel-modalias-lookup-helper-to-util.patch

+ Patch85: 0103-cxl-list-Add-port-enumeration.patch

+ Patch86: 0104-cxl-list-Add-debug-option.patch

+ Patch87: 0105-cxl-list-Add-endpoints.patch

+ Patch88: 0106-cxl-list-Add-host-entries-for-port-like-objects.patch

+ Patch89: 0107-cxl-list-Add-host-entries-for-memdevs.patch

+ Patch90: 0108-cxl-list-Move-enabled-memdevs-underneath-their-endpo.patch

+ Patch91: 0109-cxl-list-Filter-memdev-by-ancestry.patch

+ Patch92: 0110-cxl-memdev-Use-a-local-logger-for-debug.patch

+ Patch93: 0111-cxl-memdev-Cleanup-memdev-filter.patch

+ Patch94: 0112-cxl-memdev-Add-serial-support-for-memdev-related-com.patch

+ Patch95: 0113-cxl-list-Add-numa_node-to-memdev-listings.patch

+ Patch96: 0114-util-Implement-common-bind-unbind-helpers.patch

+ Patch97: 0115-cxl-memdev-Enable-disable-support.patch

+ Patch98: 0116-cxl-list-Add-decoder-support.patch

+ Patch99: 0117-cxl-list-Extend-decoder-objects-with-target-informat.patch

+ Patch100: 0118-cxl-list-Use-physical_node-for-root-port-attachment-.patch

+ Patch101: 0119-cxl-list-Reuse-the-target-option-for-ports.patch

+ Patch102: 0120-cxl-list-Support-filtering-memdevs-by-decoders.patch

+ Patch103: 0121-cxl-list-Support-filtering-memdevs-by-ports.patch

+ Patch104: 0122-cxl-port-Add-disable-enable-port-command.patch

+ Patch105: 0123-cxl-list-Filter-dports-and-targets-by-memdevs.patch

+ Patch106: 0124-ndctl-test-make-inject-smart.sh-more-tolerant-of-dec.patch

+ Patch107: 0125-libndctl-papr-Add-support-for-reporting-shutdown-cou.patch

+ Patch108: 0126-libndctl-intel-Indicate-supported-smart-inject-types.patch

+ Patch109: 0127-libndctl-papr-Add-limited-support-for-inject-smart.patch

+ Patch110: 0128-ndtest-ack-shutdown-count-Skip-the-test-on-ndtest.patch

+ Patch111: 0129-ndctl-libndctl-Update-nvdimm-flags-after-smart-injec.patch

+ Patch112: 0132-libcxl-add-GET_PARTITION_INFO-mailbox-command-and-ac.patch

+ Patch113: 0133-libcxl-add-accessors-for-capacity-fields-of-the-IDEN.patch

+ Patch114: 0134-libcxl-return-the-partition-alignment-field-in-bytes.patch

+ Patch115: 0135-cxl-add-memdev-partition-information-to-cxl-list.patch

+ Patch116: 0136-libcxl-add-interfaces-for-SET_PARTITION_INFO-mailbox.patch

+ Patch117: 0137-cxl-add-command-cxl-set-partition.patch

+ Patch118: 0138-Update-ndctl.spec-to-allow-flatpak-builds.patch

+ Patch119: 0139-daxctl-provide-safe-versions-of-iteration-API.patch

+ Patch120: 0140-util-size.h-fix-build-for-older-compilers.patch

+ Patch121: 0141-build-Automate-rpmbuild.sh.patch

+ Patch122: 0142-util-size.h-Fix-build-error-for-GCC-10.patch

+ Patch123: 0143-libcxl-Remove-extraneous-NULL-checks-when-validating.patch

+ Patch124: 0144-libdaxctl-free-resource-allocated-with-asprintf.patch

+ Patch125: 0145-cxl-list-tidy-the-error-path-in-add_cxl_decoder.patch

+ Patch126: 0146-cxl-list-always-free-the-path-var-in-add_cxl_decoder.patch

+ Patch127: 0147-scripts-docsurgeon-Fix-document-header-for-section-1.patch

+ Patch128: 0148-ndctl-release-v73.patch

+ Patch130: 0150-build-Fix-Wall-and-O2-warnings.patch

+ Patch131: 0151-build-Fix-test-timeouts.patch

+ Patch132: 0155-build-Move-utility-helpers-to-libutil.a.patch

+ Patch133: 0156-util-Use-SZ_-size-macros-in-display-size.patch

+ Patch134: 0157-util-Pretty-print-terabytes.patch

+ Patch135: 0158-cxl-port-Fix-disable-port-man-page.patch

+ Patch136: 0159-cxl-bus-Add-bus-disable-support.patch

+ Patch137: 0160-cxl-list-Auto-enable-single-mode-for-port-listings.patch

+ Patch138: 0161-cxl-memdev-Fix-bus_invalidate-crash.patch

+ Patch139: 0162-cxl-list-Add-support-for-filtering-by-host-identifie.patch

+ Patch140: 0163-cxl-port-Relax-port-identifier-validation.patch

+ Patch142: 0165-cxl-test-Add-topology-enumeration-and-hotplug-test.patch

+ Patch143: 0167-daxctl-Fix-kernel-option-typo-in-Soft-Reservation-th.patch

+ Patch144: 0168-meson-make-modprobedatadir-an-option.patch

+ Patch145: 0169-namespace-action-Drop-more-zero-namespace-checks.patch

+ Patch146: 0170-ndctl-dimm-Flush-invalidated-labels-after-overwrite.patch

+ Patch147: 0171-libcxl-fix-a-segfault-when-memdev-pmem-is-absent.patch

+ Patch148: 0172-ndctl-bus-Handle-missing-scrub-commands-more-gracefu.patch

+ Patch149: 0173-util-wrapper.c-Fix-gcc-warning-in-xrealloc.patch

+ Patch150: 0174-libcxl-Fix-memory-leakage-in-cxl_port_init.patch

+ Patch151: 0175-cxl-list-Reformat-option-list.patch

+ Patch152: 0176-cxl-list-Emit-endpoint-decoders-filtered-by-memdev.patch

+ Patch153: 0177-cxl-list-Hide-0s-in-disabled-decoder-listings.patch

+ Patch154: 0178-cxl-list-Add-DPA-span-to-endpoint-decoder-listings.patch

+ Patch155: 0179-ccan-list-Import-latest-list-helpers.patch

+ Patch156: 0180-cxl-lib-Maintain-decoders-in-id-order.patch

+ Patch157: 0181-cxl-memdev-Fix-json-for-multi-device-partitioning.patch

+ Patch158: 0182-cxl-list-Emit-mode-for-endpoint-decoder-objects.patch

+ Patch159: 0183-cxl-set-partition-Accept-ram-as-an-alias-for-volatil.patch

+ Patch160: 0184-cxl-memdev-Add-reserve-free-dpa-commands.patch

+ Patch161: 0185-cxl-test-Update-CXL-memory-parameters.patch

+ Patch162: 0186-cxl-test-Checkout-region-setup-teardown.patch

+ Patch163: 0187-cxl-test-add-a-test-to-read-write-zero-labels.patch

+ Patch164: 0188-cxl-list-Clarify-B-vs-P-p-root.patch

+ Patch165: 0189-libcxl-add-a-depth-attribute-to-cxl_port.patch

+ Patch166: 0190-cxl-port-Consolidate-the-debug-option-in-cxl-port-ma.patch

+ Patch167: 0191-cxl-memdev-refactor-decoder-mode-string-parsing.patch

+ Patch168: 0192-libcxl-Introduce-libcxl-region-and-mapping-objects.patch

+ Patch169: 0193-cxl-cli-add-region-listing-support.patch

+ Patch170: 0194-libcxl-add-low-level-APIs-for-region-creation.patch

+ Patch171: 0195-cxl-add-a-create-region-command.patch

+ Patch172: 0196-cxl-add-commands-to-enable-disable-destroy-region.patch

+ Patch173: 0197-cxl-list-make-memdevs-and-regions-the-default-listin.patch

+ Patch174: 0198-test-add-a-cxl-create-region-test.patch

+ Patch175: 0199-cxl-decoder-add-a-max_available_extent-attribute.patch

+ Patch176: 0200-cxl-Add-list-verbose-option-to-the-cxl-command.patch

+ Patch177: 0201-cxl-test-Validate-endpoint-interleave-geometry.patch

+ Patch178: 0202-cxl-list-Add-interleave-parameters-to-decoder-listin.patch

+ Patch179: 0203-cxl-list-Add-region-to-decoder-listings.patch

+ Patch180: 0204-cxl-list-Filter-decoders-by-region.patch

+ Patch181: 0205-cxl-list-Add-depth-to-port-listings.patch

+ Patch182: 0206-cxl-test-Validate-switch-port-settings-in-cxl-region.patch

+ Patch183: 0207-meson-fix-modprobedatadir-default-value.patch

+ Patch184: 0208-ndctl-move-developer-scripts-from-contrib-to-scripts.patch

+ Patch185: 0209-ndctl-remove-obsolete-m4-directory.patch

+ Patch186: 0210-ndctl-update-.gitignore.patch

+ Patch187: 0211-scripts-fix-contrib-do_abidiff-for-updated-fedpkg.patch

+ Patch188: 0212-scripts-update-release-helper-scripts-for-meson-and-.patch

+ Patch189: 0213-meson.build-be-specific-for-library-path.patch

+ Patch190: 0214-cxl-region-fix-a-dereferecnce-after-NULL-check.patch

+ Patch191: 0215-libcxl-fox-a-resource-leak-and-a-forward-NULL-check.patch

+ Patch192: 0216-cxl-filter-Fix-an-uninitialized-pointer-dereference.patch

+ Patch193: 0217-ndctl-release-v74.patch

  %endif

  

  Requires:	ndctl-libs%{?_isa} = %{version}-%{release}

  Requires:	daxctl-libs%{?_isa} = %{version}-%{release}

  %if 0%{?facebook}

- Requires:	cxl-libs%{?_isa} = %{version}-%{release}

+ Requires:       cxl-libs%{?_isa} = %{version}-%{release}

  %endif

+ BuildRequires: make

  BuildRequires:	autoconf

  BuildRequires:	asciidoc

+ %define asciidoc -Dasciidoctor=disabled

  BuildRequires:	xmlto

- BuildRequires:	automake

+ BuildRequires:	meson

+ BuildRequires:	ninja-build

  BuildRequires:	libtool

  BuildRequires:	pkgconfig

  BuildRequires:	pkgconfig(libkmod)
@@ -60,7 +241,6 @@ 

  %package -n ndctl-devel

  Summary:	Development files for libndctl

  License:	LGPLv2

- Group:		Development/Libraries

  Requires:	ndctl-libs%{?_isa} = %{version}-%{release}

  

  %description -n ndctl-devel
@@ -70,7 +250,6 @@ 

  %package -n daxctl

  Summary:	Manage Device-DAX instances

  License:	GPLv2

- Group:		System Environment/Base

  Requires:	daxctl-libs%{?_isa} = %{version}-%{release}

  

  %description -n daxctl
@@ -79,7 +258,17 @@ 

  of performance / feature differentiated memory without need of a

  filesystem.

  

- %if 0%{?facebook}

+ %package -n daxctl-devel

+ Summary:	Development files for libdaxctl

+ License:	LGPLv2

+ Requires:	daxctl-libs%{?_isa} = %{version}-%{release}

+ 

+ %description -n daxctl-devel

+ The %{name}-devel package contains libraries and header files for

+ developing applications that use %{name}, a library for enumerating

+ "Device DAX" devices.  Device DAX is a facility for establishing DAX

+ mappings of performance / feature-differentiated memory.

+ 

  %package -n cxl-cli

  Summary:	Manage CXL devices

  License:	GPLv2
@@ -97,25 +286,10 @@ 

  %description -n cxl-devel

  This package contains libraries and header files for developing applications

  that use libcxl, a library for enumerating and communicating with CXL devices.

- %endif

- 

- %package -n daxctl-devel

- Summary:	Development files for libdaxctl

- License:	LGPLv2

- Group:		Development/Libraries

- Requires:	daxctl-libs%{?_isa} = %{version}-%{release}

- 

- %description -n daxctl-devel

- The %{name}-devel package contains libraries and header files for

- developing applications that use %{name}, a library for enumerating

- "Device DAX" devices.  Device DAX is a facility for establishing DAX

- mappings of performance / feature-differentiated memory.

- 

  

  %package -n ndctl-libs

  Summary:	Management library for "libnvdimm" subsystem devices (Non-volatile Memory)

  License:	LGPLv2

- Group:		System Environment/Libraries

  Requires:	daxctl-libs%{?_isa} = %{version}-%{release}

  

  
@@ -125,38 +299,44 @@ 

  %package -n daxctl-libs

  Summary:	Management library for "Device DAX" devices

  License:	LGPLv2

- Group:		System Environment/Libraries

  

  %description -n daxctl-libs

  Device DAX is a facility for establishing DAX mappings of performance /

  feature-differentiated memory. daxctl-libs provides an enumeration /

  control API for these devices.

  

- %if 0%{?facebook}

  %package -n cxl-libs

  Summary:	Management library for CXL devices

  License:	LGPLv2

  

  %description -n cxl-libs

  libcxl is a library for enumerating and communicating with CXL devices.

- %endif

  

  

  %prep

  %autosetup -p1 ndctl-%{version}

  

  %build

+ %if 0%{?facebook}

  echo %{version} > version

  ./autogen.sh

  %configure --disable-static --disable-silent-rules --disable-asciidoctor

  make %{?_smp_mflags}

+ %else

+ %meson %{?asciidoc} -Dversion-tag=%{version}

+ %meson_build

+ %endif

  

  %install

+ %if 0%{?facebook}

  %make_install

  find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'

  

  %check

  make check

+ %else

+ %meson_install

+ %endif

  

  %ldconfig_scriptlets -n ndctl-libs

  
@@ -185,11 +365,12 @@ 

  %{_mandir}/man1/daxctl*

  %{_datadir}/daxctl/daxctl.conf

  

- %if 0%{?facebook}

  %files -n cxl-cli

  %license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0

  %{_bindir}/cxl

  %{_mandir}/man1/cxl*

+ %if 0%{?facebook} < 1

+ %{bashcompdir}/cxl

  %endif

  

  %files -n ndctl-libs
@@ -202,12 +383,10 @@ 

  %license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0

  %{_libdir}/libdaxctl.so.*

  

- %if 0%{?facebook}

  %files -n cxl-libs

  %doc README.md

  %license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0

  %{_libdir}/libcxl.so.*

- %endif

  

  %files -n ndctl-devel

  %license LICENSES/preferred/LGPL-2.1
@@ -221,18 +400,20 @@ 

  %{_libdir}/libdaxctl.so

  %{_libdir}/pkgconfig/libdaxctl.pc

  

- %if 0%{?facebook}

  %files -n cxl-devel

  %license LICENSES/preferred/LGPL-2.1

  %{_includedir}/cxl/

  %{_libdir}/libcxl.so

  %{_libdir}/pkgconfig/libcxl.pc

  %{_mandir}/man3/cxl*

- %{_mandir}/man3/libcxl.3.gz

- %endif

+ %{_mandir}/man3/libcxl.3*

  

  

  %changelog

+ * Fri Aug 04 2023 Anita Zhang <the.anitazha@gmail.com> - 71.1-8.1

+ - Sync 71.1-8 from c9 branch.

+ - Patch bafc29a0..df411ebe from elake/ndctl fork for hs+fb

+ 

  * Thu Feb 23 2023 Anita Zhang <the.anitazha@gmail.com> - 71.1-4.2

  - Patch SPD decoding and dimm_slot_info CCI command support

  
@@ -240,47 +421,113 @@ 

  - Patch 71.1 with diff between ea014c0..3ff031d from elake/ndctl fork for hs+fb

  - Sync changes from rhel/ndctl.spec (autogenerated by the GitHub Makefile)

  

- * Tue Jun 14 2022 Jeff Moyer <jmoyer@redhat.com> - 71.1-4.el8

- - Pull in fixes from upstream v72 and v73 (Jeff Moyer)

-   - Fix enable-namespace all reporting errors incorrectly

-   - Add support for inject-smart on papr scm

- - Related: bz#2090190 bz#1986185 bz#2040074

+ * Thu Oct 13 2022 Jeff Moyer <jmoyer@redhat.com> - 71.1-8

+ - Backport changes up to v74, excluding the config file changes. (Jeff Moyer)

+   This includes support for the CXL commands, and adds the following

+   packages: cxl-cli, cxl-devel, cxl-libs

+ - Resolves: rhbz#2132167

  

- * Mon Nov 29 2021 Bryan Gurney <bgurney@redhat.com> - 71.1-3.el8

+ * Tue Jun 14 2022 Bryan Gurney <bgurney@redhat.com> - 71.1-7

+ - Pull in fixes from upstream v72 and v73 (Jeff Moyer)

+ - Fix enable-namespace all reporting errors incorrectly

+ - Add support for inject-smart on papr scm

+ - Related: rhbz#2040075

+ - Related: rhbz#1873851

+ - Related: rhbz#1880578

+ - Related: rhbz#1922538

+ - Related: rhbz#2087707

+ 

+ * Wed Dec 1 2021 Bryan Gurney <bgurney@redhat.com> - 71.1-6

+ - Add gating test

+ - Related: rhbz#2028152

+ 

+ * Mon Nov 29 2021 Bryan Gurney <bgurney@redhat.com> - 71.1-5

  - Rebuild with latest json-c version

- - Related: bz#2021816

- 

- * Thu Feb 11 2021 Jeff Moyer <jmoyer@redhat.com> - 71.1-2.el8

- - Get rid of confusing message when deleting all namespaces

- - Related: bz#1782182

- 

- * Fri Feb  5 2021 Jeff Moyer <jmoyer@redhat.com> - 71.1-1.el8

- - Update to v71.1 to pull in ppc support.

- - Related: bz#1782182

- 

- * Fri Nov  1 2019 Jeff Moyer <jmoyer@redhat.com> - 67-2.el8

- - Fix up botched change to nvdimm-security.conf (Jeff Moyer)

- - Related: bz#1724531

- 

- * Mon Oct 28 2019 Jeff Moyer <jmoyer@redhat.com> - 67-1.el8

- - Rebase to v67.  This brings in the following features:

-   - support for the 'security frozen' sysfs attribute

-   - support for using pmem as system ram

-   - various cleanup and bug fixes

- - Fix load-keys failure in initramfs (Jeff Moyer)

- - Resolves: bz#1724531 bz#1730673 bz#1741164 bz#1741165 bz#1749888 bz#1749889

- 

- * Mon Jun  3 2019 Jeff Moyer <jmoyer@redhat.com> - 65-1.el8

- - Rebase to v65.

- - Resolves: bz#1665407 bz#1634349

- 

- * Tue Oct 09 2018 Jeff Moyer <jmoyer@redhat.com - 62-2.el8

- - Remove faulty udev rule

- - Resolves: bz#1637624

- 

- * Thu Aug 23 2018 Jeff Moyer <jmoyer@redhat.com> - 62-1

- - rebase to v62

- - Resolves: bz#1567756 bz#1497651 bz#1610650 bz#1511774 bz#1570548

+ - Related: rhbz#2023317

+ 

+ * Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 71.1-4

+ - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags

+   Related: rhbz#1991688

+ 

+ * Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 71.1-3

+ - Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937

+ 

+ * Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 71.1-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild

+ 

+ * Tue Dec 22 2020 Vishal Verma <vishal.l.verma@intel.com> - 71.1-1

+ - release v71.1

+ 

+ * Sat Dec 19 2020 Vishal Verma <vishal.l.verma@intel.com> - 71-1

+ - release v71

+ 

+ * Sat Oct 10 2020 Vishal Verma <vishal.l.verma@intel.com> - 70.1-1

+ - release v70.1

+ 

+ * Tue Oct 06 2020 Vishal Verma <vishal@stellar.sh> - 70-1

+ - release v70

+ 

+ * Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 69-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild

+ 

+ * Thu Jul 23 2020 Vishal Verma <vishal.l.verma@intel.com> - 69-1

+ - release v69

+ 

+ * Tue Apr 21 2020 Björn Esser <besser82@fedoraproject.org> - 68-2

+ - Rebuild (json-c)

+ 

+ * Tue Mar 24 2020 Vishal Verma <vishal@stellar.sh> - 68-1

+ - release v68

+ 

+ * Fri Jan 31 2020 Vishal Verma <vishal.l.verma@intel.com> - 67-3

+ - Add fix for GCC10 builds

+ 

+ * Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 67-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild

+ 

+ * Mon Oct 28 2019 Vishal Verma <vishal.l.verma@intel.com> - 67-1

+ - release v67

+ 

+ * Wed Aug 07 2019 Vishal Verma <vishal.l.verma@intel.com> - 66-1

+ - release v66

+ 

+ * Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 65-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild

+ 

+ * Sat May 11 2019 Vishal Verma <vishal.l.verma@intel.com> - 65-1

+ - release v65

+ 

+ * Wed Feb 06 2019 Vishal Verma <vishal.l.verma@intel.com> - 64.1-1

+ - release v64.1

+ 

+ * Mon Feb 04 2019 Vishal Verma <vishal.l.verma@intel.com> - 64-1

+ - release v64

+ 

+ * Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 63-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild

+ 

+ * Fri Oct 05 2018 Vishal Verma <vishal.l.verma@intel.com> - 63-1

+ - release v63

+ - remove ndctl-udev and related files

+ 

+ * Tue Aug 14 2018 Vishal Verma <vishal@stellar.sh> - 62-1

+ - release v62

+ - Add files for udev and ndctl-monitor

+ 

+ * Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 61.2-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild

+ 

+ * Wed Jul 11 2018 Vishal Verma <vishal.l.verma@intel.com> - 61.2-1

+ - release v61.2

+ 

+ * Tue Jun 26 2018 Vishal Verma <vishal@stellar.sh> - 61.1-1

+ - release v61.1

+ 

+ * Tue Jun 26 2018 Vishal Verma <vishal@stellar.sh> - 61-1

+ - new version

+ 

+ * Thu May 17 2018 Dan Williams <dan.j.williams@intel.com> - 60.3-1

+ - release v60.3

  

  * Mon Apr 23 2018 Dan Williams <dan.j.williams@intel.com> - 60.1-1

  - release v60.1

  • Sync 71.1-8 from c9 branch.
  • Patch bafc29a0..df411ebe from elake/ndctl fork for hs+fb

Pull-Request has been merged by anitazha

9 months ago
Metadata
Changes Summary 194
+51
file added
SOURCES/0003-ndctl-test-Fix-btt-expect-table-compile-warning.patch
+57
file added
SOURCES/0004-ndctl-test-Cleanup-unnecessary-out-label.patch
+40
file added
SOURCES/0005-ndctl-test-Fix-device-dax-mremap-test.patch
+134
file added
SOURCES/0006-ndctl-test-Exercise-soft_offline_page-corner-cases.patch
+73
file added
SOURCES/0007-msft-Add-xlat_firmware_status-for-JEDEC-Byte-Address.patch
+140
file added
SOURCES/0008-ndctl-namespace-Fix-disable-namespace-accounting-rel.patch
+50
file added
SOURCES/0009-zero_info_block-skip-seed-devices.patch
+51
file added
SOURCES/0010-ndctl-update-.gitignore.patch
+127
file added
SOURCES/0011-ndctl-test-add-checking-the-presence-of-jq-command-a.patch
+78
file added
SOURCES/0012-Expose-ndctl_bus_nfit_translate_spa-as-a-public-func.patch
+72
file added
SOURCES/0013-test-libndctl-Use-ndctl_region_set_ro-to-change-disk.patch
+221
file added
SOURCES/0014-daxctl-fail-reconfigure-device-based-on-kernel-onlin.patch
+63
file added
SOURCES/0015-libdaxctl-add-an-API-to-check-if-a-device-is-active.patch
+113
file added
SOURCES/0016-libndctl-check-for-active-system-ram-before-disablin.patch
+49
file added
SOURCES/0017-daxctl-emit-counts-of-total-and-online-memblocks.patch
+220
file added
SOURCES/0018-libndctl-Unify-adding-dimms-for-papr-and-nfit-famili.patch
+211
file added
SOURCES/0019-test-Don-t-skip-tests-if-nfit-modules-are-missing.patch
+41
file added
SOURCES/0020-papr-Add-support-to-parse-save_fail-flag-for-dimm.patch
+129
file added
SOURCES/0021-Use-page-size-as-alignment-value.patch
+38
file added
SOURCES/0022-libndctl-Remove-redundant-checks-and-assignments.patch
+56
file added
SOURCES/0023-ndctl-Update-nvdimm-mailing-list-address.patch
+122
file added
SOURCES/0024-libndctl-papr-Fix-probe-for-papr-scm-compatible-nvdi.patch
+38
file added
SOURCES/0025-ndctl-scrub-Stop-translating-return-values.patch
+48
file added
SOURCES/0026-ndctl-scrub-Reread-scrub-engine-status-at-start.patch
+167
file added
SOURCES/0027-ndctl-dimm-Fix-label-index-block-calculations.patch
+58
file added
SOURCES/0028-ndctl-namespace-Skip-seed-namespaces-when-processing.patch
+82
file added
SOURCES/0029-ndctl-namespace-Suppress-ENXIO-when-processing-all-n.patch
+85
file added
SOURCES/0030-namespace-action-Drop-zero-namespace-checks.patch
+187
file added
SOURCES/0031-ndctl-add-.clang-format.patch
+1277
file added
SOURCES/0032-cxl-add-a-cxl-utility-and-libcxl-library.patch
+256
file added
SOURCES/0033-cxl-add-a-local-copy-of-the-cxl_mem-UAPI-header.patch
+114
file added
SOURCES/0034-util-add-the-struct_size-helper-from-the-kernel.patch
+535
file added
SOURCES/0035-libcxl-add-support-for-command-query-and-submission.patch
+157
file added
SOURCES/0036-libcxl-add-support-for-the-Identify-Device-command.patch
+575
file added
SOURCES/0037-libcxl-add-GET_HEALTH_INFO-mailbox-command-and-acces.patch
+113
file added
SOURCES/0038-libcxl-add-support-for-the-GET_LSA-command.patch
+89
file added
SOURCES/0039-libcxl-add-label_size-to-cxl_memdev-and-an-API-to-re.patch
+184
file added
SOURCES/0040-libcxl-add-representation-for-an-nvdimm-bridge-objec.patch
+247
file added
SOURCES/0041-libcxl-add-interfaces-for-label-operations.patch
+583
file added
SOURCES/0042-cxl-add-commands-to-read-write-and-zero-labels.patch
+248
file added
SOURCES/0043-Documentation-cxl-add-library-API-documentation.patch
+147
file added
SOURCES/0044-ndctl-Add-CXL-packages-to-the-RPM-spec.patch
+139
file added
SOURCES/0045-cxl-cli-add-bash-completion.patch
+308
file added
SOURCES/0046-cxl-add-health-information-to-cxl-list.patch
+75
file added
SOURCES/0047-ndctl-install-bash-completion-symlinks.patch
+400
file added
SOURCES/0048-scripts-Add-a-man-page-template-generator.patch
+167
file added
SOURCES/0049-daxctl-Add-Soft-Reservation-theory-of-operation.patch
+46
file added
SOURCES/0061-libcxl-fix-potential-NULL-dereference-in-cxl_memdev_.patch
+142
file added
SOURCES/0064-ndctl-release-v72.patch
+32
file added
SOURCES/0067-ndctl-add-repology-graphic-to-README.md.patch
+29
file added
SOURCES/0068-Documentation-ndctl-fix-self-reference-of-ndctl-disa.patch
+97
file added
SOURCES/0069-ndctl-docs-Clarify-update-firwmware-activation-overf.patch
+171
file added
SOURCES/0070-ndctl-test-Prepare-for-BLK-aperture-support-removal.patch
+428
file added
SOURCES/0071-ndctl-test-Move-reset-to-function-in-common.patch
+104
file added
SOURCES/0072-ndctl-test-Initialize-the-label-area-by-default.patch
+43
file added
SOURCES/0073-ndctl-test-Skip-BLK-flags-checks.patch
+41
file added
SOURCES/0074-ndctl-test-Move-sector-mode-to-a-different-region.patch
+1966
file added
SOURCES/0075-ndctl-Deprecate-BLK-aperture-support.patch
+78
file added
SOURCES/0076-ndctl-test-Fix-support-for-missing-dax_pmem_compat-m.patch
+5595
file added
SOURCES/0077-util-Distribute-filter-and-json-helpers-to-per-tool-.patch
+104
file added
SOURCES/0078-Documentation-Drop-attrs.adoc-include.patch
+53
file added
SOURCES/0079-build-Drop-unnecessary-tool-config.h-includes.patch
+355
file added
SOURCES/0080-test-Prepare-out-of-line-builds.patch
+28
file added
SOURCES/0081-ndctl-Drop-executable-bit-for-bash-completion-script.patch
+1577
file added
SOURCES/0082-build-Add-meson-build-infrastructure.patch
+223
file added
SOURCES/0083-build-Add-meson-rpmbuild-support.patch
+1423
file added
SOURCES/0084-ndctl-Jettison-autotools.patch
+32
file added
SOURCES/0085-ndctl-build-Default-asciidoctor-to-enabled.patch
+88
file added
SOURCES/0086-ndctl-update-README.md-for-meson-build.patch
+122
file added
SOURCES/0087-test-Add-suite-identifiers-to-tests.patch
+287
file added
SOURCES/0088-ndctl-Rename-util_filter-to-ndctl_filter.patch
+54
file added
SOURCES/0089-build-Add-tags.patch
+194
file added
SOURCES/0090-json-Add-support-for-json_object_new_uint64.patch
+32
file added
SOURCES/0091-cxl-json-Cleanup-object-leak-false-positive.patch
+118
file added
SOURCES/0092-cxl-list-Support-multiple-memdev-device-name-filter-.patch
+55
file added
SOURCES/0093-cxl-list-Support-comma-separated-lists.patch
+292
file added
SOURCES/0094-cxl-list-Introduce-cxl_filter_walk.patch
+159
file added
SOURCES/0095-cxl-list-Emit-device-serial-numbers.patch
+163
file added
SOURCES/0096-cxl-list-Add-filter-by-serial-support.patch
+164
file added
SOURCES/0097-cxl-lib-Rename-nvdimm-bridge-to-pmem.patch
+61
file added
SOURCES/0098-cxl-list-Cleanup-options-definitions.patch
+170
file added
SOURCES/0099-Documentation-Enhance-libcxl-memdev-API-documentatio.patch
+739
file added
SOURCES/0100-cxl-list-Add-bus-objects.patch
+44
file added
SOURCES/0101-util-json-Warn-on-stderr-about-empty-list-results.patch
+165
file added
SOURCES/0102-util-sysfs-Uplevel-modalias-lookup-helper-to-util.patch
+862
file added
SOURCES/0103-cxl-list-Add-port-enumeration.patch
+103
file added
SOURCES/0104-cxl-list-Add-debug-option.patch
+746
file added
SOURCES/0105-cxl-list-Add-endpoints.patch
+154
file added
SOURCES/0106-cxl-list-Add-host-entries-for-port-like-objects.patch
+175
file added
SOURCES/0107-cxl-list-Add-host-entries-for-memdevs.patch
+499
file added
SOURCES/0108-cxl-list-Move-enabled-memdevs-underneath-their-endpo.patch
+329
file added
SOURCES/0109-cxl-list-Filter-memdev-by-ancestry.patch
+173
file added
SOURCES/0110-cxl-memdev-Use-a-local-logger-for-debug.patch
+64
file added
SOURCES/0111-cxl-memdev-Cleanup-memdev-filter.patch
+133
file added
SOURCES/0112-cxl-memdev-Add-serial-support-for-memdev-related-com.patch
+136
file added
SOURCES/0113-cxl-list-Add-numa_node-to-memdev-listings.patch
+329
file added
SOURCES/0114-util-Implement-common-bind-unbind-helpers.patch
+379
file added
SOURCES/0115-cxl-memdev-Enable-disable-support.patch
+1108
file added
SOURCES/0116-cxl-list-Add-decoder-support.patch
+537
file added
SOURCES/0117-cxl-list-Extend-decoder-objects-with-target-informat.patch
+156
file added
SOURCES/0118-cxl-list-Use-physical_node-for-root-port-attachment-.patch
+457
file added
SOURCES/0119-cxl-list-Reuse-the-target-option-for-ports.patch
+205
file added
SOURCES/0120-cxl-list-Support-filtering-memdevs-by-decoders.patch
+200
file added
SOURCES/0121-cxl-list-Support-filtering-memdevs-by-ports.patch
+734
file added
SOURCES/0122-cxl-port-Add-disable-enable-port-command.patch
+340
file added
SOURCES/0123-cxl-list-Filter-dports-and-targets-by-memdevs.patch
+46
file added
SOURCES/0124-ndctl-test-make-inject-smart.sh-more-tolerant-of-dec.patch
+136
file added
SOURCES/0125-libndctl-papr-Add-support-for-reporting-shutdown-cou.patch
+161
file added
SOURCES/0126-libndctl-intel-Indicate-supported-smart-inject-types.patch
+180
file added
SOURCES/0127-libndctl-papr-Add-limited-support-for-inject-smart.patch
+41
file added
SOURCES/0128-ndtest-ack-shutdown-count-Skip-the-test-on-ndtest.patch
+218
file added
SOURCES/0129-ndctl-libndctl-Update-nvdimm-flags-after-smart-injec.patch
+202
file added
SOURCES/0132-libcxl-add-GET_PARTITION_INFO-mailbox-command-and-ac.patch
+118
file added
SOURCES/0133-libcxl-add-accessors-for-capacity-fields-of-the-IDEN.patch
+53
file added
SOURCES/0134-libcxl-return-the-partition-alignment-field-in-bytes.patch
+267
file added
SOURCES/0135-cxl-add-memdev-partition-information-to-cxl-list.patch
+154
file added
SOURCES/0136-libcxl-add-interfaces-for-SET_PARTITION_INFO-mailbox.patch
+400
file added
SOURCES/0137-cxl-add-command-cxl-set-partition.patch
+41
file added
SOURCES/0138-Update-ndctl.spec-to-allow-flatpak-builds.patch
+47
file added
SOURCES/0139-daxctl-provide-safe-versions-of-iteration-API.patch
+216
file added
SOURCES/0140-util-size.h-fix-build-for-older-compilers.patch
+49
file added
SOURCES/0141-build-Automate-rpmbuild.sh.patch
+48
file added
SOURCES/0142-util-size.h-Fix-build-error-for-GCC-10.patch
+47
file added
SOURCES/0143-libcxl-Remove-extraneous-NULL-checks-when-validating.patch
+35
file added
SOURCES/0144-libdaxctl-free-resource-allocated-with-asprintf.patch
+51
file added
SOURCES/0145-cxl-list-tidy-the-error-path-in-add_cxl_decoder.patch
+38
file added
SOURCES/0146-cxl-list-always-free-the-path-var-in-add_cxl_decoder.patch
+40
file added
SOURCES/0147-scripts-docsurgeon-Fix-document-header-for-section-1.patch
+156
file added
SOURCES/0148-ndctl-release-v73.patch
+49
file added
SOURCES/0150-build-Fix-Wall-and-O2-warnings.patch
+33
file added
SOURCES/0151-build-Fix-test-timeouts.patch
+68
file added
SOURCES/0155-build-Move-utility-helpers-to-libutil.a.patch
+60
file added
SOURCES/0156-util-Use-SZ_-size-macros-in-display-size.patch
+61
file added
SOURCES/0157-util-Pretty-print-terabytes.patch
+49
file added
SOURCES/0158-cxl-port-Fix-disable-port-man-page.patch
+384
file added
SOURCES/0159-cxl-bus-Add-bus-disable-support.patch
+37
file added
SOURCES/0160-cxl-list-Auto-enable-single-mode-for-port-listings.patch
+50
file added
SOURCES/0161-cxl-memdev-Fix-bus_invalidate-crash.patch
+73
file added
SOURCES/0162-cxl-list-Add-support-for-filtering-by-host-identifie.patch
+92
file added
SOURCES/0163-cxl-port-Relax-port-identifier-validation.patch
+236
file added
SOURCES/0165-cxl-test-Add-topology-enumeration-and-hotplug-test.patch
+32
file added
SOURCES/0167-daxctl-Fix-kernel-option-typo-in-Soft-Reservation-th.patch
+38
file added
SOURCES/0168-meson-make-modprobedatadir-an-option.patch
+116
file added
SOURCES/0169-namespace-action-Drop-more-zero-namespace-checks.patch
+94
file added
SOURCES/0170-ndctl-dimm-Flush-invalidated-labels-after-overwrite.patch
+45
file added
SOURCES/0171-libcxl-fix-a-segfault-when-memdev-pmem-is-absent.patch
+83
file added
SOURCES/0172-ndctl-bus-Handle-missing-scrub-commands-more-gracefu.patch
+58
file added
SOURCES/0173-util-wrapper.c-Fix-gcc-warning-in-xrealloc.patch
+31
file added
SOURCES/0174-libcxl-Fix-memory-leakage-in-cxl_port_init.patch
+47
file added
SOURCES/0175-cxl-list-Reformat-option-list.patch
+46
file added
SOURCES/0176-cxl-list-Emit-endpoint-decoders-filtered-by-memdev.patch
+59
file added
SOURCES/0177-cxl-list-Hide-0s-in-disabled-decoder-listings.patch
+167
file added
SOURCES/0178-cxl-list-Add-DPA-span-to-endpoint-decoder-listings.patch
+459
file added
SOURCES/0179-ccan-list-Import-latest-list-helpers.patch
+103
file added
SOURCES/0180-cxl-lib-Maintain-decoders-in-id-order.patch
+93
file added
SOURCES/0181-cxl-memdev-Fix-json-for-multi-device-partitioning.patch
+181
file added
SOURCES/0182-cxl-list-Emit-mode-for-endpoint-decoder-objects.patch
+56
file added
SOURCES/0183-cxl-set-partition-Accept-ram-as-an-alias-for-volatil.patch
+763
file added
SOURCES/0184-cxl-memdev-Add-reserve-free-dpa-commands.patch
+86
file added
SOURCES/0185-cxl-test-Update-CXL-memory-parameters.patch
+169
file added
SOURCES/0186-cxl-test-Checkout-region-setup-teardown.patch
+121
file added
SOURCES/0187-cxl-test-add-a-test-to-read-write-zero-labels.patch
+93
file added
SOURCES/0188-cxl-list-Clarify-B-vs-P-p-root.patch
+45
file added
SOURCES/0189-libcxl-add-a-depth-attribute-to-cxl_port.patch
+82
file added
SOURCES/0190-cxl-port-Consolidate-the-debug-option-in-cxl-port-ma.patch
+74
file added
SOURCES/0191-cxl-memdev-refactor-decoder-mode-string-parsing.patch
+651
file added
SOURCES/0192-libcxl-Introduce-libcxl-region-and-mapping-objects.patch
+548
file added
SOURCES/0193-cxl-cli-add-region-listing-support.patch
+644
file added
SOURCES/0194-libcxl-add-low-level-APIs-for-region-creation.patch
+829
file added
SOURCES/0195-cxl-add-a-create-region-command.patch
+459
file added
SOURCES/0196-cxl-add-commands-to-enable-disable-destroy-region.patch
+39
file added
SOURCES/0197-cxl-list-make-memdevs-and-regions-the-default-listin.patch
+173
file added
SOURCES/0198-test-add-a-cxl-create-region-test.patch
+240
file added
SOURCES/0199-cxl-decoder-add-a-max_available_extent-attribute.patch
+108
file added
SOURCES/0200-cxl-Add-list-verbose-option-to-the-cxl-command.patch
+57
file added
SOURCES/0201-cxl-test-Validate-endpoint-interleave-geometry.patch
+49
file added
SOURCES/0202-cxl-list-Add-interleave-parameters-to-decoder-listin.patch
+140
file added
SOURCES/0203-cxl-list-Add-region-to-decoder-listings.patch
+59
file added
SOURCES/0204-cxl-list-Filter-decoders-by-region.patch
+90
file added
SOURCES/0205-cxl-list-Add-depth-to-port-listings.patch
+63
file added
SOURCES/0206-cxl-test-Validate-switch-port-settings-in-cxl-region.patch
+34
file added
SOURCES/0207-meson-fix-modprobedatadir-default-value.patch
+49
file added
SOURCES/0208-ndctl-move-developer-scripts-from-contrib-to-scripts.patch
+31
file added
SOURCES/0209-ndctl-remove-obsolete-m4-directory.patch
+32
file added
SOURCES/0210-ndctl-update-.gitignore.patch
+30
file added
SOURCES/0211-scripts-fix-contrib-do_abidiff-for-updated-fedpkg.patch
+66
file added
SOURCES/0212-scripts-update-release-helper-scripts-for-meson-and-.patch
+48
file added
SOURCES/0213-meson.build-be-specific-for-library-path.patch
+39
file added
SOURCES/0214-cxl-region-fix-a-dereferecnce-after-NULL-check.patch
+50
file added
SOURCES/0215-libcxl-fox-a-resource-leak-and-a-forward-NULL-check.patch
+33
file added
SOURCES/0216-cxl-filter-Fix-an-uninitialized-pointer-dereference.patch
+133
file added
SOURCES/0217-ndctl-release-v74.patch
+273
file added
SOURCES/elake-diff-bafc29a0-df411ebe.patch
+332 -85
file changed
SPECS/ndctl.spec