Re: [PATCH v4 4/4] cxl/hdm: Restore commit_end when decoder enumeration fails
Dave Jiang <[email protected]>
| Newsgroups | org.kernel.vger.linux-cxl |
|---|---|
| Message-ID | <[email protected]> |
On 7/20/26 6:59 PM, Alison Schofield wrote:
> commit_end tracks the highest committed decoder on a port. It gets
> advanced before decoder enumeration is complete, so a later failure
> leaves it pointing at a decoder that was never added. The next probe
> then rejects decoder0 as out of order and enumeration fails.
>
> Reset commit_end to the none committed baseline once the decoders are
s/none committed/uncommitted/ ?
> torn down, so a subsequent probe rebuilds it from scratch. Register
> the reset before the decoders are added so that on unwind it runs
> after every decoder has been unregistered. This prevents commit_end
> from dropping below the highest committed decoder still registered and
> exposing an inconsistent value to a concurrent reader.
>
> Protect the commit_end advance in the DVSEC emulation path against
> concurrent readers, matching the register-programmed path.
>
> Fixes: 176baefb2eb5 ("cxl/hdm: Commit decoder state to hardware")
> Fixes: b777e9bec960 ("cxl/hdm: Emulate HDM decoder from DVSEC range registers")
> Signed-off-by: Alison Schofield <[email protected]>
Reviewed-by: Dave Jiang <[email protected]>
> ---
> drivers/cxl/core/hdm.c | 23 ++++++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
> index 077aface1a2a..7d4ba7fa30fa 100644
> --- a/drivers/cxl/core/hdm.c
> +++ b/drivers/cxl/core/hdm.c
> @@ -955,7 +955,8 @@ static int cxl_setup_hdm_decoder_from_dvsec(
> * change the range registers at run time.
> */
> cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
> - port->commit_end = cxld->id;
> + scoped_guard(rwsem_write, &cxl_rwsem.region)
> + port->commit_end = cxld->id;
>
> rc = devm_cxl_dpa_reserve(cxled, *dpa_base, len, 0);
> if (rc) {
> @@ -1181,6 +1182,14 @@ static void cxl_settle_decoders(struct cxl_hdm *cxlhdm)
> msleep(20);
> }
>
> +static void cxl_reset_commit_end(void *data)
> +{
> + struct cxl_port *port = data;
> +
> + guard(rwsem_write)(&cxl_rwsem.region);
> + port->commit_end = -1;
> +}
> +
> /**
> * devm_cxl_enumerate_decoders - add decoder objects per HDM register set
> * @cxlhdm: Structure to populate with HDM capabilities
> @@ -1191,13 +1200,21 @@ static int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
> {
> void __iomem *hdm = cxlhdm->regs.hdm_decoder;
> struct cxl_port *port = cxlhdm->port;
> - int i;
> u64 dpa_base = 0;
> + int i, rc;
>
> cxl_settle_decoders(cxlhdm);
>
> + /*
> + * Reset commit_end after all decoders have been torn down so a
> + * subsequent probe rebuilds it from scratch.
> + */
> + rc = devm_add_action(&port->dev, cxl_reset_commit_end, port);
> + if (rc)
> + return rc;
> +
> for (i = 0; i < cxlhdm->decoder_count; i++) {
> - int rc, target_count = cxlhdm->target_count;
> + int target_count = cxlhdm->target_count;
> struct cxl_decoder *cxld;
>
> if (is_cxl_endpoint(port)) {