Commit 303d3284 authored by Dave Jiang's avatar Dave Jiang
Browse files

Merge branch 'for-7.1/dax-hmem' into cxl-for-next

The series addresses conflicts between HMEM and CXL when handling Soft
Reserved memory ranges. CXL will try best effort in claiming the Soft
Reserved memory region that are CXL regions. If fails, it will punt
back to HMEM.

tools/testing/cxl: Test dax_hmem takeover of CXL regions
tools/testing/cxl: Simulate auto-assembly failure
dax/hmem: Parent dax_hmem devices
dax/hmem: Fix singleton confusion between dax_hmem_work and hmem devices
dax/hmem: Reduce visibility of dax_cxl coordination symbols
cxl/region: Constify cxl_region_resource_contains()
cxl/region: Limit visibility of cxl_region_contains_resource()
dax/cxl: Fix HMEM dependencies
cxl/region: Fix use-after-free from auto assembly failure
dax/hmem, cxl: Defer and resolve Soft Reserved ownership
cxl/region: Add helper to check Soft Reserved containment by CXL regions
dax: Track all dax_region allocations under a global resource tree
dax/cxl, hmem: Initialize hmem early and defer dax_cxl binding
dax/hmem: Gate Soft Reserved deferral on DEV_DAX_CXL
dax/hmem: Request cxl_acpi and cxl_pci before walking Soft Reserved ranges
dax/hmem: Factor HMEM registration into __hmem_register_device()
dax/bus: Use dax_region_put() in alloc_dax_region() error path
parents 7aacc625 549b5c12
Loading
Loading
Loading
Loading
+83 −1
Original line number Diff line number Diff line
@@ -1103,6 +1103,14 @@ static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr,

	if (!cxld->region) {
		cxld->region = cxlr;

		/*
		 * Now that cxld->region is set the intermediate staging state
		 * can be cleared.
		 */
		if (cxld == &cxled->cxld &&
		    cxled->state == CXL_DECODER_STATE_AUTO_STAGED)
			cxled->state = CXL_DECODER_STATE_AUTO;
		get_device(&cxlr->dev);
	}

@@ -1844,6 +1852,7 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr,
	pos = p->nr_targets;
	p->targets[pos] = cxled;
	cxled->pos = pos;
	cxled->state = CXL_DECODER_STATE_AUTO_STAGED;
	p->nr_targets++;

	return 0;
@@ -2193,6 +2202,47 @@ static int cxl_region_attach(struct cxl_region *cxlr,
	return 0;
}

static int cxl_region_by_target(struct device *dev, const void *data)
{
	const struct cxl_endpoint_decoder *cxled = data;
	struct cxl_region_params *p;
	struct cxl_region *cxlr;

	if (!is_cxl_region(dev))
		return 0;

	cxlr = to_cxl_region(dev);
	p = &cxlr->params;
	return p->targets[cxled->pos] == cxled;
}

/*
 * When an auto-region fails to assemble the decoder may be listed as a target,
 * but not fully attached.
 */
static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled)
{
	struct cxl_region_params *p;
	struct cxl_region *cxlr;
	int pos = cxled->pos;

	if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED)
		return;

	struct device *dev __free(put_device) =
		bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target);
	if (!dev)
		return;

	cxlr = to_cxl_region(dev);
	p = &cxlr->params;

	p->nr_targets--;
	cxled->state = CXL_DECODER_STATE_AUTO;
	cxled->pos = -1;
	p->targets[pos] = NULL;
}

static struct cxl_region *
__cxl_decoder_detach(struct cxl_region *cxlr,
		     struct cxl_endpoint_decoder *cxled, int pos,
@@ -2216,8 +2266,10 @@ __cxl_decoder_detach(struct cxl_region *cxlr,
		cxled = p->targets[pos];
	} else {
		cxlr = cxled->cxld.region;
		if (!cxlr)
		if (!cxlr) {
			cxl_cancel_auto_attach(cxled);
			return NULL;
		}
		p = &cxlr->params;
	}

@@ -4217,6 +4269,36 @@ static int cxl_region_setup_poison(struct cxl_region *cxlr)
	return devm_add_action_or_reset(dev, remove_debugfs, dentry);
}

static int region_contains_resource(struct device *dev, const void *data)
{
	const struct resource *res = data;
	struct cxl_region *cxlr;
	struct cxl_region_params *p;

	if (!is_cxl_region(dev))
		return 0;

	cxlr = to_cxl_region(dev);
	p = &cxlr->params;

	if (p->state != CXL_CONFIG_COMMIT)
		return 0;

	if (!p->res)
		return 0;

	return resource_contains(p->res, res) ? 1 : 0;
}

bool cxl_region_contains_resource(const struct resource *res)
{
	guard(rwsem_read)(&cxl_rwsem.region);
	struct device *dev __free(put_device) = bus_find_device(
		&cxl_bus_type, NULL, res, region_contains_resource);
	return !!dev;
}
EXPORT_SYMBOL_FOR_MODULES(cxl_region_contains_resource, "dax_hmem");

static int cxl_region_can_probe(struct cxl_region *cxlr)
{
	struct cxl_region_params *p = &cxlr->params;
+9 −2
Original line number Diff line number Diff line
@@ -287,12 +287,14 @@ struct cxl_decoder {
};

/*
 * Track whether this decoder is reserved for region autodiscovery, or
 * free for userspace provisioning.
 * Track whether this decoder is free for userspace provisioning, reserved for
 * region autodiscovery, whether it is started connecting (awaiting other
 * peers), or has completed auto assembly.
 */
enum cxl_decoder_state {
	CXL_DECODER_STATE_MANUAL,
	CXL_DECODER_STATE_AUTO,
	CXL_DECODER_STATE_AUTO_STAGED,
};

/**
@@ -843,6 +845,7 @@ struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
int cxl_add_to_region(struct cxl_endpoint_decoder *cxled);
struct cxl_dax_region *to_cxl_dax_region(struct device *dev);
u64 cxl_port_get_spa_cache_alias(struct cxl_port *endpoint, u64 spa);
bool cxl_region_contains_resource(const struct resource *res);
#else
static inline bool is_cxl_pmem_region(struct device *dev)
{
@@ -865,6 +868,10 @@ static inline u64 cxl_port_get_spa_cache_alias(struct cxl_port *endpoint,
{
	return 0;
}
static inline bool cxl_region_contains_resource(const struct resource *res)
{
	return false;
}
#endif

void cxl_endpoint_parse_cdat(struct cxl_port *port);
+4 −0
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ config DEV_DAX_HMEM
	depends on EFI_SOFT_RESERVE
	select NUMA_KEEP_MEMINFO if NUMA_MEMBLKS
	default DEV_DAX
	depends on CXL_ACPI || !CXL_ACPI
	depends on CXL_PCI || !CXL_PCI
	depends on CXL_BUS || !CXL_BUS
	help
	  EFI 2.8 platforms, and others, may advertise 'specific purpose'
	  memory. For example, a high bandwidth memory pool. The
@@ -48,6 +51,7 @@ config DEV_DAX_CXL
	tristate "CXL DAX: direct access to CXL RAM regions"
	depends on CXL_BUS && CXL_REGION && DEV_DAX
	default CXL_REGION && DEV_DAX
	depends on DEV_DAX_HMEM || !DEV_DAX_HMEM
	help
	  CXL RAM regions are either mapped by platform-firmware
	  and published in the initial system-memory map as "System RAM", mapped
+1 −2
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
obj-y += hmem/
obj-$(CONFIG_DAX) += dax.o
obj-$(CONFIG_DEV_DAX) += device_dax.o
obj-$(CONFIG_DEV_DAX_KMEM) += kmem.o
@@ -10,5 +11,3 @@ dax-y += bus.o
device_dax-y := device.o
dax_pmem-y := pmem.o
dax_cxl-y := cxl.o

obj-y += hmem/
+17 −3
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include "dax-private.h"
#include "bus.h"

static struct resource dax_regions = DEFINE_RES_MEM_NAMED(0, -1, "DAX Regions");
static DEFINE_MUTEX(dax_bus_lock);

/*
@@ -627,6 +628,7 @@ static void dax_region_unregister(void *region)

	sysfs_remove_groups(&dax_region->dev->kobj,
			dax_region_attribute_groups);
	release_resource(&dax_region->res);
	dax_region_put(dax_region);
}

@@ -635,6 +637,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
		unsigned long flags)
{
	struct dax_region *dax_region;
	int rc;

	/*
	 * The DAX core assumes that it can store its private data in
@@ -667,14 +670,25 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
		.flags = IORESOURCE_MEM | flags,
	};

	if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
		kfree(dax_region);
		return NULL;
	rc = request_resource(&dax_regions, &dax_region->res);
	if (rc) {
		dev_dbg(parent, "dax_region resource conflict for %pR\n",
			&dax_region->res);
		goto err_res;
	}

	if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups))
		goto err_sysfs;

	if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
		return NULL;
	return dax_region;

err_sysfs:
	release_resource(&dax_region->res);
err_res:
	dax_region_put(dax_region);
	return NULL;
}
EXPORT_SYMBOL_GPL(alloc_dax_region);

Loading