Skip to content

Commit ac389bc

Browse files
committed
Merge tag 'cxl-fixes-6.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
Pull cxl fixes from Dan Williams: "A collection of significant fixes for the CXL subsystem. The largest change in this set, that bordered on "new development", is the fix for the fact that the location of the new qos_class attribute did not match the Documentation. The fix ends up deleting more code than it added, and it has a new unit test to backstop basic errors in this interface going forward. So the "red-diff" and unit test saved the "rip it out and try again" response. In contrast, the new notification path for firmware reported CXL errors (CXL CPER notifications) has a locking context bug that can not be fixed with a red-diff. Given where the release cycle stands, it is not comfortable to squeeze in that fix in these waning days. So, that receives the "back it out and try again later" treatment. There is a regression fix in the code that establishes memory NUMA nodes for platform CXL regions. That has an ack from x86 folks. There are a couple more fixups for Linux to understand (reassemble) CXL regions instantiated by platform firmware. The policy around platforms that do not match host-physical-address with system-physical-address (i.e. systems that have an address translation mechanism between the address range reported in the ACPI CEDT.CFMWS and endpoint decoders) has been softened to abort driver load rather than teardown the memory range (can cause system hangs). Lastly, there is a robustness / regression fix for cases where the driver would previously continue in the face of error, and a fixup for PCI error notification handling. Summary: - Fix NUMA initialization from ACPI CEDT.CFMWS - Fix region assembly failures due to async init order - Fix / simplify export of qos_class information - Fix cxl_acpi initialization vs single-window-init failures - Fix handling of repeated 'pci_channel_io_frozen' notifications - Workaround platforms that violate host-physical-address == system-physical address assumptions - Defer CXL CPER notification handling to v6.9" * tag 'cxl-fixes-6.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: cxl/acpi: Fix load failures due to single window creation failure acpi/ghes: Remove CXL CPER notifications cxl/pci: Fix disabling memory if DVSEC CXL Range does not match a CFMWS window cxl/test: Add support for qos_class checking cxl: Fix sysfs export of qos_class for memdev cxl: Remove unnecessary type cast in cxl_qos_class_verify() cxl: Change 'struct cxl_memdev_state' *_perf_list to single 'struct cxl_dpa_perf' cxl/region: Allow out of order assembly of autodiscovered regions cxl/region: Handle endpoint decoders in cxl_region_find_decoder() x86/numa: Fix the sort compare func used in numa_fill_memblks() x86/numa: Fix the address overlap check in numa_fill_memblks() cxl/pci: Skip to handle RAS errors if CXL.mem device is detached
2 parents f2e367d + 5c6224b commit ac389bc

File tree

19 files changed

+289
-334
lines changed

19 files changed

+289
-334
lines changed

arch/x86/mm/numa.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,7 @@ static int __init cmp_memblk(const void *a, const void *b)
934934
const struct numa_memblk *ma = *(const struct numa_memblk **)a;
935935
const struct numa_memblk *mb = *(const struct numa_memblk **)b;
936936

937-
return ma->start - mb->start;
937+
return (ma->start > mb->start) - (ma->start < mb->start);
938938
}
939939

940940
static struct numa_memblk *numa_memblk_list[NR_NODE_MEMBLKS] __initdata;
@@ -944,14 +944,12 @@ static struct numa_memblk *numa_memblk_list[NR_NODE_MEMBLKS] __initdata;
944944
* @start: address to begin fill
945945
* @end: address to end fill
946946
*
947-
* Find and extend numa_meminfo memblks to cover the @start-@end
948-
* physical address range, such that the first memblk includes
949-
* @start, the last memblk includes @end, and any gaps in between
950-
* are filled.
947+
* Find and extend numa_meminfo memblks to cover the physical
948+
* address range @start-@end
951949
*
952950
* RETURNS:
953951
* 0 : Success
954-
* NUMA_NO_MEMBLK : No memblk exists in @start-@end range
952+
* NUMA_NO_MEMBLK : No memblks exist in address range @start-@end
955953
*/
956954

