[PATCH v5 3/4] cxl/hdm: Restore commit_end when decoder enumeration fails
Alison Schofield <[email protected]>
| Newsgroups | org.kernel.vger.linux-cxl |
|---|---|
| Message-ID | <4802c5abc906b858a4754bfc4fa3e4c2c455d0c3.1786143520.git.alison.schofield@intel.com> |
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 uncommitted baseline once the decoders are
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")
Reviewed-by: Jonathan Cameron <[email protected]>
Reviewed-by: Dave Jiang <[email protected]>
Reviewed-by: Li Ming <[email protected]>
Reviewed-by: Richard Cheng <[email protected]>
Signed-off-by: Alison Schofield <[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 fc22d515b638..cb24901dd289 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -956,7 +956,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) {
@@ -1159,6 +1160,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
@@ -1169,8 +1178,8 @@ 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;
/*
* Per CXL 4.0 8.2.4.20.1 Target Count is the number of target ports
@@ -1186,8 +1195,16 @@ static int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
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)) {
--
2.37.3