Skip to content

Commit 48667f6

Browse files
committed
cxl/core: Split decoder setup into alloc + add
The kbuild robot reports: drivers/cxl/core/bus.c:516:1: warning: stack frame size (1032) exceeds limit (1024) in function 'devm_cxl_add_decoder' It is also the case the devm_cxl_add_decoder() is unwieldy to use for all the different decoder types. Fix the stack usage by splitting the creation into alloc and add steps. This also allows for context specific construction before adding. With the split the caller is responsible for registering a devm callback to trigger device_unregister() for the decoder rather than it being implicit in the decoder registration. I.e. the routine that calls alloc is responsible for calling put_device() if the "add" operation fails. Reported-by: kernel test robot <[email protected]> Reported-by: Nathan Chancellor <[email protected]> Reported-by: Dan Carpenter <[email protected]> Reviewed-by: Ben Widawsky <[email protected]> Link: https://lore.kernel.org/r/163225205828.3038145.6831131648369404859.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams <[email protected]>
1 parent 7d3eb23 commit 48667f6

File tree

5 files changed

+114
-126
lines changed

5 files changed

+114
-126
lines changed

drivers/cxl/acpi.c

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ static void cxl_add_cfmws_decoders(struct device *dev,
8282
struct cxl_decoder *cxld;
8383
acpi_size len, cur = 0;
8484
void *cedt_subtable;
85-
unsigned long flags;
8685
int rc;
8786

8887
len = acpi_cedt->length - sizeof(*acpi_cedt);
@@ -119,24 +118,36 @@ static void cxl_add_cfmws_decoders(struct device *dev,
119118
for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++)
120119
target_map[i] = cfmws->interleave_targets[i];
121120

122-
flags = cfmws_to_decoder_flags(cfmws->restrictions);
123-
cxld = devm_cxl_add_decoder(dev, root_port,
124-
CFMWS_INTERLEAVE_WAYS(cfmws),
125-
cfmws->base_hpa, cfmws->window_size,
126-
CFMWS_INTERLEAVE_WAYS(cfmws),
127-
CFMWS_INTERLEAVE_GRANULARITY(cfmws),
128-
CXL_DECODER_EXPANDER,
129-
flags, target_map);
130-
131-
if (IS_ERR(cxld)) {
121+
cxld = cxl_decoder_alloc(root_port,
122+
CFMWS_INTERLEAVE_WAYS(cfmws));
123+
if (IS_ERR(cxld))
124+
goto next;
125+
126+
cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
127+
cxld->target_type = CXL_DECODER_EXPANDER;
128+
cxld->range = (struct range) {
129+
.start = cfmws->base_hpa,
130+
.end = cfmws->base_hpa + cfmws->window_size - 1,
131+
};
132+
cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws);
133+
cxld->interleave_granularity =
134+
CFMWS_INTERLEAVE_GRANULARITY(cfmws);
135+
136+
rc = cxl_decoder_add(cxld, target_map);
137+
if (rc)
138+
put_device(&cxld->dev);
139+
else
140+
rc = cxl_decoder_autoremove(dev, cxld);
141+
if (rc) {
132142
dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
133143
cfmws->base_hpa, cfmws->base_hpa +
134144
cfmws->window_size - 1);
135-
} else {
136-
dev_dbg(dev, "add: %s range %#llx-%#llx\n",
137-
dev_name(&cxld->dev), cfmws->base_hpa,
138-
cfmws->base_hpa + cfmws->window_size - 1);
145+
goto next;
139146
}
147+
dev_dbg(dev, "add: %s range %#llx-%#llx\n",
148+
dev_name(&cxld->dev), cfmws->base_hpa,
149+
cfmws->base_hpa + cfmws->window_size - 1);
150+
next:
140151
cur += c->length;
141152
}
142153
}
@@ -266,6 +277,7 @@ static int add_host_bridge_uport(struct device *match, void *arg)
266277
struct acpi_device *bridge = to_cxl_host_bridge(host, match);
267278
struct acpi_pci_root *pci_root;
268279
struct cxl_walk_context ctx;
280+
int single_port_map[1], rc;
269281
struct cxl_decoder *cxld;
270282
struct cxl_dport *dport;
271283
struct cxl_port *port;
@@ -301,22 +313,46 @@ static int add_host_bridge_uport(struct device *match, void *arg)
301313
return -ENODEV;
302314
if (ctx.error)
303315
return ctx.error;
316+
if (ctx.count > 1)
317+
return 0;
304318

