Skip to content

Commit 7004cc9

Browse files
committed
cxl/core/port: Handle invalid decoders
In case init_hdm_decoder() finds invalid settings, skip to the next valid decoder. Only fail port enumeration if zero valid decoders are found. This protects the driver init against broken hardware and / or future interleave capabilities. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Link: https://lore.kernel.org/r/164317464918.3438644.12371149695618136198.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 0909b4e commit 7004cc9

1 file changed

Lines changed: 30 additions & 6 deletions

File tree

drivers/cxl/core/hdm.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ static int to_interleave_ways(u32 ctrl)
149149
}
150150
}
151151

152-
static void init_hdm_decoder(struct cxl_decoder *cxld, int *target_map,
153-
void __iomem *hdm, int which)
152+
static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
153+
int *target_map, void __iomem *hdm, int which)
154154
{
155155
u64 size, base;
156156
u32 ctrl;
@@ -166,6 +166,11 @@ static void init_hdm_decoder(struct cxl_decoder *cxld, int *target_map,
166166

167167
if (!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED))
168168
size = 0;
169+
if (base == U64_MAX || size == U64_MAX) {
170+
dev_warn(&port->dev, "decoder%d.%d: Invalid resource range\n",
171+
port->id, cxld->id);
172+
return -ENXIO;
173+
}
169174

170175
cxld->decoder_range = (struct range) {
171176
.start = base,
@@ -179,6 +184,12 @@ static void init_hdm_decoder(struct cxl_decoder *cxld, int *target_map,
179184
cxld->flags |= CXL_DECODER_F_LOCK;
180185
}
181186
cxld->interleave_ways = to_interleave_ways(ctrl);
187+
if (!cxld->interleave_ways) {
188+
dev_warn(&port->dev,
189+
"decoder%d.%d: Invalid interleave ways (ctrl: %#x)\n",
190+
port->id, cxld->id, ctrl);
191+
return -ENXIO;
192+
}
182193
cxld->interleave_granularity = to_interleave_granularity(ctrl);
183194

184195
if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl))
@@ -187,12 +198,14 @@ static void init_hdm_decoder(struct cxl_decoder *cxld, int *target_map,
187198
cxld->target_type = CXL_DECODER_ACCELERATOR;
188199

189200
if (is_cxl_endpoint(to_cxl_port(cxld->dev.parent)))
190-
return;
201+
return 0;
191202

192203
target_list.value =
193204
ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
194205
for (i = 0; i < cxld->interleave_ways; i++)
195206
target_map[i] = target_list.target_id[i];
207+
208+
return 0;
196209
}
197210

198211
/**
@@ -203,7 +216,7 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
203216
{
204217
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
205218
struct cxl_port *port = cxlhdm->port;
206-
int i, committed;
219+
int i, committed, failed;
207220
u32 ctrl;
208221

209222
/*
@@ -223,7 +236,7 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
223236
if (committed != cxlhdm->decoder_count)
224237
msleep(20);
225238

226-
for (i = 0; i < cxlhdm->decoder_count; i++) {
239+
for (i = 0, failed = 0; i < cxlhdm->decoder_count; i++) {
227240
int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
228241
int rc, target_count = cxlhdm->target_count;
229242
struct cxl_decoder *cxld;
@@ -238,7 +251,13 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
238251
return PTR_ERR(cxld);
239252
}
240253

241-
init_hdm_decoder(cxld, target_map, cxlhdm->regs.hdm_decoder, i);
254+
rc = init_hdm_decoder(port, cxld, target_map,
255+
cxlhdm->regs.hdm_decoder, i);
256+
if (rc) {
257+
put_device(&cxld->dev);
258+
failed++;
259+
continue;
260+
}
242261
rc = add_hdm_decoder(port, cxld, target_map);
243262
if (rc) {
244263
dev_warn(&port->dev,
@@ -247,6 +266,11 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
247266
}
248267
}
249268

269+
if (failed == cxlhdm->decoder_count) {
270+
dev_err(&port->dev, "No valid decoders found\n");
271+
return -ENXIO;
272+
}
273+
250274
return 0;
251275
}
252276
EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, CXL);

0 commit comments

Comments
 (0)