957955
int __init numa_fill_memblks(u64 start, u64 end)
@@ -963,17 +961,14 @@ int __init numa_fill_memblks(u64 start, u64 end)
963961

964962
/*
965963
* Create a list of pointers to numa_meminfo memblks that
966-
* overlap start, end. Exclude (start == bi->end) since
967-
* end addresses in both a CFMWS range and a memblk range
968-
* are exclusive.
969-
*
970-
* This list of pointers is used to make in-place changes
971-
* that fill out the numa_meminfo memblks.
964+
* overlap start, end. The list is used to make in-place
965+
* changes that fill out the numa_meminfo memblks.
972966
*/
973967
for (int i = 0; i < mi->nr_blks; i++) {
974968
struct numa_memblk *bi = &mi->blk[i];
975969

976-
if (start < bi->end && end >= bi->start) {
970+
if (memblock_addrs_overlap(start, end - start, bi->start,
971+
bi->end - bi->start)) {
977972
blk[count] = &mi->blk[i];
978973
count++;
979974
}

drivers/acpi/apei/ghes.c

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <linux/interrupt.h>
2727
#include <linux/timer.h>
2828
#include <linux/cper.h>
29-
#include <linux/cxl-event.h>
3029
#include <linux/platform_device.h>
3130
#include <linux/mutex.h>
3231
#include <linux/ratelimit.h>
@@ -674,52 +673,6 @@ static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
674673
schedule_work(&entry->work);
675674
}
676675

677-
/*
678-
* Only a single callback can be registered for CXL CPER events.
679-
*/
680-
static DECLARE_RWSEM(cxl_cper_rw_sem);
681-
static cxl_cper_callback cper_callback;
682-
683-
static void cxl_cper_post_event(enum cxl_event_type event_type,
684-
struct cxl_cper_event_rec *rec)
685-
{
686-
if (rec->hdr.length <= sizeof(rec->hdr) ||
687-
rec->hdr.length > sizeof(*rec)) {
688-
pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n",
689-
rec->hdr.length);
690-
return;
691-
}
692-
693-
if (!(rec->hdr.validation_bits & CPER_CXL_COMP_EVENT_LOG_VALID)) {
694-
pr_err(FW_WARN "CXL CPER invalid event\n");
695-
return;
696-
}
697-
698-
guard(rwsem_read)(&cxl_cper_rw_sem);
699-
if (cper_callback)
700-
cper_callback(event_type, rec);
701-
}
702-
703-
int cxl_cper_register_callback(cxl_cper_callback callback)
704-
{
705-
guard(rwsem_write)(&cxl_cper_rw_sem);
706-
if (cper_callback)
707-
return -EINVAL;
708-
cper_callback = callback;
709-
return 0;
710-
}
711-
EXPORT_SYMBOL_NS_GPL(cxl_cper_register_callback, CXL);
712-
713-
int cxl_cper_unregister_callback(cxl_cper_callback callback)
714-
{
715-
guard(rwsem_write)(&cxl_cper_rw_sem);
716-
if (callback != cper_callback)
717-
return -EINVAL;
718-
cper_callback = NULL;
719-
return 0;
720-
}
721-
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_callback, CXL);
722-
723676
static bool ghes_do_proc(struct ghes *ghes,
724677
const struct acpi_hest_generic_status *estatus)
725678
{
@@ -754,22 +707,6 @@ static bool ghes_do_proc(struct ghes *ghes,
754707
}
755708
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
756709
queued = ghes_handle_arm_hw_error(gdata, sev, sync);
757-
} else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
758-
struct cxl_cper_event_rec *rec =
759-
acpi_hest_get_payload(gdata);
760-
761-
cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec);
762-
} else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) {
763-
struct cxl_cper_event_rec *rec =
764-
acpi_hest_get_payload(gdata);
765-
766-
cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec);
767-
} else if (guid_equal(sec_type,
768-
&CPER_SEC_CXL_MEM_MODULE_GUID)) {
769-
struct cxl_cper_event_rec *rec =
770-
acpi_hest_get_payload(gdata);
771-
772-
cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec);
773710
} else {
774711
void *err = acpi_hest_get_payload(gdata);
775712

drivers/cxl/acpi.c

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -316,31 +316,27 @@ static const struct cxl_root_ops acpi_root_ops = {
316316
.qos_class = cxl_acpi_qos_class,
317317
};
318318

319-
static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
320-
const unsigned long end)
319+
static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
320+
struct cxl_cfmws_context *ctx)
321321
{
322322
int target_map[CXL_DECODER_MAX_INTERLEAVE];
323-
struct cxl_cfmws_context *ctx = arg;
324323
struct cxl_port *root_port = ctx->root_port;
325324
struct resource *cxl_res = ctx->cxl_res;
326325
struct cxl_cxims_context cxims_ctx;
327326
struct cxl_root_decoder *cxlrd;
328327
struct device *dev = ctx->dev;
329-
struct acpi_cedt_cfmws *cfmws;
330328
cxl_calc_hb_fn cxl_calc_hb;
331329
struct cxl_decoder *cxld;
332330
unsigned int ways, i, ig;
333331
struct resource *res;
334332
int rc;
335333

336-
cfmws = (struct acpi_cedt_cfmws *) header;
337-
338334
rc = cxl_acpi_cfmws_verify(dev, cfmws);
339335
if (rc) {
340336
dev_err(dev, "CFMWS range %#llx-%#llx not registered\n",
341337
cfmws->base_hpa,
342338
cfmws->base_hpa + cfmws->window_size - 1);
343-
return 0;
339+
return rc;
344340
}
345341

346342
rc = eiw_to_ways(cfmws->interleave_ways, &ways);
@@ -376,7 +372,7 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
376372

377373
cxlrd = cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb);
378374
if (IS_ERR(cxlrd))
379-
return 0;
375+
return PTR_ERR(cxlrd);
380376

381377
cxld = &cxlrd->cxlsd.cxld;
382378
cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
@@ -420,16 +416,7 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
420416
put_device(&cxld->dev);
421417
else
422418
rc = cxl_decoder_autoremove(dev, cxld);
423-
if (rc) {
424-
dev_err(dev, "Failed to add decode range: %pr", res);
425-
return rc;
426-
}
427-
dev_dbg(dev, "add: %s node: %d range [%#llx - %#llx]\n",
428-
dev_name(&cxld->dev),
429-
phys_to_target_node(cxld->hpa_range.start),
430-
cxld->hpa_range.start, cxld->hpa_range.end);
431-
432-
return 0;
419+
return rc;
433420

434421
err_insert:
435422
kfree(res->name);
@@ -438,6 +425,29 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
438425
return -ENOMEM;
439426
}
440427

428+
static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
429+
const unsigned long end)
430+
{
431+
struct acpi_cedt_cfmws *cfmws = (struct acpi_cedt_cfmws *)header;
432+
struct cxl_cfmws_context *ctx = arg;
433+
struct device *dev = ctx->dev;
434+
int rc;
435+
436+
rc = __cxl_parse_cfmws(cfmws, ctx);
437+
if (rc)
438+
dev_err(dev,
439+
"Failed to add decode range: [%#llx - %#llx] (%d)\n",
440+
cfmws->base_hpa,
441+
cfmws->base_hpa + cfmws->window_size - 1, rc);
442+
else
443+
dev_dbg(dev, "decode range: node: %d range [%#llx - %#llx]\n",
444+
phys_to_target_node(cfmws->base_hpa), cfmws->base_hpa,
445+
cfmws->base_hpa + cfmws->window_size - 1);
446+
447+
/* never fail cxl_acpi load for a single window failure */
448+
return 0;
449+
}
450+
441451
__mock struct acpi_device *to_cxl_host_bridge(struct device *host,
442452
struct device *dev)
443453
{

drivers/cxl/core/cdat.c

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -210,40 +210,19 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,
210210
return 0;
211211
}
212212

213-
static void add_perf_entry(struct device *dev, struct dsmas_entry *dent,
214-
struct list_head *list)
213+
static void update_perf_entry(struct device *dev, struct dsmas_entry *dent,
214+
struct cxl_dpa_perf *dpa_perf)
215215
{
216-
struct cxl_dpa_perf *dpa_perf;
217-
218-
dpa_perf = kzalloc(sizeof(*dpa_perf), GFP_KERNEL);
219-
if (!dpa_perf)
220-
return;
221-
222216
dpa_perf->dpa_range = dent->dpa_range;
223217
dpa_perf->coord = dent->coord;
224218
dpa_perf->qos_class = dent->qos_class;
225-
list_add_tail(&dpa_perf->list, list);
226219
dev_dbg(dev,
227220
"DSMAS: dpa: %#llx qos: %d read_bw: %d write_bw %d read_lat: %d write_lat: %d\n",
228221
dent->dpa_range.start, dpa_perf->qos_class,
229222
dent->coord.read_bandwidth, dent->coord.write_bandwidth,
230223
dent->coord.read_latency, dent->coord.write_latency);
231224
}
232225

233-
static void free_perf_ents(void *data)
234-
{
235-
struct cxl_memdev_state *mds = data;
236-
struct cxl_dpa_perf *dpa_perf, *n;
237-
LIST_HEAD(discard);
238-
239-
list_splice_tail_init(&mds->ram_perf_list, &discard);
240-
list_splice_tail_init(&mds->pmem_perf_list, &discard);
241-
list_for_each_entry_safe(dpa_perf, n, &discard, list) {
242-
list_del(&dpa_perf->list);
243-
kfree(dpa_perf);
244-
}
245-
}
246-
247226
static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
248227
struct xarray *dsmas_xa)
249228
{
@@ -263,16 +242,14 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
263242
xa_for_each(dsmas_xa, index, dent) {
264243
if (resource_size(&cxlds->ram_res) &&
265244
range_contains(&ram_range, &dent->dpa_range))
266-
add_perf_entry(dev, dent, &mds->ram_perf_list);
245+
update_perf_entry(dev, dent, &mds->ram_perf);
267246
else if (resource_size(&cxlds->pmem_res) &&
268247
range_contains(&pmem_range, &dent->dpa_range))
269-
add_perf_entry(dev, dent, &mds->pmem_perf_list);
248+
update_perf_entry(dev, dent, &mds->pmem_perf);
270249
else
271250
dev_dbg(dev, "no partition for dsmas dpa: %#llx\n",
272251
dent->dpa_range.start);
273252
}
274-
275-
devm_add_action_or_reset(&cxlds->cxlmd->dev, free_perf_ents, mds);
276253
}
277254

278255
static int match_cxlrd_qos_class(struct device *dev, void *data)
@@ -293,24 +270,24 @@ static int match_cxlrd_qos_class(struct device *dev, void *data)
293270
return 0;
294271
}
295272

296-
static void cxl_qos_match(struct cxl_port *root_port,
297-
struct list_head *work_list,
298-
struct list_head *discard_list)
273+
static void reset_dpa_perf(struct cxl_dpa_perf *dpa_perf)
299274
{
300-
struct cxl_dpa_perf *dpa_perf, *n;
275+
*dpa_perf = (struct cxl_dpa_perf) {
276+
.qos_class = CXL_QOS_CLASS_INVALID,
277+
};
278+
}
301279

