Skip to content

Commit 16c7a36

Browse files
committed
Merge tag 'cxl-fixes-for-6.1-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
Pull cxl fixes from Dan Williams: "Several fixes for CXL region creation crashes, leaks and failures. This is mainly fallout from the original implementation of dynamic CXL region creation (instantiate new physical memory pools) that arrived in v6.0-rc1. Given the theme of "failures in the presence of pass-through decoders" this also includes new regression test infrastructure for that case. Summary: - Fix region creation crash with pass-through decoders - Fix region creation crash when no decoder allocation fails - Fix region creation crash when scanning regions to enforce the increasing physical address order constraint that CXL mandates - Fix a memory leak for cxl_pmem_region objects, track 1:N instead of 1:1 memory-device-to-region associations. - Fix a memory leak for cxl_region objects when regions with active targets are deleted - Fix assignment of NUMA nodes to CXL regions by CFMWS (CXL Window) emulated proximity domains. - Fix region creation failure for switch attached devices downstream of a single-port host-bridge - Fix false positive memory leak of cxl_region objects by recycling recently used region ids rather than freeing them - Add regression test infrastructure for a pass-through decoder configuration - Fix some mailbox payload handling corner cases" * tag 'cxl-fixes-for-6.1-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: cxl/region: Recycle region ids cxl/region: Fix 'distance' calculation with passthrough ports tools/testing/cxl: Add a single-port host-bridge regression config tools/testing/cxl: Fix some error exits cxl/pmem: Fix cxl_pmem_region and cxl_memdev leak cxl/region: Fix cxl_region leak, cleanup targets at region delete cxl/region: Fix region HPA ordering validation cxl/pmem: Use size_add() against integer overflow cxl/region: Fix decoder allocation crash ACPI: NUMA: Add CXL CFMWS 'nodes' to the possible nodes set cxl/pmem: Fix failure to account for 8 byte header for writes to the device LSA. cxl/region: Fix null pointer dereference due to pass through decoder commit cxl/mbox: Add a check on input payload size
2 parents aa52994 + 8f401ec commit 16c7a36

File tree

8 files changed

+448
-91
lines changed

8 files changed

+448
-91
lines changed

drivers/acpi/numa/srat.c

+1
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
327327
pr_warn("ACPI NUMA: Failed to add memblk for CFMWS node %d [mem %#llx-%#llx]\n",
328328
node, start, end);
329329
}
330+
node_set(node, numa_nodes_parsed);
330331

331332
/* Set the next available fake_pxm value */
332333
(*fake_pxm)++;

drivers/cxl/core/mbox.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ int cxl_mbox_send_cmd(struct cxl_dev_state *cxlds, u16 opcode, void *in,
174174
};
175175
int rc;
176176

177-
if (out_size > cxlds->payload_size)
177+
if (in_size > cxlds->payload_size || out_size > cxlds->payload_size)
178178
return -E2BIG;
179179

180180
rc = cxlds->mbox_send(cxlds, &mbox_cmd);

drivers/cxl/core/pmem.c

+2
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ static void cxl_nvdimm_release(struct device *dev)
188188
{
189189
struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
190190

191+
xa_destroy(&cxl_nvd->pmem_regions);
191192
kfree(cxl_nvd);
192193
}
193194

@@ -230,6 +231,7 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd)
230231

231232
dev = &cxl_nvd->dev;
232233
cxl_nvd->cxlmd = cxlmd;
234+
xa_init(&cxl_nvd->pmem_regions);
233235
device_initialize(dev);
234236
lockdep_set_class(&dev->mutex, &cxl_nvdimm_key);
235237
device_set_pm_not_required(dev);

drivers/cxl/core/port.c

+9-2
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,7 @@ static struct cxl_dport *find_dport(struct cxl_port *port, int id)
811811
static int add_dport(struct cxl_port *port, struct cxl_dport *new)
812812
{
813813
struct cxl_dport *dup;
814+
int rc;
814815

815816
device_lock_assert(&port->dev);
816817
dup = find_dport(port, new->port_id);
@@ -821,8 +822,14 @@ static int add_dport(struct cxl_port *port, struct cxl_dport *new)
821822
dev_name(dup->dport));
822823
return -EBUSY;
823824
}
824-
return xa_insert(&port->dports, (unsigned long)new->dport, new,
825-
GFP_KERNEL);
825+
826+
rc = xa_insert(&port->dports, (unsigned long)new->dport, new,
827+
GFP_KERNEL);
828+
if (rc)
829+
return rc;
830+
831+
port->nr_dports++;
832+
return 0;
826833
}
827834