305319
/* TODO: Scan CHBCR for HDM Decoder resources */
306320

307321
/*
308-
* In the single-port host-bridge case there are no HDM decoders
309-
* in the CHBCR and a 1:1 passthrough decode is implied.
322+
* Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability
323+
* Structure) single ported host-bridges need not publish a decoder
324+
* capability when a passthrough decode can be assumed, i.e. all
325+
* transactions that the uport sees are claimed and passed to the single
326+
* dport. Disable the range until the first CXL region is enumerated /
327+
* activated.
310328
*/
311-
if (ctx.count == 1) {
312-
cxld = devm_cxl_add_passthrough_decoder(host, port);
313-
if (IS_ERR(cxld))
314-
return PTR_ERR(cxld);
329+
cxld = cxl_decoder_alloc(port, 1);
330+
if (IS_ERR(cxld))
331+
return PTR_ERR(cxld);
332+
333+
cxld->interleave_ways = 1;
334+
cxld->interleave_granularity = PAGE_SIZE;
335+
cxld->target_type = CXL_DECODER_EXPANDER;
336+
cxld->range = (struct range) {
337+
.start = 0,
338+
.end = -1,
339+
};
315340

316-
dev_dbg(host, "add: %s\n", dev_name(&cxld->dev));
317-
}
341+
device_lock(&port->dev);
342+
dport = list_first_entry(&port->dports, typeof(*dport), list);
343+
device_unlock(&port->dev);
318344

319-
return 0;
345+
single_port_map[0] = dport->port_id;
346+
347+
rc = cxl_decoder_add(cxld, single_port_map);
348+
if (rc)
349+
put_device(&cxld->dev);
350+
else
351+
rc = cxl_decoder_autoremove(host, cxld);
352+
353+
if (rc == 0)
354+
dev_dbg(host, "add: %s\n", dev_name(&cxld->dev));
355+
return rc;
320356
}
321357

322358
static int add_host_bridge_dport(struct device *match, void *arg)

drivers/cxl/core/bus.c

Lines changed: 42 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -453,77 +453,57 @@ int cxl_add_dport(struct cxl_port *port, struct device *dport_dev, int port_id,
453453
}
454454
EXPORT_SYMBOL_GPL(cxl_add_dport);
455455

456-
static int decoder_populate_targets(struct device *host,
457-
struct cxl_decoder *cxld,
458-
struct cxl_port *port, int *target_map,
459-
int nr_targets)
456+
static int decoder_populate_targets(struct cxl_decoder *cxld,
457+
struct cxl_port *port, int *target_map)
460458
{
461459
int rc = 0, i;
462460

463461
if (!target_map)
464462
return 0;
465463

466464
device_lock(&port->dev);
467-
for (i = 0; i < nr_targets; i++) {
465+
if (list_empty(&port->dports)) {
466+
rc = -EINVAL;
467+
goto out_unlock;
468+
}
469+
470+
for (i = 0; i < cxld->nr_targets; i++) {
468471
struct cxl_dport *dport = find_dport(port, target_map[i]);
469472

470473
if (!dport) {
471474
rc = -ENXIO;
472-
break;
475+
goto out_unlock;
473476
}
474-
dev_dbg(host, "%s: target: %d\n", dev_name(dport->dport), i);
475477
cxld->target[i] = dport;
476478
}
479+
480+
out_unlock:
477481
device_unlock(&port->dev);
478482

479483
return rc;
480484
}
481485

482-
static struct cxl_decoder *
483-
cxl_decoder_alloc(struct device *host, struct cxl_port *port, int nr_targets,
484-
resource_size_t base, resource_size_t len,
485-
int interleave_ways, int interleave_granularity,
486-
enum cxl_decoder_type type, unsigned long flags,
487-
int *target_map)
486+
struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets)
488487
{
489-
struct cxl_decoder *cxld;
488+
struct cxl_decoder *cxld, cxld_const_init = {
489+
.nr_targets = nr_targets,
490+
};
490491
struct device *dev;
491492
int rc = 0;
492493

493-
if (interleave_ways < 1)
494+
if (nr_targets > CXL_DECODER_MAX_INTERLEAVE || nr_targets < 1)
494495
return ERR_PTR(-EINVAL);
495496

496-
device_lock(&port->dev);
497-
if (list_empty(&port->dports))
498-
rc = -EINVAL;
499-
device_unlock(&port->dev);
500-
if (rc)
501-
return ERR_PTR(rc);
502-
503497
cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL);
504498
if (!cxld)
505499
return ERR_PTR(-ENOMEM);
500+
memcpy(cxld, &cxld_const_init, sizeof(cxld_const_init));
506501

507502
rc = ida_alloc(&port->decoder_ida, GFP_KERNEL);
508503
if (rc < 0)
509504
goto err;
510505

511-
*cxld = (struct cxl_decoder) {
512-
.id = rc,
513-
.range = {
514-
.start = base,
515-
.end = base + len - 1,
516-
},
517-
.flags = flags,
518-
.interleave_ways = interleave_ways,
519-
.interleave_granularity = interleave_granularity,
520-
.target_type = type,
521-
};
522-
523-
rc = decoder_populate_targets(host, cxld, port, target_map, nr_targets);
524-
if (rc)
525-
goto err;
526-
506+
cxld->id = rc;
527507
dev = &cxld->dev;
528508
device_initialize(dev);
529509
device_set_pm_not_required(dev);
@@ -541,72 +521,47 @@ cxl_decoder_alloc(struct device *host, struct cxl_port *port, int nr_targets,
541521
kfree(cxld);
542522
return ERR_PTR(rc);
543523
}
524+
EXPORT_SYMBOL_GPL(cxl_decoder_alloc);
544525

545-
struct cxl_decoder *
546-
devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets,
547-
resource_size_t base, resource_size_t len,
548-
int interleave_ways, int interleave_granularity,
549-
enum cxl_decoder_type type, unsigned long flags,
550-
int *target_map)
526+
int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
551527
{
552-
struct cxl_decoder *cxld;
528+
struct cxl_port *port;
553529
struct device *dev;
554530
int rc;
555531

556-
if (nr_targets > CXL_DECODER_MAX_INTERLEAVE)
557-
return ERR_PTR(-EINVAL);
532+
if (WARN_ON_ONCE(!cxld))
533+
return -EINVAL;
558534

559-
cxld = cxl_decoder_alloc(host, port, nr_targets, base, len,
560-
interleave_ways, interleave_granularity, type,
561-
flags, target_map);
562-
if (IS_ERR(cxld))
563-
return cxld;
535+
if (WARN_ON_ONCE(IS_ERR(cxld)))
536+
return PTR_ERR(cxld);
564537

565-
dev = &cxld->dev;
566-
rc = dev_set_name(dev, "decoder%d.%d", port->id, cxld->id);
567-
if (rc)
568-
goto err;
538+
if (cxld->interleave_ways < 1)
539+
return -EINVAL;
569540

570-
rc = device_add(dev);
541+
port = to_cxl_port(cxld->dev.parent);
542+
rc = decoder_populate_targets(cxld, port, target_map);
571543
if (rc)
572-
goto err;
544+
return rc;
573545

574-
rc = devm_add_action_or_reset(host, unregister_cxl_dev, dev);
546+
dev = &cxld->dev;
547+
rc = dev_set_name(dev, "decoder%d.%d", port->id, cxld->id);
575548
if (rc)
576-
return ERR_PTR(rc);
577-
return cxld;
549+
return rc;
578550

579-
err:
580-
put_device(dev);
581-
return ERR_PTR(rc);
551+
return device_add(dev);
582552
}
583-
EXPORT_SYMBOL_GPL(devm_cxl_add_decoder);
553+
EXPORT_SYMBOL_GPL(cxl_decoder_add);
584554

585-
/*
586-
* Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure)
587-
* single ported host-bridges need not publish a decoder capability when a
588-
* passthrough decode can be assumed, i.e. all transactions that the uport sees
589-
* are claimed and passed to the single dport. Default the range a 0-base
590-
* 0-length until the first CXL region is activated.
591-
*/
592-
struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host,
593-
struct cxl_port *port)
555+
static void cxld_unregister(void *dev)
594556
{
595-
struct cxl_dport *dport;
596-
int target_map[1];
597-
598-
device_lock(&port->dev);
599-
dport = list_first_entry_or_null(&port->dports, typeof(*dport), list);
600-
device_unlock(&port->dev);
601-
602-
if (!dport)
603-
return ERR_PTR(-ENXIO);
557+
device_unregister(dev);
558+
}
604559

605-
target_map[0] = dport->port_id;
606-
return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE,
607-
CXL_DECODER_EXPANDER, 0, target_map);
560+
int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld)
561+
{
562+
return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev);
608563
}
609-
EXPORT_SYMBOL_GPL(devm_cxl_add_passthrough_decoder);
564+
EXPORT_SYMBOL_GPL(cxl_decoder_autoremove);
610565

611566
/**
612567
* __cxl_driver_register - register a driver for the cxl bus

drivers/cxl/core/core.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ extern const struct device_type cxl_nvdimm_type;
99

1010
extern struct attribute_group cxl_base_attribute_group;
1111

12-
static inline void unregister_cxl_dev(void *dev)
13-
{
14-
device_unregister(dev);
15-
}
16-
1712
struct cxl_send_command;
1813
struct cxl_mem_query_commands;
1914
int cxl_query_cmd(struct cxl_memdev *cxlmd,

drivers/cxl/core/pmem.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd)
222222
return cxl_nvd;
223223
}
224224

225+
static void cxl_nvd_unregister(void *dev)
226+
{
227+
device_unregister(dev);
228+
}
229+
225230
/**
226231
* devm_cxl_add_nvdimm() - add a bridge between a cxl_memdev and an nvdimm
227232
* @host: same host as @cxlmd
@@ -251,7 +256,7 @@ int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd)
251256
dev_dbg(host, "%s: register %s\n", dev_name(dev->parent),
252257
dev_name(dev));
253258

254-
return devm_add_action_or_reset(host, unregister_cxl_dev, dev);
259+
return devm_add_action_or_reset(host, cxl_nvd_unregister, dev);
255260

256261
err:
257262
put_device(dev);

drivers/cxl/cxl.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ enum cxl_decoder_type {
195195
* @interleave_granularity: data stride per dport
196196
* @target_type: accelerator vs expander (type2 vs type3) selector
197197
* @flags: memory type capabilities and locking
198+
* @nr_targets: number of elements in @target
198199
* @target: active ordered target list in current decoder configuration
199200
*/
200201
struct cxl_decoder {
@@ -205,6 +206,7 @@ struct cxl_decoder {
205206
int interleave_granularity;
206207
enum cxl_decoder_type target_type;
207208
unsigned long flags;
209+
const int nr_targets;
208210
struct cxl_dport *target[];
209211
};
210212

@@ -286,15 +288,10 @@ int cxl_add_dport(struct cxl_port *port, struct device *dport, int port_id,
286288

287289
struct cxl_decoder *to_cxl_decoder(struct device *dev);
288290
bool is_root_decoder(struct device *dev);
289-
struct cxl_decoder *
290-
devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets,
291-
resource_size_t base, resource_size_t len,
292-
int interleave_ways, int interleave_granularity,
293-
enum cxl_decoder_type type, unsigned long flags,
294-
int *target_map);
295-
296-
struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host,
297-
struct cxl_port *port);
291+
struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets);
292+
int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
293+
int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);
294+
298295
extern struct bus_type cxl_bus_type;
299296

300297
struct cxl_driver {

0 commit comments

Comments
 (0)