302-
list_for_each_entry_safe(dpa_perf, n, work_list, list) {
303-
int rc;
280+
static bool cxl_qos_match(struct cxl_port *root_port,
281+
struct cxl_dpa_perf *dpa_perf)
282+
{
283+
if (dpa_perf->qos_class == CXL_QOS_CLASS_INVALID)
284+
return false;
304285

305-
if (dpa_perf->qos_class == CXL_QOS_CLASS_INVALID)
306-
return;
286+
if (!device_for_each_child(&root_port->dev, &dpa_perf->qos_class,
287+
match_cxlrd_qos_class))
288+
return false;
307289

308-
rc = device_for_each_child(&root_port->dev,
309-
(void *)&dpa_perf->qos_class,
310-
match_cxlrd_qos_class);
311-
if (!rc)
312-
list_move_tail(&dpa_perf->list, discard_list);
313-
}
290+
return true;
314291
}
315292

316293
static int match_cxlrd_hb(struct device *dev, void *data)
@@ -334,23 +311,10 @@ static int match_cxlrd_hb(struct device *dev, void *data)
334311
return 0;
335312
}
336313

337-
static void discard_dpa_perf(struct list_head *list)
338-
{
339-
struct cxl_dpa_perf *dpa_perf, *n;
340-
341-
list_for_each_entry_safe(dpa_perf, n, list, list) {
342-
list_del(&dpa_perf->list);
343-
kfree(dpa_perf);
344-
}
345-
}
346-
DEFINE_FREE(dpa_perf, struct list_head *, if (!list_empty(_T)) discard_dpa_perf(_T))
347-
348314
static int cxl_qos_class_verify(struct cxl_memdev *cxlmd)
349315
{
350316
struct cxl_dev_state *cxlds = cxlmd->cxlds;
351317
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
352-
LIST_HEAD(__discard);
353-
struct list_head *discard __free(dpa_perf) = &__discard;
354318
struct cxl_port *root_port;
355319
int rc;
356320

@@ -363,16 +327,17 @@ static int cxl_qos_class_verify(struct cxl_memdev *cxlmd)
363327
root_port = &cxl_root->port;
364328

365329
/* Check that the QTG IDs are all sane between end device and root decoders */
366-
cxl_qos_match(root_port, &mds->ram_perf_list, discard);
367-
cxl_qos_match(root_port, &mds->pmem_perf_list, discard);
330+
if (!cxl_qos_match(root_port, &mds->ram_perf))
331+
reset_dpa_perf(&mds->ram_perf);
332+
if (!cxl_qos_match(root_port, &mds->pmem_perf))
333+
reset_dpa_perf(&mds->pmem_perf);
368334

369335
/* Check to make sure that the device's host bridge is under a root decoder */
370336
rc = device_for_each_child(&root_port->dev,
371-
(void *)cxlmd->endpoint->host_bridge,
372-
match_cxlrd_hb);
337+
cxlmd->endpoint->host_bridge, match_cxlrd_hb);
373338
if (!rc) {
374-
list_splice_tail_init(&mds->ram_perf_list, discard);
375-
list_splice_tail_init(&mds->pmem_perf_list, discard);
339+
reset_dpa_perf(&mds->ram_perf);
340+
reset_dpa_perf(&mds->pmem_perf);
376341
}
377342

378343
return rc;
@@ -417,6 +382,7 @@ void cxl_endpoint_parse_cdat(struct cxl_port *port)
417382

418383
cxl_memdev_set_qos_class(cxlds, dsmas_xa);
419384
cxl_qos_class_verify(cxlmd);
385+
cxl_memdev_update_perf(cxlmd);
420386
}
421387
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL);
422388

drivers/cxl/core/mbox.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,8 +1391,8 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev)
13911391
mds->cxlds.reg_map.host = dev;
13921392
mds->cxlds.reg_map.resource = CXL_RESOURCE_NONE;
13931393
mds->cxlds.type = CXL_DEVTYPE_CLASSMEM;
1394-
INIT_LIST_HEAD(&mds->ram_perf_list);
1395-
INIT_LIST_HEAD(&mds->pmem_perf_list);
1394+
mds->ram_perf.qos_class = CXL_QOS_CLASS_INVALID;
1395+
mds->pmem_perf.qos_class = CXL_QOS_CLASS_INVALID;
13961396

13971397
return mds;
13981398
}

0 commit comments

Comments
 (0)