Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <lkp@intel.com>
Reported-by: Nathan Chancellor <nathan@kernel.org>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
Link: https://lore.kernel.org/r/163225205828.3038145.6831131648369404859.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+114 -126
+59 -23
drivers/cxl/acpi.c
··· 82 82 struct cxl_decoder *cxld; 83 83 acpi_size len, cur = 0; 84 84 void *cedt_subtable; 85 - unsigned long flags; 86 85 int rc; 87 86 88 87 len = acpi_cedt->length - sizeof(*acpi_cedt); ··· 118 119 for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++) 119 120 target_map[i] = cfmws->interleave_targets[i]; 120 121 121 - flags = cfmws_to_decoder_flags(cfmws->restrictions); 122 - cxld = devm_cxl_add_decoder(dev, root_port, 123 - CFMWS_INTERLEAVE_WAYS(cfmws), 124 - cfmws->base_hpa, cfmws->window_size, 125 - CFMWS_INTERLEAVE_WAYS(cfmws), 126 - CFMWS_INTERLEAVE_GRANULARITY(cfmws), 127 - CXL_DECODER_EXPANDER, 128 - flags, target_map); 122 + cxld = cxl_decoder_alloc(root_port, 123 + CFMWS_INTERLEAVE_WAYS(cfmws)); 124 + if (IS_ERR(cxld)) 125 + goto next; 129 126 130 - if (IS_ERR(cxld)) { 127 + cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions); 128 + cxld->target_type = CXL_DECODER_EXPANDER; 129 + cxld->range = (struct range) { 130 + .start = cfmws->base_hpa, 131 + .end = cfmws->base_hpa + cfmws->window_size - 1, 132 + }; 133 + cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws); 134 + cxld->interleave_granularity = 135 + CFMWS_INTERLEAVE_GRANULARITY(cfmws); 136 + 137 + rc = cxl_decoder_add(cxld, target_map); 138 + if (rc) 139 + put_device(&cxld->dev); 140 + else 141 + rc = cxl_decoder_autoremove(dev, cxld); 142 + if (rc) { 131 143 dev_err(dev, "Failed to add decoder for %#llx-%#llx\n", 132 144 cfmws->base_hpa, cfmws->base_hpa + 133 145 cfmws->window_size - 1); 134 - } else { 135 - dev_dbg(dev, "add: %s range %#llx-%#llx\n", 136 - dev_name(&cxld->dev), cfmws->base_hpa, 137 - cfmws->base_hpa + cfmws->window_size - 1); 146 + goto next; 138 147 } 148 + dev_dbg(dev, "add: %s range %#llx-%#llx\n", 149 + dev_name(&cxld->dev), cfmws->base_hpa, 150 + cfmws->base_hpa + cfmws->window_size - 1); 151 + next: 139 152 cur += c->length; 140 153 } 141 154 } ··· 277 266 struct acpi_device *bridge = to_cxl_host_bridge(host, match); 278 267 struct acpi_pci_root *pci_root; 279 268 struct cxl_walk_context ctx; 269 + int single_port_map[1], rc; 280 270 struct cxl_decoder *cxld; 281 271 struct cxl_dport *dport; 282 272 struct cxl_port *port; ··· 313 301 return -ENODEV; 314 302 if (ctx.error) 315 303 return ctx.error; 304 + if (ctx.count > 1) 305 + return 0; 316 306 317 307 /* TODO: Scan CHBCR for HDM Decoder resources */ 318 308 319 309 /* 320 - * In the single-port host-bridge case there are no HDM decoders 321 - * in the CHBCR and a 1:1 passthrough decode is implied. 310 + * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability 311 + * Structure) single ported host-bridges need not publish a decoder 312 + * capability when a passthrough decode can be assumed, i.e. all 313 + * transactions that the uport sees are claimed and passed to the single 314 + * dport. Disable the range until the first CXL region is enumerated / 315 + * activated. 322 316 */ 323 - if (ctx.count == 1) { 324 - cxld = devm_cxl_add_passthrough_decoder(host, port); 325 - if (IS_ERR(cxld)) 326 - return PTR_ERR(cxld); 317 + cxld = cxl_decoder_alloc(port, 1); 318 + if (IS_ERR(cxld)) 319 + return PTR_ERR(cxld); 327 320 321 + cxld->interleave_ways = 1; 322 + cxld->interleave_granularity = PAGE_SIZE; 323 + cxld->target_type = CXL_DECODER_EXPANDER; 324 + cxld->range = (struct range) { 325 + .start = 0, 326 + .end = -1, 327 + }; 328 + 329 + device_lock(&port->dev); 330 + dport = list_first_entry(&port->dports, typeof(*dport), list); 331 + device_unlock(&port->dev); 332 + 333 + single_port_map[0] = dport->port_id; 334 + 335 + rc = cxl_decoder_add(cxld, single_port_map); 336 + if (rc) 337 + put_device(&cxld->dev); 338 + else 339 + rc = cxl_decoder_autoremove(host, cxld); 340 + 341 + if (rc == 0) 328 342 dev_dbg(host, "add: %s\n", dev_name(&cxld->dev)); 329 - } 330 - 331 - return 0; 343 + return rc; 332 344 } 333 345 334 346 static int add_host_bridge_dport(struct device *match, void *arg)
+44 -89
drivers/cxl/core/bus.c
··· 453 453 } 454 454 EXPORT_SYMBOL_GPL(cxl_add_dport); 455 455 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) 460 458 { 461 459 int rc = 0, i; 462 460 ··· 462 464 return 0; 463 465 464 466 device_lock(&port->dev); 465 - for (i = 0; i < nr_targets; i++) { 467 + if (list_empty(&port->dports)) { 468 + rc = -EINVAL; 469 + goto out_unlock; 470 + } 471 + 472 + for (i = 0; i < cxld->nr_targets; i++) { 466 473 struct cxl_dport *dport = find_dport(port, target_map[i]); 467 474 468 475 if (!dport) { 469 476 rc = -ENXIO; 470 - break; 477 + goto out_unlock; 471 478 } 472 - dev_dbg(host, "%s: target: %d\n", dev_name(dport->dport), i); 473 479 cxld->target[i] = dport; 474 480 } 481 + 482 + out_unlock: 475 483 device_unlock(&port->dev); 476 484 477 485 return rc; 478 486 } 479 487 480 - static struct cxl_decoder * 481 - cxl_decoder_alloc(struct device *host, struct cxl_port *port, int nr_targets, 482 - resource_size_t base, resource_size_t len, 483 - int interleave_ways, int interleave_granularity, 484 - enum cxl_decoder_type type, unsigned long flags, 485 - int *target_map) 488 + struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets) 486 489 { 487 - struct cxl_decoder *cxld; 490 + struct cxl_decoder *cxld, cxld_const_init = { 491 + .nr_targets = nr_targets, 492 + }; 488 493 struct device *dev; 489 494 int rc = 0; 490 495 491 - if (interleave_ways < 1) 496 + if (nr_targets > CXL_DECODER_MAX_INTERLEAVE || nr_targets < 1) 492 497 return ERR_PTR(-EINVAL); 493 - 494 - device_lock(&port->dev); 495 - if (list_empty(&port->dports)) 496 - rc = -EINVAL; 497 - device_unlock(&port->dev); 498 - if (rc) 499 - return ERR_PTR(rc); 500 498 501 499 cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL); 502 500 if (!cxld) 503 501 return ERR_PTR(-ENOMEM); 502 + memcpy(cxld, &cxld_const_init, sizeof(cxld_const_init)); 504 503 505 504 rc = ida_alloc(&port->decoder_ida, GFP_KERNEL); 506 505 if (rc < 0) 507 506 goto err; 508 507 509 - *cxld = (struct cxl_decoder) { 510 - .id = rc, 511 - .range = { 512 - .start = base, 513 - .end = base + len - 1, 514 - }, 515 - .flags = flags, 516 - .interleave_ways = interleave_ways, 517 - .interleave_granularity = interleave_granularity, 518 - .target_type = type, 519 - }; 520 - 521 - rc = decoder_populate_targets(host, cxld, port, target_map, nr_targets); 522 - if (rc) 523 - goto err; 524 - 508 + cxld->id = rc; 525 509 dev = &cxld->dev; 526 510 device_initialize(dev); 527 511 device_set_pm_not_required(dev); ··· 521 541 kfree(cxld); 522 542 return ERR_PTR(rc); 523 543 } 544 + EXPORT_SYMBOL_GPL(cxl_decoder_alloc); 524 545 525 - struct cxl_decoder * 526 - devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, 527 - resource_size_t base, resource_size_t len, 528 - int interleave_ways, int interleave_granularity, 529 - enum cxl_decoder_type type, unsigned long flags, 530 - int *target_map) 546 + int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) 531 547 { 532 - struct cxl_decoder *cxld; 548 + struct cxl_port *port; 533 549 struct device *dev; 534 550 int rc; 535 551 536 - if (nr_targets > CXL_DECODER_MAX_INTERLEAVE) 537 - return ERR_PTR(-EINVAL); 552 + if (WARN_ON_ONCE(!cxld)) 553 + return -EINVAL; 538 554 539 - cxld = cxl_decoder_alloc(host, port, nr_targets, base, len, 540 - interleave_ways, interleave_granularity, type, 541 - flags, target_map); 542 - if (IS_ERR(cxld)) 543 - return cxld; 555 + if (WARN_ON_ONCE(IS_ERR(cxld))) 556 + return PTR_ERR(cxld); 557 + 558 + if (cxld->interleave_ways < 1) 559 + return -EINVAL; 560 + 561 + port = to_cxl_port(cxld->dev.parent); 562 + rc = decoder_populate_targets(cxld, port, target_map); 563 + if (rc) 564 + return rc; 544 565 545 566 dev = &cxld->dev; 546 567 rc = dev_set_name(dev, "decoder%d.%d", port->id, cxld->id); 547 568 if (rc) 548 - goto err; 569 + return rc; 549 570 550 - rc = device_add(dev); 551 - if (rc) 552 - goto err; 553 - 554 - rc = devm_add_action_or_reset(host, unregister_cxl_dev, dev); 555 - if (rc) 556 - return ERR_PTR(rc); 557 - return cxld; 558 - 559 - err: 560 - put_device(dev); 561 - return ERR_PTR(rc); 571 + return device_add(dev); 562 572 } 563 - EXPORT_SYMBOL_GPL(devm_cxl_add_decoder); 573 + EXPORT_SYMBOL_GPL(cxl_decoder_add); 564 574 565 - /* 566 - * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure) 567 - * single ported host-bridges need not publish a decoder capability when a 568 - * passthrough decode can be assumed, i.e. all transactions that the uport sees 569 - * are claimed and passed to the single dport. Default the range a 0-base 570 - * 0-length until the first CXL region is activated. 571 - */ 572 - struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host, 573 - struct cxl_port *port) 575 + static void cxld_unregister(void *dev) 574 576 { 575 - struct cxl_dport *dport; 576 - int target_map[1]; 577 - 578 - device_lock(&port->dev); 579 - dport = list_first_entry_or_null(&port->dports, typeof(*dport), list); 580 - device_unlock(&port->dev); 581 - 582 - if (!dport) 583 - return ERR_PTR(-ENXIO); 584 - 585 - target_map[0] = dport->port_id; 586 - return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE, 587 - CXL_DECODER_EXPANDER, 0, target_map); 577 + device_unregister(dev); 588 578 } 589 - EXPORT_SYMBOL_GPL(devm_cxl_add_passthrough_decoder); 579 + 580 + int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld) 581 + { 582 + return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev); 583 + } 584 + EXPORT_SYMBOL_GPL(cxl_decoder_autoremove); 590 585 591 586 /** 592 587 * __cxl_driver_register - register a driver for the cxl bus
-5
drivers/cxl/core/core.h
··· 9 9 10 10 extern struct attribute_group cxl_base_attribute_group; 11 11 12 - static inline void unregister_cxl_dev(void *dev) 13 - { 14 - device_unregister(dev); 15 - } 16 - 17 12 struct cxl_send_command; 18 13 struct cxl_mem_query_commands; 19 14 int cxl_query_cmd(struct cxl_memdev *cxlmd,
+6 -1
drivers/cxl/core/pmem.c
··· 222 222 return cxl_nvd; 223 223 } 224 224 225 + static void cxl_nvd_unregister(void *dev) 226 + { 227 + device_unregister(dev); 228 + } 229 + 225 230 /** 226 231 * devm_cxl_add_nvdimm() - add a bridge between a cxl_memdev and an nvdimm 227 232 * @host: same host as @cxlmd ··· 256 251 dev_dbg(host, "%s: register %s\n", dev_name(dev->parent), 257 252 dev_name(dev)); 258 253 259 - return devm_add_action_or_reset(host, unregister_cxl_dev, dev); 254 + return devm_add_action_or_reset(host, cxl_nvd_unregister, dev); 260 255 261 256 err: 262 257 put_device(dev);
+5 -8
drivers/cxl/cxl.h
··· 195 195 * @interleave_granularity: data stride per dport 196 196 * @target_type: accelerator vs expander (type2 vs type3) selector 197 197 * @flags: memory type capabilities and locking 198 + * @nr_targets: number of elements in @target 198 199 * @target: active ordered target list in current decoder configuration 199 200 */ 200 201 struct cxl_decoder { ··· 206 205 int interleave_granularity; 207 206 enum cxl_decoder_type target_type; 208 207 unsigned long flags; 208 + const int nr_targets; 209 209 struct cxl_dport *target[]; 210 210 }; 211 211 ··· 288 286 289 287 struct cxl_decoder *to_cxl_decoder(struct device *dev); 290 288 bool is_root_decoder(struct device *dev); 291 - struct cxl_decoder * 292 - devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, 293 - resource_size_t base, resource_size_t len, 294 - int interleave_ways, int interleave_granularity, 295 - enum cxl_decoder_type type, unsigned long flags, 296 - int *target_map); 289 + struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets); 290 + int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map); 291 + int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld); 297 292 298 - struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host, 299 - struct cxl_port *port); 300 293 extern struct bus_type cxl_bus_type; 301 294 302 295 struct cxl_driver {