Commit 6697b2cf authored by Dan Williams's avatar Dan Williams

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: <stable@vger.kernel.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 18558cae
...@@ -469,37 +469,16 @@ static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc, ...@@ -469,37 +469,16 @@ static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
nfit_mem->bdw = NULL; nfit_mem->bdw = NULL;
} }
static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc, static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa) struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
{ {
u16 dcr = __to_nfit_memdev(nfit_mem)->region_index; u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
struct nfit_memdev *nfit_memdev; struct nfit_memdev *nfit_memdev;
struct nfit_flush *nfit_flush; struct nfit_flush *nfit_flush;
struct nfit_dcr *nfit_dcr;
struct nfit_bdw *nfit_bdw; struct nfit_bdw *nfit_bdw;
struct nfit_idt *nfit_idt; struct nfit_idt *nfit_idt;
u16 idt_idx, range_index; u16 idt_idx, range_index;
list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
if (nfit_dcr->dcr->region_index != dcr)
continue;
nfit_mem->dcr = nfit_dcr->dcr;
break;
}
if (!nfit_mem->dcr) {
dev_dbg(acpi_desc->dev, "SPA %d missing:%s%s\n",
spa->range_index, __to_nfit_memdev(nfit_mem)
? "" : " MEMDEV", nfit_mem->dcr ? "" : " DCR");
return -ENODEV;
}
/*
* We've found enough to create an nvdimm, optionally
* find an associated BDW
*/
list_add(&nfit_mem->list, &acpi_desc->dimms);
list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) { list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
if (nfit_bdw->bdw->region_index != dcr) if (nfit_bdw->bdw->region_index != dcr)
continue; continue;
...@@ -508,12 +487,12 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc, ...@@ -508,12 +487,12 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
} }
if (!nfit_mem->bdw) if (!nfit_mem->bdw)
return 0; return;
nfit_mem_find_spa_bdw(acpi_desc, nfit_mem); nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
if (!nfit_mem->spa_bdw) if (!nfit_mem->spa_bdw)
return 0; return;
range_index = nfit_mem->spa_bdw->range_index; range_index = nfit_mem->spa_bdw->range_index;
list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) { 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, ...@@ -538,8 +517,6 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
} }
break; break;
} }
return 0;
} }
static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, 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, ...@@ -548,7 +525,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
struct nfit_mem *nfit_mem, *found; struct nfit_mem *nfit_mem, *found;
struct nfit_memdev *nfit_memdev; struct nfit_memdev *nfit_memdev;
int type = nfit_spa_type(spa); int type = nfit_spa_type(spa);
u16 dcr;
switch (type) { switch (type) {
case NFIT_SPA_DCR: case NFIT_SPA_DCR:
...@@ -559,14 +535,18 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, ...@@ -559,14 +535,18 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
} }
list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) { list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
int rc; struct nfit_dcr *nfit_dcr;
u32 device_handle;
u16 dcr;
if (nfit_memdev->memdev->range_index != spa->range_index) if (nfit_memdev->memdev->range_index != spa->range_index)
continue; continue;
found = NULL; found = NULL;
dcr = nfit_memdev->memdev->region_index; dcr = nfit_memdev->memdev->region_index;
device_handle = nfit_memdev->memdev->device_handle;
list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
if (__to_nfit_memdev(nfit_mem)->region_index == dcr) { if (__to_nfit_memdev(nfit_mem)->device_handle
== device_handle) {
found = nfit_mem; found = nfit_mem;
break; break;
} }
...@@ -579,6 +559,31 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, ...@@ -579,6 +559,31 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
if (!nfit_mem) if (!nfit_mem)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&nfit_mem->list); INIT_LIST_HEAD(&nfit_mem->list);
list_add(&nfit_mem->list, &acpi_desc->dimms);
}
list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
if (nfit_dcr->dcr->region_index != dcr)
continue;
/*
* Record the control region for the dimm. For
* the ACPI 6.1 case, where there are separate
* control regions for the pmem vs blk
* interfaces, be sure to record the extended
* blk details.
*/
if (!nfit_mem->dcr)
nfit_mem->dcr = nfit_dcr->dcr;
else if (nfit_mem->dcr->windows == 0
&& nfit_dcr->dcr->windows)
nfit_mem->dcr = nfit_dcr->dcr;
break;
}
if (dcr && !nfit_mem->dcr) {
dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
spa->range_index, dcr);
return -ENODEV;
} }
if (type == NFIT_SPA_DCR) { if (type == NFIT_SPA_DCR) {
...@@ -595,6 +600,7 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, ...@@ -595,6 +600,7 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
nfit_mem->idt_dcr = nfit_idt->idt; nfit_mem->idt_dcr = nfit_idt->idt;
break; break;
} }
nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
} else { } else {
/* /*
* A single dimm may belong to multiple SPA-PM * 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, ...@@ -603,13 +609,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
*/ */
nfit_mem->memdev_pmem = nfit_memdev->memdev; nfit_mem->memdev_pmem = nfit_memdev->memdev;
} }
if (found)
continue;
rc = nfit_mem_add(acpi_desc, nfit_mem, spa);
if (rc)
return rc;
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment