Commit 0f157c7f authored by Dan Williams's avatar Dan Williams
Browse files

cxl/core: Define a 'struct cxl_root_decoder'



Previously the target routing specifics of switch decoders were factored
out of 'struct cxl_decoder' into 'struct cxl_switch_decoder'.

This patch, 2 of 3, adds a 'struct cxl_root_decoder' as a superset of a
switch decoder that also track the associated CXL window platform
resource.

Note that the reason the resource for a given root decoder needs to be
looked up after the fact (i.e. after cxl_parse_cfmws() and
add_cxl_resource()) is because add_cxl_resource() may have merged CXL
windows in order to keep them at the top of the resource tree / decode
hierarchy.

Co-developed-by: default avatarBen Widawsky <bwidawsk@kernel.org>
Signed-off-by: default avatarBen Widawsky <bwidawsk@kernel.org>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/r/165784326541.1758207.9915663937394448341.stgit@dwillia2-xfh.jf.intel.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 974854ab
Loading
Loading
Loading
Loading
+36 −4
Original line number Original line Diff line number Diff line
@@ -84,7 +84,7 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
	struct cxl_cfmws_context *ctx = arg;
	struct cxl_cfmws_context *ctx = arg;
	struct cxl_port *root_port = ctx->root_port;
	struct cxl_port *root_port = ctx->root_port;
	struct resource *cxl_res = ctx->cxl_res;
	struct resource *cxl_res = ctx->cxl_res;
	struct cxl_switch_decoder *cxlsd;
	struct cxl_root_decoder *cxlrd;
	struct device *dev = ctx->dev;
	struct device *dev = ctx->dev;
	struct acpi_cedt_cfmws *cfmws;
	struct acpi_cedt_cfmws *cfmws;
	struct cxl_decoder *cxld;
	struct cxl_decoder *cxld;
@@ -128,11 +128,11 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
	if (rc)
	if (rc)
		goto err_insert;
		goto err_insert;


	cxlsd = cxl_root_decoder_alloc(root_port, ways);
	cxlrd = cxl_root_decoder_alloc(root_port, ways);
	if (IS_ERR(cxld))
	if (IS_ERR(cxlrd))
		return 0;
		return 0;


	cxld = &cxlsd->cxld;
	cxld = &cxlrd->cxlsd.cxld;
	cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
	cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
	cxld->target_type = CXL_DECODER_EXPANDER;
	cxld->target_type = CXL_DECODER_EXPANDER;
	cxld->hpa_range = (struct range) {
	cxld->hpa_range = (struct range) {
@@ -409,6 +409,32 @@ static int add_cxl_resources(struct resource *cxl_res)
	return 0;
	return 0;
}
}


static int pair_cxl_resource(struct device *dev, void *data)
{
	struct resource *cxl_res = data;
	struct resource *p;

	if (!is_root_decoder(dev))
		return 0;

	for (p = cxl_res->child; p; p = p->sibling) {
		struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
		struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
		struct resource res = {
			.start = cxld->hpa_range.start,
			.end = cxld->hpa_range.end,
			.flags = IORESOURCE_MEM,
		};

		if (resource_contains(p, &res)) {
			cxlrd->res = cxl_get_public_resource(p);
			break;
		}
	}

	return 0;
}

