Re: [PATCH v8 15/27] cxl: define a driver interface for HPA free space enumeration
From: Alejandro Lucero Palau <hidden>
Date: 2024-12-27 10:05:51
Also in:
linux-cxl
On 12/24/24 17:42, Jonathan Cameron wrote:
On Mon, 16 Dec 2024 16:10:30 +0000 [off-list ref] wrote:quoted
From: Alejandro Lucero <redacted> CXL region creation involves allocating capacity from device DPA (device-physical-address space) and assigning it to decode a given HPA (host-physical-address space). Before determining how much DPA to allocate the amount of available HPA must be determined. Also, not all HPA is create equal, some specifically targets RAM, some target PMEM,is created equal
Yes. I'll fix it
quoted
some is prepared for device-memory flows like HDM-D and HDM-DB, and some is host-only (HDM-H). Wrap all of those concerns into an API that retrieves a root decoder (platform CXL window) that fits the specified constraints and the capacity available for a new region. Based on https://lore.kernel.org/linux-cxl/168592159290.1948938.13522227102445462976.stgit@dwillia2-xfh.jf.intel.com/ (local) Signed-off-by: Alejandro Lucero <redacted> Co-developed-by: Dan Williams <redacted>A few minor things inline. I think you also definitely need a SoB from Dan given the Co-dev.
Right. I hope Dan takes a look to the patches, and I'll be happy to include that.
quoted
--- drivers/cxl/core/region.c | 154 ++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 3 + include/cxl/cxl.h | 8 ++ 3 files changed, 165 insertions(+)diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 967132b49832..eb2ae276b01a 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c@@ -687,6 +687,160 @@ static int free_hpa(struct cxl_region *cxlr) return 0; } +struct cxlrd_max_context { + struct device *host_bridge; + unsigned long flags; + resource_size_t max_hpa; + struct cxl_root_decoder *cxlrd; +}; + +static int find_max_hpa(struct device *dev, void *data) +{ + struct cxlrd_max_context *ctx = data; + struct cxl_switch_decoder *cxlsd; + struct cxl_root_decoder *cxlrd; + struct resource *res, *prev; + struct cxl_decoder *cxld; + resource_size_t max; + + if (!is_root_decoder(dev)) + return 0; + + cxlrd = to_cxl_root_decoder(dev); + cxlsd = &cxlrd->cxlsd; + cxld = &cxlsd->cxld; + if ((cxld->flags & ctx->flags) != ctx->flags) { + dev_dbg(dev, "%s, flags not matching: %08lx vs %08lx\n", + __func__, cxld->flags, ctx->flags); + return 0; + } + + /* + * The CXL specs do not forbid an accelerator being part of an + * interleaved HPA range, but it is unlikely and because it helps + * simplifying the code, we assume this being the case by now.because it simplifies the code, don't allow it.
Simpler. I'll change it.
quoted
+ */ + if (cxld->interleave_ways != 1) { + dev_dbg(dev, "%s, interleave_ways not matching\n", __func__);Dynamic debug does all sorts of magic with printing, so don't add __func__ in any of these.
Yes. Fixing it.
quoted
+ return 0; + } + + guard(rwsem_read)(&cxl_region_rwsem); + if (ctx->host_bridge != cxlsd->target[0]->dport_dev) { + dev_dbg(dev, "%s, host bridge does not match\n", __func__); + return 0; + } + + /* + * Walk the root decoder resource range relying on cxl_region_rwsem to + * preclude sibling arrival/departure and find the largest free space + * gap. + */ + lockdep_assert_held_read(&cxl_region_rwsem); + max = 0; + res = cxlrd->res->child; + if (!res)Add a comment here. Not locally obvious why we'd only look at parent size whilst check if the child exists.
I'll do. Thanks
quoted
+ max = resource_size(cxlrd->res); + else + max = 0; + + for (prev = NULL; res; prev = res, res = res->sibling) { + struct resource *next = res->sibling; + resource_size_t free = 0; + + /* + * Sanity check for preventing arithmetic problems below as a + * resource with size 0 could imply using the end field below + * when set to unsigned zero - 1 or all f in hex. + */ + if (prev && !resource_size(prev)) + continue; + + if (!prev && res->start > cxlrd->res->start) { + free = res->start - cxlrd->res->start; + max = max(free, max); + } + if (prev && res->start > prev->end + 1) { + free = res->start - prev->end + 1; + max = max(free, max); + } + if (next && res->end + 1 < next->start) { + free = next->start - res->end + 1; + max = max(free, max); + } + if (!next && res->end + 1 < cxlrd->res->end + 1) { + free = cxlrd->res->end + 1 - res->end + 1; + max = max(free, max); + } + } + + dev_dbg(CXLRD_DEV(cxlrd), "%s, found %pa bytes of free space\n", + __func__, &max); + if (max > ctx->max_hpa) { + if (ctx->cxlrd) + put_device(CXLRD_DEV(ctx->cxlrd)); + get_device(CXLRD_DEV(cxlrd)); + ctx->cxlrd = cxlrd; + ctx->max_hpa = max; + dev_dbg(CXLRD_DEV(cxlrd), "%s, found %pa bytes of free space\n", + __func__, &max); + } + return 0; +}