828835
/*

drivers/cxl/core/region.c

+85-28
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr)
174174
iter = to_cxl_port(iter->dev.parent)) {
175175
cxl_rr = cxl_rr_load(iter, cxlr);
176176
cxld = cxl_rr->decoder;
177-
rc = cxld->commit(cxld);
177+
if (cxld->commit)
178+
rc = cxld->commit(cxld);
178179
if (rc)
179180
break;
180181
}
@@ -657,6 +658,9 @@ static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port,
657658
xa_for_each(&port->regions, index, iter) {
658659
struct cxl_region_params *ip = &iter->region->params;
659660

661+
if (!ip->res)
662+
continue;
663+
660664
if (ip->res->start > p->res->start) {
661665
dev_dbg(&cxlr->dev,
662666
"%s: HPA order violation %s:%pr vs %pr\n",
@@ -686,18 +690,27 @@ static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port,
686690
return cxl_rr;
687691
}
688692

689-
static void free_region_ref(struct cxl_region_ref *cxl_rr)
693+
static void cxl_rr_free_decoder(struct cxl_region_ref *cxl_rr)
690694
{
691-
struct cxl_port *port = cxl_rr->port;
692695
struct cxl_region *cxlr = cxl_rr->region;
693696
struct cxl_decoder *cxld = cxl_rr->decoder;
694697

698+
if (!cxld)
699+
return;
700+
695701
dev_WARN_ONCE(&cxlr->dev, cxld->region != cxlr, "region mismatch\n");
696702
if (cxld->region == cxlr) {
697703
cxld->region = NULL;
698704
put_device(&cxlr->dev);
699705
}
706+
}
700707

708+
static void free_region_ref(struct cxl_region_ref *cxl_rr)
709+
{
710+
struct cxl_port *port = cxl_rr->port;
711+
struct cxl_region *cxlr = cxl_rr->region;
712+
713+
cxl_rr_free_decoder(cxl_rr);
701714
xa_erase(&port->regions, (unsigned long)cxlr);
702715
xa_destroy(&cxl_rr->endpoints);
703716
kfree(cxl_rr);
@@ -728,6 +741,33 @@ static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr,
728741
return 0;
729742
}
730743

744+
static int cxl_rr_alloc_decoder(struct cxl_port *port, struct cxl_region *cxlr,
745+
struct cxl_endpoint_decoder *cxled,
746+
struct cxl_region_ref *cxl_rr)
747+
{
748+
struct cxl_decoder *cxld;
749+
750+
if (port == cxled_to_port(cxled))
751+
cxld = &cxled->cxld;
752+
else
753+
cxld = cxl_region_find_decoder(port, cxlr);
754+
if (!cxld) {
755+
dev_dbg(&cxlr->dev, "%s: no decoder available\n",
756+
dev_name(&port->dev));
757+
return -EBUSY;
758+
}
759+
760+
if (cxld->region) {
761+
dev_dbg(&cxlr->dev, "%s: %s already attached to %s\n",
762+
dev_name(&port->dev), dev_name(&cxld->dev),
763+
dev_name(&cxld->region->dev));
764+
return -EBUSY;
765+
}
766+
767+
cxl_rr->decoder = cxld;
768+
return 0;
769+
}
770+
731771
/**
732772
* cxl_port_attach_region() - track a region's interest in a port by endpoint
733773
* @port: port to add a new region reference 'struct cxl_region_ref'
@@ -794,12 +834,6 @@ static int cxl_port_attach_region(struct cxl_port *port,
794834
cxl_rr->nr_targets++;
795835
nr_targets_inc = true;
796836
}
797-
798-
/*
799-
* The decoder for @cxlr was allocated when the region was first
800-
* attached to @port.
801-
*/
802-
cxld = cxl_rr->decoder;
803837
} else {
804838
cxl_rr = alloc_region_ref(port, cxlr);
805839
if (IS_ERR(cxl_rr)) {
@@ -810,26 +844,11 @@ static int cxl_port_attach_region(struct cxl_port *port,
810844
}
811845
nr_targets_inc = true;
812846

813-
if (port == cxled_to_port(cxled))
814-
cxld = &cxled->cxld;
815-
else
816-
cxld = cxl_region_find_decoder(port, cxlr);
817-
if (!cxld) {
818-
dev_dbg(&cxlr->dev, "%s: no decoder available\n",
819-
dev_name(&port->dev));
820-
goto out_erase;
821-
}
822-
823-
if (cxld->region) {
824-
dev_dbg(&cxlr->dev, "%s: %s already attached to %s\n",
825-
dev_name(&port->dev), dev_name(&cxld->dev),
826-
dev_name(&cxld->region->dev));
827-
rc = -EBUSY;
847+
rc = cxl_rr_alloc_decoder(port, cxlr, cxled, cxl_rr);
848+
if (rc)
828849
goto out_erase;
829-
}
830-
831-
cxl_rr->decoder = cxld;
832850
}
851+
cxld = cxl_rr->decoder;
833852

834853
rc = cxl_rr_ep_add(cxl_rr, cxled);
835854
if (rc) {
@@ -971,7 +990,14 @@ static int cxl_port_setup_targets(struct cxl_port *port,
971990
if (cxl_rr->nr_targets_set) {
972991
int i, distance;
973992

974-
distance = p->nr_targets / cxl_rr->nr_targets;
993+
/*
994+
* Passthrough ports impose no distance requirements between
995+
* peers
996+
*/
997+
if (port->nr_dports == 1)
998+
distance = 0;
999+
else
1000+
distance = p->nr_targets / cxl_rr->nr_targets;
9751001
for (i = 0; i < cxl_rr->nr_targets_set; i++)
9761002
if (ep->dport == cxlsd->target[i]) {
9771003
rc = check_last_peer(cxled, ep, cxl_rr,
@@ -1508,9 +1534,24 @@ static const struct attribute_group *region_groups[] = {
15081534

15091535
static void cxl_region_release(struct device *dev)
15101536
{
1537+
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev->parent);
15111538
struct cxl_region *cxlr = to_cxl_region(dev);
1539+
int id = atomic_read(&cxlrd->region_id);
1540+
1541+
/*
1542+
* Try to reuse the recently idled id rather than the cached
1543+
* next id to prevent the region id space from increasing
1544+
* unnecessarily.
1545+
*/
1546+
if (cxlr->id < id)
1547+
if (atomic_try_cmpxchg(&cxlrd->region_id, &id, cxlr->id)) {
1548+
memregion_free(id);
1549+
goto out;
1550+
}
15121551

15131552
memregion_free(cxlr->id);
1553+
out:
1554+
put_device(dev->parent);
15141555
kfree(cxlr);
15151556
}
15161557

@@ -1538,8 +1579,19 @@ static struct cxl_region *to_cxl_region(struct device *dev)
15381579
static void unregister_region(void *dev)
15391580
{
15401581
struct cxl_region *cxlr = to_cxl_region(dev);
1582+
struct cxl_region_params *p = &cxlr->params;
1583+
int i;
15411584

15421585
device_del(dev);
1586+
1587+
/*
1588+
* Now that region sysfs is shutdown, the parameter block is now
1589+
* read-only, so no need to hold the region rwsem to access the
1590+
* region parameters.
1591+
*/
1592+
for (i = 0; i < p->interleave_ways; i++)
1593+
detach_target(cxlr, i);
1594+
15431595
cxl_region_iomem_release(cxlr);
15441596
put_device(dev);
15451597
}
@@ -1561,6 +1613,11 @@ static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int i
15611613
device_initialize(dev);
15621614
lockdep_set_class(&dev->mutex, &cxl_region_key);
15631615
dev->parent = &cxlrd->cxlsd.cxld.dev;
1616+
/*
1617+
* Keep root decoder pinned through cxl_region_release to fixup
1618+
* region id allocations
1619+
*/
1620+
get_device(dev->parent);
15641621
device_set_pm_not_required(dev);
15651622
dev->bus = &cxl_bus_type;
15661623
dev->type = &cxl_region_type;

drivers/cxl/cxl.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ struct cxl_nvdimm {
423423
struct device dev;
424424
struct cxl_memdev *cxlmd;
425425
struct cxl_nvdimm_bridge *bridge;
426-
struct cxl_pmem_region *region;
426+
struct xarray pmem_regions;
427427
};
428428

429429
struct cxl_pmem_region_mapping {
@@ -457,6 +457,7 @@ struct cxl_pmem_region {
457457
* @regions: cxl_region_ref instances, regions mapped by this port
458458
* @parent_dport: dport that points to this port in the parent
459459
* @decoder_ida: allocator for decoder ids
460+
* @nr_dports: number of entries in @dports
460461
* @hdm_end: track last allocated HDM decoder instance for allocation ordering
461462
* @commit_end: cursor to track highest committed decoder for commit ordering
462463
* @component_reg_phys: component register capability base address (optional)
@@ -475,6 +476,7 @@ struct cxl_port {
475476
struct xarray regions;
476477
struct cxl_dport *parent_dport;
477478
struct ida decoder_ida;
479+
int nr_dports;
478480
int hdm_end;
479481
int commit_end;
480482
resource_size_t component_reg_phys;

0 commit comments

Comments
 (0)