drivers/cxl/core/atl.c

Source file repositories/reference/linux-study-clean/drivers/cxl/core/atl.c

File Facts

System
Linux kernel
Corpus path
drivers/cxl/core/atl.c
Extension
.c
Size
6160 bytes
Lines
212
Domain
Driver Families
Bucket
drivers/cxl
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct prm_cxl_dpa_spa_data {
	u64 dpa;
	u8 reserved;
	u8 devfn;
	u8 bus;
	u8 segment;
	u64 *spa;
} __packed;

static u64 prm_cxl_dpa_spa(struct pci_dev *pci_dev, u64 dpa)
{
	struct prm_cxl_dpa_spa_data data;
	u64 spa;
	int rc;

	data = (struct prm_cxl_dpa_spa_data) {
		.dpa     = dpa,
		.devfn   = pci_dev->devfn,
		.bus     = pci_dev->bus->number,
		.segment = pci_domain_nr(pci_dev->bus),
		.spa     = &spa,
	};

	rc = acpi_call_prm_handler(prm_cxl_dpa_spa_guid, &data);
	if (rc) {
		pci_dbg(pci_dev, "failed to get SPA for %#llx: %d\n", dpa, rc);
		return ULLONG_MAX;
	}

	pci_dbg(pci_dev, "PRM address translation: DPA -> SPA: %#llx -> %#llx\n", dpa, spa);

	return spa;
}

static int cxl_prm_setup_root(struct cxl_root *cxl_root, void *data)
{
	struct cxl_region_context *ctx = data;
	struct cxl_endpoint_decoder *cxled = ctx->cxled;
	struct cxl_decoder *cxld = &cxled->cxld;
	struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
	struct range hpa_range = ctx->hpa_range;
	struct pci_dev *pci_dev;
	u64 spa_len, len;
	u64 addr, base_spa, base;
	int ways, gran;

	/*
	 * When Normalized Addressing is enabled, the endpoint maintains a 1:1
	 * mapping between HPA and DPA. If disabled, skip address translation
	 * and perform only a range check.
	 */
	if (hpa_range.start != cxled->dpa_res->start)
		return 0;

	/*
	 * Endpoints are programmed passthrough in Normalized Addressing mode.
	 */
	if (ctx->interleave_ways != 1) {
		dev_dbg(&cxld->dev, "unexpected interleaving config: ways: %d granularity: %d\n",
			ctx->interleave_ways, ctx->interleave_granularity);
		return -ENXIO;
	}

	if (!cxlmd || !dev_is_pci(cxlmd->dev.parent)) {
		dev_dbg(&cxld->dev, "No endpoint found: %s, range %#llx-%#llx\n",
			dev_name(cxld->dev.parent), hpa_range.start,
			hpa_range.end);
		return -ENXIO;
	}

	pci_dev = to_pci_dev(cxlmd->dev.parent);

	/* Translate HPA range to SPA. */
	base = hpa_range.start;
	hpa_range.start = prm_cxl_dpa_spa(pci_dev, hpa_range.start);
	hpa_range.end = prm_cxl_dpa_spa(pci_dev, hpa_range.end);
	base_spa = hpa_range.start;

	if (hpa_range.start == ULLONG_MAX || hpa_range.end == ULLONG_MAX) {
		dev_dbg(cxld->dev.parent,
			"CXL address translation: Failed to translate HPA range: %#llx-%#llx:%#llx-%#llx(%s)\n",
			hpa_range.start, hpa_range.end, ctx->hpa_range.start,
			ctx->hpa_range.end, dev_name(&cxld->dev));
		return -ENXIO;
	}

	/*
	 * Since translated addresses include the interleaving offsets, align
	 * the range to 256 MB.
	 */

Annotation

Implementation Notes