// SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ #include <linux/device.h> #include <linux/module.h> #include <linux/slab.h>
#include"cxlmem.h" #include"cxlpci.h"
/** * DOC: cxl port * * The port driver enumerates dport via PCI and scans for HDM * (Host-managed-Device-Memory) decoder resources via the * @component_reg_phys value passed in by the agent that registered the * port. All descendant ports of a CXL root port (described by platform * firmware) are managed in this drivers context. Each driver instance * is responsible for tearing down the driver context of immediate * descendant ports. The locking for this is validated by * CONFIG_PROVE_CXL_LOCKING. * * The primary service this driver provides is presenting APIs to other * drivers to utilize the decoders, and indicating to userspace (via bind * status) the connectivity of the CXL.mem protocol throughout the * PCIe topology.
*/
if (cxled->state != CXL_DECODER_STATE_AUTO) return 0;
/* * Region enumeration is opportunistic, if this add-event fails, * continue to the next endpoint decoder.
*/
rc = cxl_add_to_region(cxled); if (rc)
dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
return 0;
}
staticint cxl_switch_port_probe(struct cxl_port *port)
{ struct cxl_hdm *cxlhdm; int rc;
/* Cache the data early to ensure is_visible() works */
read_cdat_data(port);
rc = devm_cxl_port_enumerate_dports(port); if (rc < 0) return rc;
cxl_switch_parse_cdat(port);
cxlhdm = devm_cxl_setup_hdm(port, NULL); if (!IS_ERR(cxlhdm)) return devm_cxl_enumerate_decoders(cxlhdm, NULL);
if (PTR_ERR(cxlhdm) != -ENODEV) {
dev_err(&port->dev, "Failed to map HDM decoder capability\n"); return PTR_ERR(cxlhdm);
}
if (rc == 1) {
dev_dbg(&port->dev, "Fallback to passthrough decoder\n"); return devm_cxl_add_passthrough_decoder(port);
}
dev_err(&port->dev, "HDM decoder capability not found\n"); return -ENXIO;
}
staticint cxl_endpoint_port_probe(struct cxl_port *port)
{ struct cxl_endpoint_dvsec_info info = { .port = port }; struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); struct cxl_dev_state *cxlds = cxlmd->cxlds; struct cxl_hdm *cxlhdm; int rc;
rc = cxl_dvsec_rr_decode(cxlds, &info); if (rc < 0) return rc;
cxlhdm = devm_cxl_setup_hdm(port, &info); if (IS_ERR(cxlhdm)) { if (PTR_ERR(cxlhdm) == -ENODEV)
dev_err(&port->dev, "HDM decoder registers not found\n"); return PTR_ERR(cxlhdm);
}
/* Cache the data early to ensure is_visible() works */
read_cdat_data(port);
cxl_endpoint_parse_cdat(port);
get_device(&cxlmd->dev);
rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd); if (rc) return rc;
rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info); if (rc) return rc;
rc = devm_cxl_enumerate_decoders(cxlhdm, &info); if (rc) return rc;
/* * Now that all endpoint decoders are successfully enumerated, try to * assemble regions from committed decoders
*/
device_for_each_child(&port->dev, NULL, discover_region);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.