cxl/core/hdm: Add CXL standard decoder enumeration to the core

Unlike the decoder enumeration for "root decoders" described by platform
firmware, standard decoders can be enumerated from the component
registers space once the base address has been identified (via PCI,
ACPI, or another mechanism).

Add common infrastructure for HDM (Host-managed-Device-Memory) Decoder
enumeration and share it between host-bridge, upstream switch port, and
cxl_test defined decoders.

The locking model for switch level decoders is to hold the port lock
over the enumeration. This facilitates moving the dport and decoder
enumeration to a 'port' driver. For now, the only enumerator of decoder
resources is the cxl_acpi root driver.

Co-developed-by: Ben Widawsky <ben.widawsky@intel.com>
Signed-off-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/r/164374688404.395335.9239248252443123526.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Dan Williams
2022-02-01 12:24:30 -08:00
parent 98d2d3a264
commit d17d0540a0
12 changed files with 434 additions and 49 deletions

View File

@@ -168,10 +168,10 @@ static int add_host_bridge_uport(struct device *match, void *arg)
struct device *host = root_port->dev.parent;
struct acpi_device *bridge = to_cxl_host_bridge(host, match);
struct acpi_pci_root *pci_root;
int single_port_map[1], rc;
struct cxl_decoder *cxld;
struct cxl_dport *dport;
struct cxl_hdm *cxlhdm;
struct cxl_port *port;
int rc;
if (!bridge)
return 0;
@@ -200,37 +200,24 @@ static int add_host_bridge_uport(struct device *match, void *arg)
rc = devm_cxl_port_enumerate_dports(host, port);
if (rc < 0)
return rc;
if (rc > 1)
return 0;
/* TODO: Scan CHBCR for HDM Decoder resources */
/*
* Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability
* Structure) single ported host-bridges need not publish a decoder
* capability when a passthrough decode can be assumed, i.e. all
* transactions that the uport sees are claimed and passed to the single
* dport. Disable the range until the first CXL region is enumerated /
* activated.
*/
cxld = cxl_switch_decoder_alloc(port, 1);
if (IS_ERR(cxld))
return PTR_ERR(cxld);
cxl_device_lock(&port->dev);
dport = list_first_entry(&port->dports, typeof(*dport), list);
cxl_device_unlock(&port->dev);
if (rc == 1) {
rc = devm_cxl_add_passthrough_decoder(host, port);
goto out;
}
single_port_map[0] = dport->port_id;
cxlhdm = devm_cxl_setup_hdm(host, port);
if (IS_ERR(cxlhdm)) {
rc = PTR_ERR(cxlhdm);
goto out;
}
rc = cxl_decoder_add(cxld, single_port_map);
rc = devm_cxl_enumerate_decoders(host, cxlhdm);
if (rc)
put_device(&cxld->dev);
else
rc = cxl_decoder_autoremove(host, cxld);
dev_err(&port->dev, "Couldn't enumerate decoders (%d)\n", rc);
if (rc == 0)
dev_dbg(host, "add: %s\n", dev_name(&cxld->dev));
out:
cxl_device_unlock(&port->dev);
return rc;
}