Skip to content

Commit 6697b2c

Browse files
committed
nfit: fix multi-interface dimm handling, acpi6.1 compatibility
ACPI 6.1 clarified that multi-interface dimms require multiple control region entries (DCRs) per dimm. Previously we were assuming that a control region is only present when block-data-windows are present. This implementation was done with an eye to be compatibility with the looser ACPI 6.0 interpretation of this table. 1/ When coalescing the memory device (MEMDEV) tables for a single dimm, coalesce on device_handle rather than control region index. 2/ Whenever we disocver a control region with non-zero block windows re-scan for block-data-window (BDW) entries. We may need to revisit this if a DIMM ever implements a format interface outside of blk or pmem, but that is not on the foreseeable horizon. Cc: <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent 18558ca commit 6697b2c

File tree

1 file changed

+35
-36
lines changed

1 file changed

+35
-36
lines changed

drivers/acpi/nfit.c

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -469,37 +469,16 @@ static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
469469
nfit_mem->bdw = NULL;
470470
}
471471

472-
static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
472+
static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
473473
struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
474474
{
475475
u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
476476
struct nfit_memdev *nfit_memdev;
477477
struct nfit_flush *nfit_flush;
478-
struct nfit_dcr *nfit_dcr;
479478
struct nfit_bdw *nfit_bdw;
480479
struct nfit_idt *nfit_idt;
481480
u16 idt_idx, range_index;
482481

483-
list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
484-
if (nfit_dcr->dcr->region_index != dcr)
485-
continue;
486-
nfit_mem->dcr = nfit_dcr->dcr;
487-
break;
488-
}
489-
490-
if (!nfit_mem->dcr) {
491-
dev_dbg(acpi_desc->dev, "SPA %d missing:%s%s\n",
492-
spa->range_index, __to_nfit_memdev(nfit_mem)
493-
? "" : " MEMDEV", nfit_mem->dcr ? "" : " DCR");
494-
return -ENODEV;
495-
}
496-
497-
/*
498-
* We've found enough to create an nvdimm, optionally
499-
* find an associated BDW
500-
*/
501-
list_add(&nfit_mem->list, &acpi_desc->dimms);
502-
503482
list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
504483
if (nfit_bdw->bdw->region_index != dcr)
505484
continue;
@@ -508,12 +487,12 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
508487
}
509488

510489
if (!nfit_mem->bdw)
511-
return 0;
490+
return;
512491

513492
nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
514493

515494
if (!nfit_mem->spa_bdw)
516-
return 0;
495+
return;
517496

518497
range_index = nfit_mem->spa_bdw->range_index;
519498
list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
@@ -538,8 +517,6 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
538517
}
539518
break;
540519
}
541-
542-
return 0;
543520
}
544521

545522
static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
@@ -548,7 +525,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
548525
struct nfit_mem *nfit_mem, *found;
549526
struct nfit_memdev *nfit_memdev;
550527
int type = nfit_spa_type(spa);
551-
u16 dcr;
552528

553529
switch (type) {
554530
case NFIT_SPA_DCR:
@@ -559,14 +535,18 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
559535
}
560536

561537
list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
562-
int rc;
538+
struct nfit_dcr *nfit_dcr;
539+
u32 device_handle;
540+
u16 dcr;
563541

564542
if (nfit_memdev->memdev->range_index != spa->range_index)
565543
continue;
566544
found = NULL;
567545
dcr = nfit_memdev->memdev->region_index;
546+
device_handle = nfit_memdev->memdev->device_handle;
568547
list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
569-
if (__to_nfit_memdev(nfit_mem)->region_index == dcr) {
548+
if (__to_nfit_memdev(nfit_mem)->device_handle
549+
== device_handle) {
570550
found = nfit_mem;
571551
break;
572552
}
@@ -579,6 +559,31 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
579559
if (!nfit_mem)
580560
return -ENOMEM;
581561
INIT_LIST_HEAD(&nfit_mem->list);
562+
list_add(&nfit_mem->list, &acpi_desc->dimms);
563+
}
564+
565+
list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
566+
if (nfit_dcr->dcr->region_index != dcr)
567+
continue;
568+
/*
569+
* Record the control region for the dimm. For
570+
* the ACPI 6.1 case, where there are separate
571+
* control regions for the pmem vs blk
572+
* interfaces, be sure to record the extended
573+
* blk details.
574+
*/
575+
if (!nfit_mem->dcr)
576+
nfit_mem->dcr = nfit_dcr->dcr;
577+
else if (nfit_mem->dcr->windows == 0
578+
&& nfit_dcr->dcr->windows)
579+
nfit_mem->dcr = nfit_dcr->dcr;
580+
break;
581+
}
582+
583+
if (dcr && !nfit_mem->dcr) {
584+
dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
585+
spa->range_index, dcr);
586+
return -ENODEV;
582587
}
583588

584589
if (type == NFIT_SPA_DCR) {
@@ -595,6 +600,7 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
595600
nfit_mem->idt_dcr = nfit_idt->idt;
596601
break;
597602
}
603+
nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
598604
} else {
599605
/*
600606
* A single dimm may belong to multiple SPA-PM
@@ -603,13 +609,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
603609
*/
604610
nfit_mem->memdev_pmem = nfit_memdev->memdev;
605611
}
606-
607-
if (found)
608-
continue;
609-
610-
rc = nfit_mem_add(acpi_desc, nfit_mem, spa);
611-
if (rc)
612-
return rc;
613612
}
614613

615614
return 0;

0 commit comments

Comments
 (0)