static int cxl_acpi_probe(struct platform_device *pdev)
static int cxl_acpi_probe(struct platform_device *pdev)
{
{
	int rc;
	int rc;
@@ -459,6 +485,12 @@ static int cxl_acpi_probe(struct platform_device *pdev)
	if (rc)
	if (rc)
		return rc;
		return rc;


	/*
	 * Populate the root decoders with their related iomem resource,
	 * if present
	 */
	device_for_each_child(&root_port->dev, cxl_res, pair_cxl_resource);

	/*
	/*
	 * Root level scanned with host-bridge as dports, now scan host-bridges
	 * Root level scanned with host-bridge as dports, now scan host-bridges
	 * for their role as CXL uports to their CXL-capable PCIe Root Ports.
	 * for their role as CXL uports to their CXL-capable PCIe Root Ports.
+27 −7
Original line number Original line Diff line number Diff line
@@ -260,6 +260,23 @@ static void cxl_switch_decoder_release(struct device *dev)
	kfree(cxlsd);
	kfree(cxlsd);
}
}


struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev)
{
	if (dev_WARN_ONCE(dev, !is_root_decoder(dev),
			  "not a cxl_root_decoder device\n"))
		return NULL;
	return container_of(dev, struct cxl_root_decoder, cxlsd.cxld.dev);
}
EXPORT_SYMBOL_NS_GPL(to_cxl_root_decoder, CXL);

static void cxl_root_decoder_release(struct device *dev)
{
	struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);

	__cxl_decoder_release(&cxlrd->cxlsd.cxld);
	kfree(cxlrd);
}

static const struct device_type cxl_decoder_endpoint_type = {
static const struct device_type cxl_decoder_endpoint_type = {
	.name = "cxl_decoder_endpoint",
	.name = "cxl_decoder_endpoint",
	.release = cxl_decoder_release,
	.release = cxl_decoder_release,
@@ -274,7 +291,7 @@ static const struct device_type cxl_decoder_switch_type = {


static const struct device_type cxl_decoder_root_type = {
static const struct device_type cxl_decoder_root_type = {
	.name = "cxl_decoder_root",
	.name = "cxl_decoder_root",
	.release = cxl_switch_decoder_release,
	.release = cxl_root_decoder_release,
	.groups = cxl_decoder_root_attribute_groups,
	.groups = cxl_decoder_root_attribute_groups,
};
};


@@ -1271,9 +1288,10 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
 * firmware description of CXL resources into a CXL standard decode
 * firmware description of CXL resources into a CXL standard decode
 * topology.
 * topology.
 */
 */
struct cxl_switch_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
						unsigned int nr_targets)
						unsigned int nr_targets)
{
{
	struct cxl_root_decoder *cxlrd;
	struct cxl_switch_decoder *cxlsd;
	struct cxl_switch_decoder *cxlsd;
	struct cxl_decoder *cxld;
	struct cxl_decoder *cxld;
	int rc;
	int rc;
@@ -1281,19 +1299,21 @@ struct cxl_switch_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
	if (!is_cxl_root(port))
	if (!is_cxl_root(port))
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);


	cxlsd = kzalloc(struct_size(cxlsd, target, nr_targets), GFP_KERNEL);
	cxlrd = kzalloc(struct_size(cxlrd, cxlsd.target, nr_targets),
	if (!cxlsd)
			GFP_KERNEL);
	if (!cxlrd)
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);


	cxlsd = &cxlrd->cxlsd;
	rc = cxl_switch_decoder_init(port, cxlsd, nr_targets);
	rc = cxl_switch_decoder_init(port, cxlsd, nr_targets);
	if (rc) {
	if (rc) {
		kfree(cxlsd);
		kfree(cxlrd);
		return ERR_PTR(rc);
		return ERR_PTR(rc);
	}
	}


	cxld = &cxlsd->cxld;
	cxld = &cxlsd->cxld;
	cxld->dev.type = &cxl_decoder_root_type;
	cxld->dev.type = &cxl_decoder_root_type;
	return cxlsd;
	return cxlrd;
}
}
EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL);
EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL);


+13 −2
Original line number Original line Diff line number Diff line
@@ -260,6 +260,16 @@ struct cxl_switch_decoder {
};
};




/**
 * struct cxl_root_decoder - Static platform CXL address decoder
 * @res: host / parent resource for region allocations
 * @cxlsd: base cxl switch decoder
 */
struct cxl_root_decoder {
	struct resource *res;
	struct cxl_switch_decoder cxlsd;
};

/**
/**
 * enum cxl_nvdimm_brige_state - state machine for managing bus rescans
 * enum cxl_nvdimm_brige_state - state machine for managing bus rescans
 * @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed
 * @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed
@@ -383,9 +393,10 @@ struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
					const struct device *dev);
					const struct device *dev);


struct cxl_decoder *to_cxl_decoder(struct device *dev);
struct cxl_decoder *to_cxl_decoder(struct device *dev);
struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev);
bool is_root_decoder(struct device *dev);
bool is_root_decoder(struct device *dev);
bool is_endpoint_decoder(struct device *dev);
bool is_endpoint_decoder(struct device *dev);
struct cxl_switch_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
						unsigned int nr_targets);
						unsigned int nr_targets);
struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
						    unsigned int nr_targets);
						    unsigned int nr_targets);