Skip to content

Commit 4fa4302

Browse files
fancxldjbw
authored andcommitted
cxl/region: Fix null pointer dereference for resetting decoder
Not all decoders have a reset callback. The CXL specification allows a host bridge with a single root port to have no explicit HDM decoders. Currently the region driver assumes there are none. As such the CXL core creates a special pass through decoder instance without a commit/reset callback. Prior to this patch, the ->reset() callback was called unconditionally when calling cxl_region_decode_reset. Thus a configuration with 1 Host Bridge, 1 Root Port, and one directly attached CXL type 3 device or multiple CXL type 3 devices attached to downstream ports of a switch can cause a null pointer dereference. Before the fix, a kernel crash was observed when we destroy the region, and a pass through decoder is reset. The issue can be reproduced as below, 1) create a region with a CXL setup which includes a HB with a single root port under which a memdev is attached directly. 2) destroy the region with cxl destroy-region regionX -f. Fixes: 176baef ("cxl/hdm: Commit decoder state to hardware") Cc: <[email protected]> Signed-off-by: Fan Ni <[email protected]> Reviewed-by: Davidlohr Bueso <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Tested-by: Gregory Price <[email protected]> Reviewed-by: Gregory Price <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dan Williams <[email protected]>
1 parent 6d796c5 commit 4fa4302

File tree

1 file changed

+5
-3
lines changed

1 file changed

+5
-3
lines changed

drivers/cxl/core/region.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
131131
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
132132
struct cxl_port *iter = cxled_to_port(cxled);
133133
struct cxl_ep *ep;
134-
int rc;
134+
int rc = 0;
135135

136136
while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
137137
iter = to_cxl_port(iter->dev.parent);
@@ -143,7 +143,8 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
143143

144144
cxl_rr = cxl_rr_load(iter, cxlr);
145145
cxld = cxl_rr->decoder;
146-
rc = cxld->reset(cxld);
146+
if (cxld->reset)
147+
rc = cxld->reset(cxld);
147148
if (rc)
148149
return rc;
149150
}
@@ -186,7 +187,8 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr)
186187
iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
187188
cxl_rr = cxl_rr_load(iter, cxlr);
188189
cxld = cxl_rr->decoder;
189-
cxld->reset(cxld);
190+
if (cxld->reset)
191+
cxld->reset(cxld);
190192
}
191193

192194
cxled->cxld.reset(&cxled->cxld);

0 commit comments

Comments
 (0)