Message ID | 20240715172835.24757-9-alejandro.lucero-palau@amd.com (mailing list archive) |
---|---|
State | Not Applicable |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | cxl: add Type2 device support | expand |
On 7/16/2024 1:28 AM, alejandro.lucero-palau@amd.com wrote: > From: Alejandro Lucero <alucerop@amd.com> > > The first stop for a CXL accelerator driver that wants to establish new > CXL.mem regions is to register a 'struct cxl_memdev. That kicks off > cxl_mem_probe() to enumerate all 'struct cxl_port' instances in the > topology up to the root. > > If the root driver has not attached yet the expectation is that the > driver waits until that link is established. The common cxl_pci_driver > has reason to keep the 'struct cxl_memdev' device attached to the bus > until the root driver attaches. An accelerator may want to instead defer > probing until CXL resources can be acquired. > > Use the @endpoint attribute of a 'struct cxl_memdev' to convey when > accelerator driver probing should be defferred vs failed. Provide that > indication via a new cxl_acquire_endpoint() API that can retrieve the > probe status of the memdev. > > The first consumer of this API is a test driver that excercises the CXL > Type-2 flow. > > Based on https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 > > Signed-off-by: Alejandro Lucero <alucerop@amd.com> > Co-developed-by: Dan Williams <dan.j.williams@intel.com> > --- > drivers/cxl/core/memdev.c | 41 ++++++++++++++++++++++++++++++ > drivers/cxl/core/port.c | 2 +- > drivers/cxl/mem.c | 7 +++-- > drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- > include/linux/cxl_accel_mem.h | 3 +++ > 5 files changed, 59 insertions(+), 4 deletions(-) > > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c > index b902948b121f..d51c8bfb32e3 100644 > --- a/drivers/cxl/core/memdev.c > +++ b/drivers/cxl/core/memdev.c > @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host, > } > EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); > > +/* > + * Try to get a locked reference on a memdev's CXL port topology > + * connection. Be careful to observe when cxl_mem_probe() has deposited > + * a probe deferral awaiting the arrival of the CXL root driver > +*/ > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) > +{ > + struct cxl_port *endpoint; > + int rc = -ENXIO; > + > + device_lock(&cxlmd->dev); > + endpoint = cxlmd->endpoint; > + if (!endpoint) > + goto err; > + > + if (IS_ERR(endpoint)) { > + rc = PTR_ERR(endpoint); > + goto err; > + } > + > + device_lock(&endpoint->dev); > + if (!endpoint->dev.driver) > + goto err_endpoint; > + > + return endpoint; > + > +err_endpoint: > + device_unlock(&endpoint->dev); > +err: > + device_unlock(&cxlmd->dev); > + return ERR_PTR(rc); > +} > +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); > + > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) > +{ > + device_unlock(&endpoint->dev); > + device_unlock(&cxlmd->dev); > +} > +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); > + > static void sanitize_teardown_notifier(void *data) > { > struct cxl_memdev_state *mds = data; > diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c > index d66c6349ed2d..3c6b896c5f65 100644 > --- a/drivers/cxl/core/port.c > +++ b/drivers/cxl/core/port.c > @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, > */ > dev_dbg(&cxlmd->dev, "%s is a root dport\n", > dev_name(dport_dev)); > - return -ENXIO; > + return -EPROBE_DEFER; > } > > parent_port = find_cxl_port(dparent, &parent_dport); > diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c > index f76af75a87b7..383a6f4829d3 100644 > --- a/drivers/cxl/mem.c > +++ b/drivers/cxl/mem.c > @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) > return rc; > > rc = devm_cxl_enumerate_ports(cxlmd); > - if (rc) > + if (rc) { > + cxlmd->endpoint = ERR_PTR(rc); > return rc; > + } > > parent_port = cxl_mem_find_port(cxlmd, &dport); > if (!parent_port) { > dev_err(dev, "CXL port topology not found\n"); > - return -ENXIO; > + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); > + return -EPROBE_DEFER; > } > > if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) { > diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c > index 0abe66490ef5..2cf4837ddfc1 100644 > --- a/drivers/net/ethernet/sfc/efx_cxl.c > +++ b/drivers/net/ethernet/sfc/efx_cxl.c > @@ -65,8 +65,16 @@ void efx_cxl_init(struct efx_nic *efx) > } > > cxl->cxlmd = devm_cxl_add_memdev(&pci_dev->dev, cxl->cxlds); > - if (IS_ERR(cxl->cxlmd)) > + if (IS_ERR(cxl->cxlmd)) { > pci_info(pci_dev, "CXL accel memdev creation failed"); > + return; > + } > + > + cxl->endpoint = cxl_acquire_endpoint(cxl->cxlmd); > + if (IS_ERR(cxl->endpoint)) > + pci_info(pci_dev, "CXL accel acquire endpoint failed"); > + > + cxl_release_endpoint(cxl->cxlmd, cxl->endpoint); there is no need to invoke cxl_release_endpoint() if cxl_acquire_endpoint() failed. right? > } > > > diff --git a/include/linux/cxl_accel_mem.h b/include/linux/cxl_accel_mem.h > index 442ed9862292..701910021df8 100644 > --- a/include/linux/cxl_accel_mem.h > +++ b/include/linux/cxl_accel_mem.h > @@ -29,4 +29,7 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds); > > struct cxl_memdev *devm_cxl_add_memdev(struct device *host, > struct cxl_dev_state *cxlds); > + > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd); > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint); > #endif
On 7/16/24 06:52, Li, Ming4 wrote: > On 7/16/2024 1:28 AM, alejandro.lucero-palau@amd.com wrote: >> From: Alejandro Lucero <alucerop@amd.com> >> >> The first stop for a CXL accelerator driver that wants to establish new >> CXL.mem regions is to register a 'struct cxl_memdev. That kicks off >> cxl_mem_probe() to enumerate all 'struct cxl_port' instances in the >> topology up to the root. >> >> If the root driver has not attached yet the expectation is that the >> driver waits until that link is established. The common cxl_pci_driver >> has reason to keep the 'struct cxl_memdev' device attached to the bus >> until the root driver attaches. An accelerator may want to instead defer >> probing until CXL resources can be acquired. >> >> Use the @endpoint attribute of a 'struct cxl_memdev' to convey when >> accelerator driver probing should be defferred vs failed. Provide that >> indication via a new cxl_acquire_endpoint() API that can retrieve the >> probe status of the memdev. >> >> The first consumer of this API is a test driver that excercises the CXL >> Type-2 flow. >> >> Based on https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 >> >> Signed-off-by: Alejandro Lucero <alucerop@amd.com> >> Co-developed-by: Dan Williams <dan.j.williams@intel.com> >> --- >> drivers/cxl/core/memdev.c | 41 ++++++++++++++++++++++++++++++ >> drivers/cxl/core/port.c | 2 +- >> drivers/cxl/mem.c | 7 +++-- >> drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- >> include/linux/cxl_accel_mem.h | 3 +++ >> 5 files changed, 59 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c >> index b902948b121f..d51c8bfb32e3 100644 >> --- a/drivers/cxl/core/memdev.c >> +++ b/drivers/cxl/core/memdev.c >> @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host, >> } >> EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); >> >> +/* >> + * Try to get a locked reference on a memdev's CXL port topology >> + * connection. Be careful to observe when cxl_mem_probe() has deposited >> + * a probe deferral awaiting the arrival of the CXL root driver >> +*/ >> +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) >> +{ >> + struct cxl_port *endpoint; >> + int rc = -ENXIO; >> + >> + device_lock(&cxlmd->dev); >> + endpoint = cxlmd->endpoint; >> + if (!endpoint) >> + goto err; >> + >> + if (IS_ERR(endpoint)) { >> + rc = PTR_ERR(endpoint); >> + goto err; >> + } >> + >> + device_lock(&endpoint->dev); >> + if (!endpoint->dev.driver) >> + goto err_endpoint; >> + >> + return endpoint; >> + >> +err_endpoint: >> + device_unlock(&endpoint->dev); >> +err: >> + device_unlock(&cxlmd->dev); >> + return ERR_PTR(rc); >> +} >> +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); >> + >> +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) >> +{ >> + device_unlock(&endpoint->dev); >> + device_unlock(&cxlmd->dev); >> +} >> +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); >> + >> static void sanitize_teardown_notifier(void *data) >> { >> struct cxl_memdev_state *mds = data; >> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c >> index d66c6349ed2d..3c6b896c5f65 100644 >> --- a/drivers/cxl/core/port.c >> +++ b/drivers/cxl/core/port.c >> @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, >> */ >> dev_dbg(&cxlmd->dev, "%s is a root dport\n", >> dev_name(dport_dev)); >> - return -ENXIO; >> + return -EPROBE_DEFER; >> } >> >> parent_port = find_cxl_port(dparent, &parent_dport); >> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c >> index f76af75a87b7..383a6f4829d3 100644 >> --- a/drivers/cxl/mem.c >> +++ b/drivers/cxl/mem.c >> @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) >> return rc; >> >> rc = devm_cxl_enumerate_ports(cxlmd); >> - if (rc) >> + if (rc) { >> + cxlmd->endpoint = ERR_PTR(rc); >> return rc; >> + } >> >> parent_port = cxl_mem_find_port(cxlmd, &dport); >> if (!parent_port) { >> dev_err(dev, "CXL port topology not found\n"); >> - return -ENXIO; >> + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); >> + return -EPROBE_DEFER; >> } >> >> if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) { >> diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c >> index 0abe66490ef5..2cf4837ddfc1 100644 >> --- a/drivers/net/ethernet/sfc/efx_cxl.c >> +++ b/drivers/net/ethernet/sfc/efx_cxl.c >> @@ -65,8 +65,16 @@ void efx_cxl_init(struct efx_nic *efx) >> } >> >> cxl->cxlmd = devm_cxl_add_memdev(&pci_dev->dev, cxl->cxlds); >> - if (IS_ERR(cxl->cxlmd)) >> + if (IS_ERR(cxl->cxlmd)) { >> pci_info(pci_dev, "CXL accel memdev creation failed"); >> + return; >> + } >> + >> + cxl->endpoint = cxl_acquire_endpoint(cxl->cxlmd); >> + if (IS_ERR(cxl->endpoint)) >> + pci_info(pci_dev, "CXL accel acquire endpoint failed"); >> + >> + cxl_release_endpoint(cxl->cxlmd, cxl->endpoint); > there is no need to invoke cxl_release_endpoint() if cxl_acquire_endpoint() failed. right? > > Right. BTW, I do that in a following patch. I should just add the functions to the CXL core here, and to use them in a subsequent patch where it makes sense. Thanks >> } >> >> >> diff --git a/include/linux/cxl_accel_mem.h b/include/linux/cxl_accel_mem.h >> index 442ed9862292..701910021df8 100644 >> --- a/include/linux/cxl_accel_mem.h >> +++ b/include/linux/cxl_accel_mem.h >> @@ -29,4 +29,7 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds); >> >> struct cxl_memdev *devm_cxl_add_memdev(struct device *host, >> struct cxl_dev_state *cxlds); >> + >> +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd); >> +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint); >> #endif >
On Mon, Jul 15, 2024 at 06:28:28PM +0100, alejandro.lucero-palau@amd.com wrote: > From: Alejandro Lucero <alucerop@amd.com> > > The first stop for a CXL accelerator driver that wants to establish new > CXL.mem regions is to register a 'struct cxl_memdev. That kicks off > cxl_mem_probe() to enumerate all 'struct cxl_port' instances in the > topology up to the root. > > If the root driver has not attached yet the expectation is that the > driver waits until that link is established. The common cxl_pci_driver > has reason to keep the 'struct cxl_memdev' device attached to the bus > until the root driver attaches. An accelerator may want to instead defer > probing until CXL resources can be acquired. > > Use the @endpoint attribute of a 'struct cxl_memdev' to convey when > accelerator driver probing should be defferred vs failed. Provide that > indication via a new cxl_acquire_endpoint() API that can retrieve the > probe status of the memdev. > > The first consumer of this API is a test driver that excercises the CXL > Type-2 flow. > > Based on https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 > > Signed-off-by: Alejandro Lucero <alucerop@amd.com> > Co-developed-by: Dan Williams <dan.j.williams@intel.com> > --- > drivers/cxl/core/memdev.c | 41 ++++++++++++++++++++++++++++++ > drivers/cxl/core/port.c | 2 +- > drivers/cxl/mem.c | 7 +++-- > drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- > include/linux/cxl_accel_mem.h | 3 +++ > 5 files changed, 59 insertions(+), 4 deletions(-) > > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c > index b902948b121f..d51c8bfb32e3 100644 > --- a/drivers/cxl/core/memdev.c > +++ b/drivers/cxl/core/memdev.c > @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host, > } > EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); > > +/* > + * Try to get a locked reference on a memdev's CXL port topology > + * connection. Be careful to observe when cxl_mem_probe() has deposited > + * a probe deferral awaiting the arrival of the CXL root driver > +*/ > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) > +{ > + struct cxl_port *endpoint; > + int rc = -ENXIO; > + > + device_lock(&cxlmd->dev); > + endpoint = cxlmd->endpoint; > + if (!endpoint) > + goto err; > + > + if (IS_ERR(endpoint)) { > + rc = PTR_ERR(endpoint); > + goto err; > + } > + > + device_lock(&endpoint->dev); > + if (!endpoint->dev.driver) > + goto err_endpoint; > + > + return endpoint; > + > +err_endpoint: > + device_unlock(&endpoint->dev); > +err: > + device_unlock(&cxlmd->dev); > + return ERR_PTR(rc); > +} > +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); > + > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) > +{ > + device_unlock(&endpoint->dev); > + device_unlock(&cxlmd->dev); > +} > +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); > + > static void sanitize_teardown_notifier(void *data) > { > struct cxl_memdev_state *mds = data; > diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c > index d66c6349ed2d..3c6b896c5f65 100644 > --- a/drivers/cxl/core/port.c > +++ b/drivers/cxl/core/port.c > @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, > */ > dev_dbg(&cxlmd->dev, "%s is a root dport\n", > dev_name(dport_dev)); > - return -ENXIO; > + return -EPROBE_DEFER; > } > > parent_port = find_cxl_port(dparent, &parent_dport); > diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c > index f76af75a87b7..383a6f4829d3 100644 > --- a/drivers/cxl/mem.c > +++ b/drivers/cxl/mem.c > @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) > return rc; > > rc = devm_cxl_enumerate_ports(cxlmd); > - if (rc) > + if (rc) { > + cxlmd->endpoint = ERR_PTR(rc); > return rc; > + } > > parent_port = cxl_mem_find_port(cxlmd, &dport); > if (!parent_port) { > dev_err(dev, "CXL port topology not found\n"); > - return -ENXIO; > + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); > + return -EPROBE_DEFER; > } > > if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) { > diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c > index 0abe66490ef5..2cf4837ddfc1 100644 > --- a/drivers/net/ethernet/sfc/efx_cxl.c > +++ b/drivers/net/ethernet/sfc/efx_cxl.c > @@ -65,8 +65,16 @@ void efx_cxl_init(struct efx_nic *efx) > } > > cxl->cxlmd = devm_cxl_add_memdev(&pci_dev->dev, cxl->cxlds); > - if (IS_ERR(cxl->cxlmd)) > + if (IS_ERR(cxl->cxlmd)) { > pci_info(pci_dev, "CXL accel memdev creation failed"); pci_err()? > + return; > + } > + > + cxl->endpoint = cxl_acquire_endpoint(cxl->cxlmd); > + if (IS_ERR(cxl->endpoint)) > + pci_info(pci_dev, "CXL accel acquire endpoint failed"); pci_err()? > + > + cxl_release_endpoint(cxl->cxlmd, cxl->endpoint); > } > > > diff --git a/include/linux/cxl_accel_mem.h b/include/linux/cxl_accel_mem.h > index 442ed9862292..701910021df8 100644 > --- a/include/linux/cxl_accel_mem.h > +++ b/include/linux/cxl_accel_mem.h > @@ -29,4 +29,7 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds); > > struct cxl_memdev *devm_cxl_add_memdev(struct device *host, > struct cxl_dev_state *cxlds); > + > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd); > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint); > #endif > -- > 2.17.1 >
On Mon, 15 Jul 2024 18:28:28 +0100 <alejandro.lucero-palau@amd.com> wrote: > From: Alejandro Lucero <alucerop@amd.com> > > The first stop for a CXL accelerator driver that wants to establish new > CXL.mem regions is to register a 'struct cxl_memdev. That kicks off > cxl_mem_probe() to enumerate all 'struct cxl_port' instances in the > topology up to the root. > > If the root driver has not attached yet the expectation is that the > driver waits until that link is established. The common cxl_pci_driver > has reason to keep the 'struct cxl_memdev' device attached to the bus > until the root driver attaches. An accelerator may want to instead defer > probing until CXL resources can be acquired. > > Use the @endpoint attribute of a 'struct cxl_memdev' to convey when > accelerator driver probing should be defferred vs failed. Provide that > indication via a new cxl_acquire_endpoint() API that can retrieve the > probe status of the memdev. > > The first consumer of this API is a test driver that excercises the CXL Spell check. exercises > Type-2 flow. > > Based on https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 > > Signed-off-by: Alejandro Lucero <alucerop@amd.com> > Co-developed-by: Dan Williams <dan.j.williams@intel.com> > --- > drivers/cxl/core/memdev.c | 41 ++++++++++++++++++++++++++++++ > drivers/cxl/core/port.c | 2 +- > drivers/cxl/mem.c | 7 +++-- > drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- > include/linux/cxl_accel_mem.h | 3 +++ > 5 files changed, 59 insertions(+), 4 deletions(-) > > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c > index b902948b121f..d51c8bfb32e3 100644 > --- a/drivers/cxl/core/memdev.c > +++ b/drivers/cxl/core/memdev.c > @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host, > } > EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); > > +/* > + * Try to get a locked reference on a memdev's CXL port topology > + * connection. Be careful to observe when cxl_mem_probe() has deposited > + * a probe deferral awaiting the arrival of the CXL root driver It might have deposited an error that isn't deferral I think. I would be careful to make that clear in this comment. > +*/ > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) > +{ > + struct cxl_port *endpoint; > + int rc = -ENXIO; > + > + device_lock(&cxlmd->dev); I'd not really expect an 'acquire endpoint' to exit in the good path with the cxlmd->dev device lock held. Perhaps that needs a bit more shouting in the naming of the function? > + endpoint = cxlmd->endpoint; > + if (!endpoint) > + goto err; > + > + if (IS_ERR(endpoint)) { > + rc = PTR_ERR(endpoint); > + goto err; > + } > + > + device_lock(&endpoint->dev); > + if (!endpoint->dev.driver) > + goto err_endpoint; > + > + return endpoint; > + > +err_endpoint: > + device_unlock(&endpoint->dev); > +err: > + device_unlock(&cxlmd->dev); > + return ERR_PTR(rc); > +} > +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); > + > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) > +{ > + device_unlock(&endpoint->dev); > + device_unlock(&cxlmd->dev); > +} > +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); > + > static void sanitize_teardown_notifier(void *data) > { > struct cxl_memdev_state *mds = data; > diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c > index d66c6349ed2d..3c6b896c5f65 100644 > --- a/drivers/cxl/core/port.c > +++ b/drivers/cxl/core/port.c > @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, > */ > dev_dbg(&cxlmd->dev, "%s is a root dport\n", > dev_name(dport_dev)); > - return -ENXIO; > + return -EPROBE_DEFER; > } > > parent_port = find_cxl_port(dparent, &parent_dport); > diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c > index f76af75a87b7..383a6f4829d3 100644 > --- a/drivers/cxl/mem.c > +++ b/drivers/cxl/mem.c > @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) > return rc; > > rc = devm_cxl_enumerate_ports(cxlmd); > - if (rc) > + if (rc) { > + cxlmd->endpoint = ERR_PTR(rc); > return rc; > + } > > parent_port = cxl_mem_find_port(cxlmd, &dport); > if (!parent_port) { > dev_err(dev, "CXL port topology not found\n"); Hmm. This seems excessive error print for a deferred path. > - return -ENXIO; > + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); > + return -EPROBE_DEFER; > } > > if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
On Mon, 15 Jul 2024 18:28:28 +0100 <alejandro.lucero-palau@amd.com> wrote: Another spell check is spotted besides others review threads. Will circle back with more comments once checking the users of the APIs. > From: Alejandro Lucero <alucerop@amd.com> > > The first stop for a CXL accelerator driver that wants to establish > new CXL.mem regions is to register a 'struct cxl_memdev. That kicks > off cxl_mem_probe() to enumerate all 'struct cxl_port' instances in > the topology up to the root. > > If the root driver has not attached yet the expectation is that the > driver waits until that link is established. The common cxl_pci_driver > has reason to keep the 'struct cxl_memdev' device attached to the bus > until the root driver attaches. An accelerator may want to instead > defer probing until CXL resources can be acquired. > > Use the @endpoint attribute of a 'struct cxl_memdev' to convey when > accelerator driver probing should be defferred vs failed. Provide that ^deferred > indication via a new cxl_acquire_endpoint() API that can retrieve the > probe status of the memdev. > > The first consumer of this API is a test driver that excercises the > CXL Type-2 flow. > > Based on > https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 > > Signed-off-by: Alejandro Lucero <alucerop@amd.com> > Co-developed-by: Dan Williams <dan.j.williams@intel.com> > --- > drivers/cxl/core/memdev.c | 41 > ++++++++++++++++++++++++++++++ drivers/cxl/core/port.c | > 2 +- drivers/cxl/mem.c | 7 +++-- > drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- > include/linux/cxl_accel_mem.h | 3 +++ > 5 files changed, 59 insertions(+), 4 deletions(-) > > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c > index b902948b121f..d51c8bfb32e3 100644 > --- a/drivers/cxl/core/memdev.c > +++ b/drivers/cxl/core/memdev.c > @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct > device *host, } > EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); > > +/* > + * Try to get a locked reference on a memdev's CXL port topology > + * connection. Be careful to observe when cxl_mem_probe() has > deposited > + * a probe deferral awaiting the arrival of the CXL root driver > +*/ > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) > +{ > + struct cxl_port *endpoint; > + int rc = -ENXIO; > + > + device_lock(&cxlmd->dev); > + endpoint = cxlmd->endpoint; > + if (!endpoint) > + goto err; > + > + if (IS_ERR(endpoint)) { > + rc = PTR_ERR(endpoint); > + goto err; > + } > + > + device_lock(&endpoint->dev); > + if (!endpoint->dev.driver) > + goto err_endpoint; > + > + return endpoint; > + > +err_endpoint: > + device_unlock(&endpoint->dev); > +err: > + device_unlock(&cxlmd->dev); > + return ERR_PTR(rc); > +} > +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); > + > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port > *endpoint) +{ > + device_unlock(&endpoint->dev); > + device_unlock(&cxlmd->dev); > +} > +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); > + > static void sanitize_teardown_notifier(void *data) > { > struct cxl_memdev_state *mds = data; > diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c > index d66c6349ed2d..3c6b896c5f65 100644 > --- a/drivers/cxl/core/port.c > +++ b/drivers/cxl/core/port.c > @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev > *cxlmd, */ > dev_dbg(&cxlmd->dev, "%s is a root dport\n", > dev_name(dport_dev)); > - return -ENXIO; > + return -EPROBE_DEFER; > } > > parent_port = find_cxl_port(dparent, &parent_dport); > diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c > index f76af75a87b7..383a6f4829d3 100644 > --- a/drivers/cxl/mem.c > +++ b/drivers/cxl/mem.c > @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) > return rc; > > rc = devm_cxl_enumerate_ports(cxlmd); > - if (rc) > + if (rc) { > + cxlmd->endpoint = ERR_PTR(rc); > return rc; > + } > > parent_port = cxl_mem_find_port(cxlmd, &dport); > if (!parent_port) { > dev_err(dev, "CXL port topology not found\n"); > - return -ENXIO; > + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); > + return -EPROBE_DEFER; > } > > if (resource_size(&cxlds->pmem_res) && > IS_ENABLED(CONFIG_CXL_PMEM)) { diff --git > a/drivers/net/ethernet/sfc/efx_cxl.c > b/drivers/net/ethernet/sfc/efx_cxl.c index 0abe66490ef5..2cf4837ddfc1 > 100644 --- a/drivers/net/ethernet/sfc/efx_cxl.c +++ > b/drivers/net/ethernet/sfc/efx_cxl.c @@ -65,8 +65,16 @@ void > efx_cxl_init(struct efx_nic *efx) } > > cxl->cxlmd = devm_cxl_add_memdev(&pci_dev->dev, cxl->cxlds); > - if (IS_ERR(cxl->cxlmd)) > + if (IS_ERR(cxl->cxlmd)) { > pci_info(pci_dev, "CXL accel memdev creation > failed"); > + return; > + } > + > + cxl->endpoint = cxl_acquire_endpoint(cxl->cxlmd); > + if (IS_ERR(cxl->endpoint)) > + pci_info(pci_dev, "CXL accel acquire endpoint > failed"); + > + cxl_release_endpoint(cxl->cxlmd, cxl->endpoint); > } > > > diff --git a/include/linux/cxl_accel_mem.h > b/include/linux/cxl_accel_mem.h index 442ed9862292..701910021df8 > 100644 --- a/include/linux/cxl_accel_mem.h > +++ b/include/linux/cxl_accel_mem.h > @@ -29,4 +29,7 @@ int cxl_await_media_ready(struct cxl_dev_state > *cxlds); > struct cxl_memdev *devm_cxl_add_memdev(struct device *host, > struct cxl_dev_state *cxlds); > + > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd); > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port > *endpoint); #endif
On 8/4/24 18:41, Jonathan Cameron wrote: > On Mon, 15 Jul 2024 18:28:28 +0100 > <alejandro.lucero-palau@amd.com> wrote: > >> From: Alejandro Lucero <alucerop@amd.com> >> >> The first stop for a CXL accelerator driver that wants to establish new >> CXL.mem regions is to register a 'struct cxl_memdev. That kicks off >> cxl_mem_probe() to enumerate all 'struct cxl_port' instances in the >> topology up to the root. >> >> If the root driver has not attached yet the expectation is that the >> driver waits until that link is established. The common cxl_pci_driver >> has reason to keep the 'struct cxl_memdev' device attached to the bus >> until the root driver attaches. An accelerator may want to instead defer >> probing until CXL resources can be acquired. >> >> Use the @endpoint attribute of a 'struct cxl_memdev' to convey when >> accelerator driver probing should be defferred vs failed. Provide that >> indication via a new cxl_acquire_endpoint() API that can retrieve the >> probe status of the memdev. >> >> The first consumer of this API is a test driver that excercises the CXL > Spell check. > exercises I'll fix it along with step instead of stop in the first line. >> Type-2 flow. >> >> Based on https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 >> >> Signed-off-by: Alejandro Lucero <alucerop@amd.com> >> Co-developed-by: Dan Williams <dan.j.williams@intel.com> >> --- >> drivers/cxl/core/memdev.c | 41 ++++++++++++++++++++++++++++++ >> drivers/cxl/core/port.c | 2 +- >> drivers/cxl/mem.c | 7 +++-- >> drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- >> include/linux/cxl_accel_mem.h | 3 +++ >> 5 files changed, 59 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c >> index b902948b121f..d51c8bfb32e3 100644 >> --- a/drivers/cxl/core/memdev.c >> +++ b/drivers/cxl/core/memdev.c >> @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host, >> } >> EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); >> >> +/* >> + * Try to get a locked reference on a memdev's CXL port topology >> + * connection. Be careful to observe when cxl_mem_probe() has deposited >> + * a probe deferral awaiting the arrival of the CXL root driver > It might have deposited an error that isn't deferral I think. > I would be careful to make that clear in this comment. Yes. The situation this patch is dealing with is not easy to handle. I realize the accel driver needs to be aware of it what the sfc code does not handle. I need to work on this starting with emulating the situation and maybe adding the work as a test ... where we need some emulated Type2 device. Dan was asking about some work done before my initial RFC where Type2 support in qemu was the target, maybe something we can talk about in the LPC. >> +*/ >> +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) >> +{ >> + struct cxl_port *endpoint; >> + int rc = -ENXIO; >> + >> + device_lock(&cxlmd->dev); > I'd not really expect an 'acquire endpoint' to exit > in the good path with the cxlmd->dev device lock held. > Perhaps that needs a bit more shouting in the naming of > the function? Uhmm, not clear to me at this point if that is needed. This is basically the original patch by Dan so as said above, I need to work on this a bit further. I'll try to get this sorted out for v3. Thanks >> + endpoint = cxlmd->endpoint; >> + if (!endpoint) >> + goto err; >> + >> + if (IS_ERR(endpoint)) { >> + rc = PTR_ERR(endpoint); >> + goto err; >> + } >> + >> + device_lock(&endpoint->dev); >> + if (!endpoint->dev.driver) >> + goto err_endpoint; >> + >> + return endpoint; >> + >> +err_endpoint: >> + device_unlock(&endpoint->dev); >> +err: >> + device_unlock(&cxlmd->dev); >> + return ERR_PTR(rc); >> +} >> +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); >> + >> +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) >> +{ >> + device_unlock(&endpoint->dev); >> + device_unlock(&cxlmd->dev); >> +} >> +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); >> + >> static void sanitize_teardown_notifier(void *data) >> { >> struct cxl_memdev_state *mds = data; >> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c >> index d66c6349ed2d..3c6b896c5f65 100644 >> --- a/drivers/cxl/core/port.c >> +++ b/drivers/cxl/core/port.c >> @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, >> */ >> dev_dbg(&cxlmd->dev, "%s is a root dport\n", >> dev_name(dport_dev)); >> - return -ENXIO; >> + return -EPROBE_DEFER; >> } >> >> parent_port = find_cxl_port(dparent, &parent_dport); >> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c >> index f76af75a87b7..383a6f4829d3 100644 >> --- a/drivers/cxl/mem.c >> +++ b/drivers/cxl/mem.c >> @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) >> return rc; >> >> rc = devm_cxl_enumerate_ports(cxlmd); >> - if (rc) >> + if (rc) { >> + cxlmd->endpoint = ERR_PTR(rc); >> return rc; >> + } >> >> parent_port = cxl_mem_find_port(cxlmd, &dport); >> if (!parent_port) { >> dev_err(dev, "CXL port topology not found\n"); > Hmm. This seems excessive error print for a deferred path. > >> - return -ENXIO; >> + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); >> + return -EPROBE_DEFER; >> } >> >> if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
On Mon, 15 Jul 2024 18:28:28 +0100 <alejandro.lucero-palau@amd.com> wrote: > From: Alejandro Lucero <alucerop@amd.com> > > The first stop for a CXL accelerator driver that wants to establish > new CXL.mem regions is to register a 'struct cxl_memdev. That kicks > off cxl_mem_probe() to enumerate all 'struct cxl_port' instances in > the topology up to the root. > > If the root driver has not attached yet the expectation is that the > driver waits until that link is established. The common cxl_pci_driver > has reason to keep the 'struct cxl_memdev' device attached to the bus > until the root driver attaches. An accelerator may want to instead > defer probing until CXL resources can be acquired. > > Use the @endpoint attribute of a 'struct cxl_memdev' to convey when > accelerator driver probing should be defferred vs failed. Provide that > indication via a new cxl_acquire_endpoint() API that can retrieve the > probe status of the memdev. > > The first consumer of this API is a test driver that excercises the > CXL Type-2 flow. > Out of curiosity, when and where do we probe CXL_DVSEC_CACHE_CAPABLE and enable the CXL_DVSEC_CACHE_ENABLE bit for a type-2 device? Thanks, Zhi. > Based on > https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 > > Signed-off-by: Alejandro Lucero <alucerop@amd.com> > Co-developed-by: Dan Williams <dan.j.williams@intel.com> > --- > drivers/cxl/core/memdev.c | 41 > ++++++++++++++++++++++++++++++ drivers/cxl/core/port.c | > 2 +- drivers/cxl/mem.c | 7 +++-- > drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- > include/linux/cxl_accel_mem.h | 3 +++ > 5 files changed, 59 insertions(+), 4 deletions(-) > > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c > index b902948b121f..d51c8bfb32e3 100644 > --- a/drivers/cxl/core/memdev.c > +++ b/drivers/cxl/core/memdev.c > @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct > device *host, } > EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); > > +/* > + * Try to get a locked reference on a memdev's CXL port topology > + * connection. Be careful to observe when cxl_mem_probe() has > deposited > + * a probe deferral awaiting the arrival of the CXL root driver > +*/ > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) > +{ > + struct cxl_port *endpoint; > + int rc = -ENXIO; > + > + device_lock(&cxlmd->dev); > + endpoint = cxlmd->endpoint; > + if (!endpoint) > + goto err; > + > + if (IS_ERR(endpoint)) { > + rc = PTR_ERR(endpoint); > + goto err; > + } > + > + device_lock(&endpoint->dev); > + if (!endpoint->dev.driver) > + goto err_endpoint; > + > + return endpoint; > + > +err_endpoint: > + device_unlock(&endpoint->dev); > +err: > + device_unlock(&cxlmd->dev); > + return ERR_PTR(rc); > +} > +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); > + > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port > *endpoint) +{ > + device_unlock(&endpoint->dev); > + device_unlock(&cxlmd->dev); > +} > +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); > + > static void sanitize_teardown_notifier(void *data) > { > struct cxl_memdev_state *mds = data; > diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c > index d66c6349ed2d..3c6b896c5f65 100644 > --- a/drivers/cxl/core/port.c > +++ b/drivers/cxl/core/port.c > @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev > *cxlmd, */ > dev_dbg(&cxlmd->dev, "%s is a root dport\n", > dev_name(dport_dev)); > - return -ENXIO; > + return -EPROBE_DEFER; > } > > parent_port = find_cxl_port(dparent, &parent_dport); > diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c > index f76af75a87b7..383a6f4829d3 100644 > --- a/drivers/cxl/mem.c > +++ b/drivers/cxl/mem.c > @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) > return rc; > > rc = devm_cxl_enumerate_ports(cxlmd); > - if (rc) > + if (rc) { > + cxlmd->endpoint = ERR_PTR(rc); > return rc; > + } > > parent_port = cxl_mem_find_port(cxlmd, &dport); > if (!parent_port) { > dev_err(dev, "CXL port topology not found\n"); > - return -ENXIO; > + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); > + return -EPROBE_DEFER; > } > > if (resource_size(&cxlds->pmem_res) && > IS_ENABLED(CONFIG_CXL_PMEM)) { diff --git > a/drivers/net/ethernet/sfc/efx_cxl.c > b/drivers/net/ethernet/sfc/efx_cxl.c index 0abe66490ef5..2cf4837ddfc1 > 100644 --- a/drivers/net/ethernet/sfc/efx_cxl.c +++ > b/drivers/net/ethernet/sfc/efx_cxl.c @@ -65,8 +65,16 @@ void > efx_cxl_init(struct efx_nic *efx) } > > cxl->cxlmd = devm_cxl_add_memdev(&pci_dev->dev, cxl->cxlds); > - if (IS_ERR(cxl->cxlmd)) > + if (IS_ERR(cxl->cxlmd)) { > pci_info(pci_dev, "CXL accel memdev creation > failed"); > + return; > + } > + > + cxl->endpoint = cxl_acquire_endpoint(cxl->cxlmd); > + if (IS_ERR(cxl->endpoint)) > + pci_info(pci_dev, "CXL accel acquire endpoint > failed"); + > + cxl_release_endpoint(cxl->cxlmd, cxl->endpoint); > } > > > diff --git a/include/linux/cxl_accel_mem.h > b/include/linux/cxl_accel_mem.h index 442ed9862292..701910021df8 > 100644 --- a/include/linux/cxl_accel_mem.h > +++ b/include/linux/cxl_accel_mem.h > @@ -29,4 +29,7 @@ int cxl_await_media_ready(struct cxl_dev_state > *cxlds); > struct cxl_memdev *devm_cxl_add_memdev(struct device *host, > struct cxl_dev_state *cxlds); > + > +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd); > +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port > *endpoint); #endif
On 8/26/24 18:42, Zhi Wang wrote: > On Mon, 15 Jul 2024 18:28:28 +0100 > <alejandro.lucero-palau@amd.com> wrote: > >> From: Alejandro Lucero <alucerop@amd.com> >> >> The first stop for a CXL accelerator driver that wants to establish >> new CXL.mem regions is to register a 'struct cxl_memdev. That kicks >> off cxl_mem_probe() to enumerate all 'struct cxl_port' instances in >> the topology up to the root. >> >> If the root driver has not attached yet the expectation is that the >> driver waits until that link is established. The common cxl_pci_driver >> has reason to keep the 'struct cxl_memdev' device attached to the bus >> until the root driver attaches. An accelerator may want to instead >> defer probing until CXL resources can be acquired. >> >> Use the @endpoint attribute of a 'struct cxl_memdev' to convey when >> accelerator driver probing should be defferred vs failed. Provide that >> indication via a new cxl_acquire_endpoint() API that can retrieve the >> probe status of the memdev. >> >> The first consumer of this API is a test driver that excercises the >> CXL Type-2 flow. >> > Out of curiosity, when and where do we probe CXL_DVSEC_CACHE_CAPABLE and > enable the CXL_DVSEC_CACHE_ENABLE bit for a type-2 device? > > Thanks, > Zhi. As It is mentioned in the cover letter, this is a Type2 device but not working on CXL.cache yet. I hope we can discuss how to deal with CXL.cache in the LPC next month. I'll be talking about it and current state of this patchset. Thank you >> Based on >> https://lore.kernel.org/linux-cxl/168592149709.1948938.8663425987110396027.stgit@dwillia2-xfh.jf.intel.com/T/#m18497367d2ae38f88e94c06369eaa83fa23e92b2 >> >> Signed-off-by: Alejandro Lucero <alucerop@amd.com> >> Co-developed-by: Dan Williams <dan.j.williams@intel.com> >> --- >> drivers/cxl/core/memdev.c | 41 >> ++++++++++++++++++++++++++++++ drivers/cxl/core/port.c | >> 2 +- drivers/cxl/mem.c | 7 +++-- >> drivers/net/ethernet/sfc/efx_cxl.c | 10 +++++++- >> include/linux/cxl_accel_mem.h | 3 +++ >> 5 files changed, 59 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c >> index b902948b121f..d51c8bfb32e3 100644 >> --- a/drivers/cxl/core/memdev.c >> +++ b/drivers/cxl/core/memdev.c >> @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct >> device *host, } >> EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); >> >> +/* >> + * Try to get a locked reference on a memdev's CXL port topology >> + * connection. Be careful to observe when cxl_mem_probe() has >> deposited >> + * a probe deferral awaiting the arrival of the CXL root driver >> +*/ >> +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) >> +{ >> + struct cxl_port *endpoint; >> + int rc = -ENXIO; >> + >> + device_lock(&cxlmd->dev); >> + endpoint = cxlmd->endpoint; >> + if (!endpoint) >> + goto err; >> + >> + if (IS_ERR(endpoint)) { >> + rc = PTR_ERR(endpoint); >> + goto err; >> + } >> + >> + device_lock(&endpoint->dev); >> + if (!endpoint->dev.driver) >> + goto err_endpoint; >> + >> + return endpoint; >> + >> +err_endpoint: >> + device_unlock(&endpoint->dev); >> +err: >> + device_unlock(&cxlmd->dev); >> + return ERR_PTR(rc); >> +} >> +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); >> + >> +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port >> *endpoint) +{ >> + device_unlock(&endpoint->dev); >> + device_unlock(&cxlmd->dev); >> +} >> +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); >> + >> static void sanitize_teardown_notifier(void *data) >> { >> struct cxl_memdev_state *mds = data; >> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c >> index d66c6349ed2d..3c6b896c5f65 100644 >> --- a/drivers/cxl/core/port.c >> +++ b/drivers/cxl/core/port.c >> @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev >> *cxlmd, */ >> dev_dbg(&cxlmd->dev, "%s is a root dport\n", >> dev_name(dport_dev)); >> - return -ENXIO; >> + return -EPROBE_DEFER; >> } >> >> parent_port = find_cxl_port(dparent, &parent_dport); >> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c >> index f76af75a87b7..383a6f4829d3 100644 >> --- a/drivers/cxl/mem.c >> +++ b/drivers/cxl/mem.c >> @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) >> return rc; >> >> rc = devm_cxl_enumerate_ports(cxlmd); >> - if (rc) >> + if (rc) { >> + cxlmd->endpoint = ERR_PTR(rc); >> return rc; >> + } >> >> parent_port = cxl_mem_find_port(cxlmd, &dport); >> if (!parent_port) { >> dev_err(dev, "CXL port topology not found\n"); >> - return -ENXIO; >> + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); >> + return -EPROBE_DEFER; >> } >> >> if (resource_size(&cxlds->pmem_res) && >> IS_ENABLED(CONFIG_CXL_PMEM)) { diff --git >> a/drivers/net/ethernet/sfc/efx_cxl.c >> b/drivers/net/ethernet/sfc/efx_cxl.c index 0abe66490ef5..2cf4837ddfc1 >> 100644 --- a/drivers/net/ethernet/sfc/efx_cxl.c +++ >> b/drivers/net/ethernet/sfc/efx_cxl.c @@ -65,8 +65,16 @@ void >> efx_cxl_init(struct efx_nic *efx) } >> >> cxl->cxlmd = devm_cxl_add_memdev(&pci_dev->dev, cxl->cxlds); >> - if (IS_ERR(cxl->cxlmd)) >> + if (IS_ERR(cxl->cxlmd)) { >> pci_info(pci_dev, "CXL accel memdev creation >> failed"); >> + return; >> + } >> + >> + cxl->endpoint = cxl_acquire_endpoint(cxl->cxlmd); >> + if (IS_ERR(cxl->endpoint)) >> + pci_info(pci_dev, "CXL accel acquire endpoint >> failed"); + >> + cxl_release_endpoint(cxl->cxlmd, cxl->endpoint); >> } >> >> >> diff --git a/include/linux/cxl_accel_mem.h >> b/include/linux/cxl_accel_mem.h index 442ed9862292..701910021df8 >> 100644 --- a/include/linux/cxl_accel_mem.h >> +++ b/include/linux/cxl_accel_mem.h >> @@ -29,4 +29,7 @@ int cxl_await_media_ready(struct cxl_dev_state >> *cxlds); >> struct cxl_memdev *devm_cxl_add_memdev(struct device *host, >> struct cxl_dev_state *cxlds); >> + >> +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd); >> +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port >> *endpoint); #endif
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index b902948b121f..d51c8bfb32e3 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -1137,6 +1137,47 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host, } EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); +/* + * Try to get a locked reference on a memdev's CXL port topology + * connection. Be careful to observe when cxl_mem_probe() has deposited + * a probe deferral awaiting the arrival of the CXL root driver +*/ +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd) +{ + struct cxl_port *endpoint; + int rc = -ENXIO; + + device_lock(&cxlmd->dev); + endpoint = cxlmd->endpoint; + if (!endpoint) + goto err; + + if (IS_ERR(endpoint)) { + rc = PTR_ERR(endpoint); + goto err; + } + + device_lock(&endpoint->dev); + if (!endpoint->dev.driver) + goto err_endpoint; + + return endpoint; + +err_endpoint: + device_unlock(&endpoint->dev); +err: + device_unlock(&cxlmd->dev); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_NS(cxl_acquire_endpoint, CXL); + +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) +{ + device_unlock(&endpoint->dev); + device_unlock(&cxlmd->dev); +} +EXPORT_SYMBOL_NS(cxl_release_endpoint, CXL); + static void sanitize_teardown_notifier(void *data) { struct cxl_memdev_state *mds = data; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index d66c6349ed2d..3c6b896c5f65 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1553,7 +1553,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, */ dev_dbg(&cxlmd->dev, "%s is a root dport\n", dev_name(dport_dev)); - return -ENXIO; + return -EPROBE_DEFER; } parent_port = find_cxl_port(dparent, &parent_dport); diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index f76af75a87b7..383a6f4829d3 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -145,13 +145,16 @@ static int cxl_mem_probe(struct device *dev) return rc; rc = devm_cxl_enumerate_ports(cxlmd); - if (rc) + if (rc) { + cxlmd->endpoint = ERR_PTR(rc); return rc; + } parent_port = cxl_mem_find_port(cxlmd, &dport); if (!parent_port) { dev_err(dev, "CXL port topology not found\n"); - return -ENXIO; + cxlmd->endpoint = ERR_PTR(-EPROBE_DEFER); + return -EPROBE_DEFER; } if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) { diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c index 0abe66490ef5..2cf4837ddfc1 100644 --- a/drivers/net/ethernet/sfc/efx_cxl.c +++ b/drivers/net/ethernet/sfc/efx_cxl.c @@ -65,8 +65,16 @@ void efx_cxl_init(struct efx_nic *efx) } cxl->cxlmd = devm_cxl_add_memdev(&pci_dev->dev, cxl->cxlds); - if (IS_ERR(cxl->cxlmd)) + if (IS_ERR(cxl->cxlmd)) { pci_info(pci_dev, "CXL accel memdev creation failed"); + return; + } + + cxl->endpoint = cxl_acquire_endpoint(cxl->cxlmd); + if (IS_ERR(cxl->endpoint)) + pci_info(pci_dev, "CXL accel acquire endpoint failed"); + + cxl_release_endpoint(cxl->cxlmd, cxl->endpoint); } diff --git a/include/linux/cxl_accel_mem.h b/include/linux/cxl_accel_mem.h index 442ed9862292..701910021df8 100644 --- a/include/linux/cxl_accel_mem.h +++ b/include/linux/cxl_accel_mem.h @@ -29,4 +29,7 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds); struct cxl_memdev *devm_cxl_add_memdev(struct device *host, struct cxl_dev_state *cxlds); + +struct cxl_port *cxl_acquire_endpoint(struct cxl_memdev *cxlmd); +void cxl_release_endpoint(struct cxl_memdev *cxlmd, struct cxl_port *endpoint); #endif