[PATCH v3 6/9] cxl/region: Enforce coarse-to-fine ordering for mixed-granularity regions
Alison Schofield <[email protected]> Thu, 30 Jul 2026 15:20:26 -0700
| Newsgroups | org.kernel.vger.linux-cxl |
|---|---|
| Message-ID | <c0c02a889a3e53d0daa5e69ad92cc6a3e88f1732.1785444498.git.alison.schofield@intel.com> |
With mixed granularity allowed, selector disjointness alone would accept an arrangement where an interleaving level is coarser than one above it. The position arithmetic cannot represent such a layout: it assumes each level below the root refines the one above. In a mixed-granularity region require each interleaving level to be strictly finer than its nearest interleaving ancestor, and reject a violation with -ENXIO in check_gran_ordering(), called from cxl_port_setup_targets(). The value validated is the derived granularity on the user path and the firmware-programmed granularity on the auto path. Same-granularity regions are exempt; their levels legitimately coarsen away from the root. Signed-off-by: Alison Schofield <[email protected]> --- drivers/cxl/core/region.c | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 3919f64e2467..b4e8ebe158f7 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1680,6 +1680,50 @@ static int derive_port_granularity(struct cxl_port *port, return 0; } +/** + * check_gran_ordering() - Check mixed-granularity decoder ordering + * @port: port being configured + * @cxlr: region under construction + * @cxld: port decoder + * @accum: selectors used by the ancestor decoders + * @iw: port decoder interleave ways + * @ig: derived port decoder granularity + * + * The mixed-granularity position calculation requires each interleaving + * decoder below the root to use a smaller granularity than its nearest + * interleaving ancestor. Passthrough decoders do not participate. + * + * Auto regions validate the firmware-programmed granularity. User-created + * regions validate @ig. + * + * Return: 0 on success, -ENXIO on invalid ordering. + */ +static int check_gran_ordering(struct cxl_port *port, struct cxl_region *cxlr, + struct cxl_decoder *cxld, u64 accum, int iw, + int ig) +{ + struct cxl_root_decoder *cxlrd = cxlr->cxlrd; + u64 val, ancestor_gran; + + if (!cxl_region_is_mixed_gran(cxlr) || iw <= 1) + return 0; + + val = test_bit(CXL_REGION_F_AUTO, &cxlr->flags) ? + cxld->interleave_granularity : ig; + ancestor_gran = accum ? (1ULL << __ffs64(accum)) : + cxlrd->cxlsd.cxld.interleave_granularity; + + if (val >= ancestor_gran) { + dev_dbg(&cxlr->dev, + "%s:%s: iw %d ig %llu not finer than nearest interleaving ancestor (ig %llu); coarse-to-fine ordering required\n", + dev_name(port->uport_dev), dev_name(&port->dev), + iw, val, ancestor_gran); + return -ENXIO; + } + + return 0; +} + /** * cxl_port_setup_targets() - Validate and program a port decoder * @port: port being configured @@ -1762,6 +1806,10 @@ static int cxl_port_setup_targets(struct cxl_port *port, return rc; } + rc = check_gran_ordering(port, cxlr, cxld, accum, iw, ig); + if (rc) + return rc; + if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) { if (iw > 1 && cxld->interleave_granularity != ig) { dev_dbg(&cxlr->dev, -- 2.37.3