Message ID | 168592159835.1948938.1647215579839222774.stgit@dwillia2-xfh.jf.intel.com |
---|---|
State | New, archived |
Headers | show |
Series | cxl: Device memory setup | expand |
On Sun, 04 Jun 2023 16:33:18 -0700 Dan Williams <dan.j.williams@intel.com> wrote: > Scenarios like recreating persistent memory regions from label data and > establishing new regions for CXL attached accelerators with local memory > need a kernel internal facility to establish new regions. Could probably make the label data one a userspace problem, but I agree that it 'might' be done entirely in kernel. > > Introduce cxl_create_region() that takes an array of endpoint decoders > with reserved capacity and a root decoder object to establish a new > region. > > Signed-off-by: Dan Williams <dan.j.williams@intel.com> > --- > drivers/cxl/core/region.c | 107 +++++++++++++++++++++++++++++++++++++++++++++ > drivers/cxl/cxlmem.h | 3 + > 2 files changed, 110 insertions(+) > > diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c > index a41756249f8d..543c4499379e 100644 > --- a/drivers/cxl/core/region.c > +++ b/drivers/cxl/core/region.c > @@ -2878,6 +2878,104 @@ construct_region_begin(struct cxl_root_decoder *cxlrd, > return cxlr; > } > > +static struct cxl_region * > +__construct_new_region(struct cxl_root_decoder *cxlrd, > + struct cxl_endpoint_decoder **cxled, int ways) > +{ > + struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; > + struct cxl_region_params *p; > + resource_size_t size = 0; > + struct cxl_region *cxlr; > + int rc, i; > + > + if (ways < 1) > + return ERR_PTR(-EINVAL); > + > + cxlr = construct_region_begin(cxlrd, cxled[0]); > + if (IS_ERR(cxlr)) > + return cxlr; > + > + rc = set_interleave_ways(cxlr, ways); > + if (rc) > + goto out; > + > + rc = set_interleave_granularity(cxlr, cxld->interleave_granularity); > + if (rc) > + goto out; > + > + down_read(&cxl_dpa_rwsem); > + for (i = 0; i < ways; i++) { > + if (!cxled[i]->dpa_res) > + break; > + size += resource_size(cxled[i]->dpa_res); > + } > + up_read(&cxl_dpa_rwsem); > + > + if (i < ways) > + goto out; > + > + rc = alloc_hpa(cxlr, size); > + if (rc) > + goto out; > + > + down_read(&cxl_dpa_rwsem); > + for (i = 0; i < ways; i++) { > + rc = cxl_region_attach(cxlr, cxled[i], i); > + if (rc) > + break; > + } > + up_read(&cxl_dpa_rwsem); > + > + if (rc) > + goto out; > + > + rc = cxl_region_decode_commit(cxlr); > + if (rc) > + goto out; > + > + p = &cxlr->params; > + p->state = CXL_CONFIG_COMMIT; > +out: > + construct_region_end(); > + if (rc) { > + drop_region(cxlr); > + return ERR_PTR(rc); > + } > + return cxlr; > +} > + > /* Establish an empty region covering the given HPA range */ > static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, > struct cxl_endpoint_decoder *cxled) > @@ -3085,6 +3183,15 @@ static int cxl_region_probe(struct device *dev) > p->res->start, p->res->end, cxlr, > is_system_ram) > 0) > return 0; > + > + /* > + * HDM-D[B] (device-memory) regions have accelerator > + * specific usage, skip device-dax registration. > + */ As before - I'm not yet convinced that is always the case for HDM-DB Particularly given you support interleaving which may never make sense for accelerators. > + if (cxlr->type == CXL_DECODER_DEVMEM) > + return 0; > + > + /* HDM-H routes to device-dax */ > return devm_cxl_add_dax_region(cxlr);
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index a41756249f8d..543c4499379e 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2878,6 +2878,104 @@ construct_region_begin(struct cxl_root_decoder *cxlrd, return cxlr; } +static struct cxl_region * +__construct_new_region(struct cxl_root_decoder *cxlrd, + struct cxl_endpoint_decoder **cxled, int ways) +{ + struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; + struct cxl_region_params *p; + resource_size_t size = 0; + struct cxl_region *cxlr; + int rc, i; + + if (ways < 1) + return ERR_PTR(-EINVAL); + + cxlr = construct_region_begin(cxlrd, cxled[0]); + if (IS_ERR(cxlr)) + return cxlr; + + rc = set_interleave_ways(cxlr, ways); + if (rc) + goto out; + + rc = set_interleave_granularity(cxlr, cxld->interleave_granularity); + if (rc) + goto out; + + down_read(&cxl_dpa_rwsem); + for (i = 0; i < ways; i++) { + if (!cxled[i]->dpa_res) + break; + size += resource_size(cxled[i]->dpa_res); + } + up_read(&cxl_dpa_rwsem); + + if (i < ways) + goto out; + + rc = alloc_hpa(cxlr, size); + if (rc) + goto out; + + down_read(&cxl_dpa_rwsem); + for (i = 0; i < ways; i++) { + rc = cxl_region_attach(cxlr, cxled[i], i); + if (rc) + break; + } + up_read(&cxl_dpa_rwsem); + + if (rc) + goto out; + + rc = cxl_region_decode_commit(cxlr); + if (rc) + goto out; + + p = &cxlr->params; + p->state = CXL_CONFIG_COMMIT; +out: + construct_region_end(); + if (rc) { + drop_region(cxlr); + return ERR_PTR(rc); + } + return cxlr; +} + +/** + * cxl_create_region - Establish a region given an array of endpoint decoders + * @cxlrd: root decoder to allocate HPA + * @cxled: array of endpoint decoders with reserved DPA capacity + * @ways: size of @cxled array + * + * Returns a fully formed region in the commit state and attached to the + * cxl_region driver. + */ +struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd, + struct cxl_endpoint_decoder **cxled, + int ways) +{ + struct cxl_region *cxlr; + + mutex_lock(&cxlrd->range_lock); + cxlr = __construct_new_region(cxlrd, cxled, ways); + mutex_unlock(&cxlrd->range_lock); + + if (IS_ERR(cxlr)) + return cxlr; + + if (device_attach(&cxlr->dev) <= 0) { + dev_err(&cxlr->dev, "failed to create region\n"); + drop_region(cxlr); + return ERR_PTR(-ENODEV); + } + + return cxlr; +} +EXPORT_SYMBOL_NS_GPL(cxl_create_region, CXL); + /* Establish an empty region covering the given HPA range */ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, struct cxl_endpoint_decoder *cxled) @@ -3085,6 +3183,15 @@ static int cxl_region_probe(struct device *dev) p->res->start, p->res->end, cxlr, is_system_ram) > 0) return 0; + + /* + * HDM-D[B] (device-memory) regions have accelerator + * specific usage, skip device-dax registration. + */ + if (cxlr->type == CXL_DECODER_DEVMEM) + return 0; + + /* HDM-H routes to device-dax */ return devm_cxl_add_dax_region(cxlr); default: dev_dbg(&cxlr->dev, "unsupported region mode: %d\n", diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 69f07186502d..ad7f806549d3 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -98,6 +98,9 @@ struct cxl_root_decoder *cxl_hpa_freespace(struct cxl_port *endpoint, int interleave_ways, unsigned long flags, resource_size_t *max); +struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd, + struct cxl_endpoint_decoder **cxled, + int ways); static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port, struct cxl_memdev *cxlmd)
Scenarios like recreating persistent memory regions from label data and establishing new regions for CXL attached accelerators with local memory need a kernel internal facility to establish new regions. Introduce cxl_create_region() that takes an array of endpoint decoders with reserved capacity and a root decoder object to establish a new region. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- drivers/cxl/core/region.c | 107 +++++++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 3 + 2 files changed, 110 insertions(+)