Skip to content

Commit fb39cbd

Browse files
committed
Merge branch 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm fixes from Dan Williams: - NFIT parsing regression fixes from Linda. The nvdimm hot-add implementation merged in 4.4-rc1 interpreted the specification in a way that breaks actual HPE platforms. We are also closing the loop with the ACPI Working Group to get this clarification added to the spec. - Andy pointed out that his laptop without nvdimm resources is loading the e820-nvdimm module by default, fix that up to only load the module when an e820-type-12 range is present. * 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: nfit: Adjust for different _FIT and NFIT headers nfit: Fix the check for a successful NFIT merge nfit: Account for table size length variation libnvdimm, e820: skip module loading when no type-12
2 parents db28176 + 6b577c9 commit fb39cbd

File tree

4 files changed

+76
-53
lines changed

4 files changed

+76
-53
lines changed

arch/x86/kernel/pmem.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,22 @@
44
*/
55
#include <linux/platform_device.h>
66
#include <linux/module.h>
7+
#include <linux/ioport.h>
8+
9+
static int found(u64 start, u64 end, void *data)
10+
{
11+
return 1;
12+
}
713

814
static __init int register_e820_pmem(void)
915
{
16+
char *pmem = "Persistent Memory (legacy)";
1017
struct platform_device *pdev;
18+
int rc;
19+
20+
rc = walk_iomem_res(pmem, IORESOURCE_MEM, 0, -1, NULL, found);
21+
if (rc <= 0)
22+
return 0;
1123

1224
/*
1325
* See drivers/nvdimm/e820.c for the implementation, this is

drivers/acpi/nfit.c

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,12 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc,
233233
struct nfit_table_prev *prev,
234234
struct acpi_nfit_system_address *spa)
235235
{
236+
size_t length = min_t(size_t, sizeof(*spa), spa->header.length);
236237
struct device *dev = acpi_desc->dev;
237238
struct nfit_spa *nfit_spa;
238239

239240
list_for_each_entry(nfit_spa, &prev->spas, list) {
240-
if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) {
241+
if (memcmp(nfit_spa->spa, spa, length) == 0) {
241242
list_move_tail(&nfit_spa->list, &acpi_desc->spas);
242243
return true;
243244
}
@@ -259,11 +260,12 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
259260
struct nfit_table_prev *prev,
260261
struct acpi_nfit_memory_map *memdev)
261262
{
263+
size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length);
262264
struct device *dev = acpi_desc->dev;
263265
struct nfit_memdev *nfit_memdev;
264266

265267
list_for_each_entry(nfit_memdev, &prev->memdevs, list)
266-
if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) {
268+
if (memcmp(nfit_memdev->memdev, memdev, length) == 0) {
267269
list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
268270
return true;
269271
}
@@ -284,11 +286,12 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
284286
struct nfit_table_prev *prev,
285287
struct acpi_nfit_control_region *dcr)
286288
{
289+
size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length);
287290
struct device *dev = acpi_desc->dev;
288291
struct nfit_dcr *nfit_dcr;
289292

290293
list_for_each_entry(nfit_dcr, &prev->dcrs, list)
291-
if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) {
294+
if (memcmp(nfit_dcr->dcr, dcr, length) == 0) {
292295
list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
293296
return true;
294297
}
@@ -308,11 +311,12 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
308311
struct nfit_table_prev *prev,
309312
struct acpi_nfit_data_region *bdw)
310313
{
314+
size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length);
311315
struct device *dev = acpi_desc->dev;
312316
struct nfit_bdw *nfit_bdw;
313317

314318
list_for_each_entry(nfit_bdw, &prev->bdws, list)
315-
if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) {
319+
if (memcmp(nfit_bdw->bdw, bdw, length) == 0) {
316320
list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
317321
return true;
318322
}
@@ -332,11 +336,12 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc,
332336
struct nfit_table_prev *prev,
333337
struct acpi_nfit_interleave *idt)
334338
{
339+
size_t length = min_t(size_t, sizeof(*idt), idt->header.length);
335340
struct device *dev = acpi_desc->dev;
336341
struct nfit_idt *nfit_idt;
337342

338343
list_for_each_entry(nfit_idt, &prev->idts, list)
339-
if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) {
344+
if (memcmp(nfit_idt->idt, idt, length) == 0) {
340345
list_move_tail(&nfit_idt->list, &acpi_desc->idts);
341346
return true;
342347
}
@@ -356,11 +361,12 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc,
356361
struct nfit_table_prev *prev,
357362
struct acpi_nfit_flush_address *flush)
358363
{
364+
size_t length = min_t(size_t, sizeof(*flush), flush->header.length);
359365
struct device *dev = acpi_desc->dev;
360366
struct nfit_flush *nfit_flush;
361367

362368
list_for_each_entry(nfit_flush, &prev->flushes, list)
363-
if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) {
369+
if (memcmp(nfit_flush->flush, flush, length) == 0) {
364370
list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
365371
return true;
366372
}
@@ -655,7 +661,7 @@ static ssize_t revision_show(struct device *dev,
655661
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
656662
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
657663

658-
return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision);
664+
return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
659665
}
660666
static DEVICE_ATTR_RO(revision);
661667

@@ -1652,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
16521658

16531659
data = (u8 *) acpi_desc->nfit;
16541660
end = data + sz;
1655-
data += sizeof(struct acpi_table_nfit);
16561661
while (!IS_ERR_OR_NULL(data))
16571662
data = add_table(acpi_desc, &prev, data, end);
16581663

@@ -1748,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev)
17481753
return PTR_ERR(acpi_desc);
17491754
}
17501755

1751-
acpi_desc->nfit = (struct acpi_table_nfit *) tbl;
1756+
/*
1757+
* Save the acpi header for later and then skip it,
1758+
* making nfit point to the first nfit table header.
1759+
*/
1760+
acpi_desc->acpi_header = *tbl;
1761+
acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit);
1762+
sz -= sizeof(struct acpi_table_nfit);
17521763

17531764
/* Evaluate _FIT and override with that if present */
17541765
status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
17551766
if (ACPI_SUCCESS(status) && buf.length > 0) {
1756-
acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
1757-
sz = buf.length;
1767+
union acpi_object *obj;
1768+
/*
1769+
* Adjust for the acpi_object header of the _FIT
1770+
*/
1771+
obj = buf.pointer;
1772+
if (obj->type == ACPI_TYPE_BUFFER) {
1773+
acpi_desc->nfit =
1774+
(struct acpi_nfit_header *)obj->buffer.pointer;
1775+
sz = obj->buffer.length;
1776+
} else
1777+
dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
1778+
__func__, (int) obj->type);
17581779
}
17591780

17601781
rc = acpi_nfit_init(acpi_desc, sz);
@@ -1777,7 +1798,8 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
17771798
{
17781799
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
17791800
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
1780-
struct acpi_table_nfit *nfit_saved;
1801+
struct acpi_nfit_header *nfit_saved;
1802+
union acpi_object *obj;
17811803
struct device *dev = &adev->dev;
17821804
acpi_status status;
17831805
int ret;
@@ -1808,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
18081830
}
18091831

18101832
nfit_saved = acpi_desc->nfit;
1811-
acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
1812-
ret = acpi_nfit_init(acpi_desc, buf.length);
1813-
if (!ret) {
1814-
/* Merge failed, restore old nfit, and exit */
1815-
acpi_desc->nfit = nfit_saved;
1816-
dev_err(dev, "failed to merge updated NFIT\n");
1833+
obj = buf.pointer;
1834+
if (obj->type == ACPI_TYPE_BUFFER) {
1835+
acpi_desc->nfit =
1836+
(struct acpi_nfit_header *)obj->buffer.pointer;
1837+
ret = acpi_nfit_init(acpi_desc, obj->buffer.length);
1838+
if (ret) {
1839+
/* Merge failed, restore old nfit, and exit */
1840+
acpi_desc->nfit = nfit_saved;
1841+
dev_err(dev, "failed to merge updated NFIT\n");
1842+
}
1843+
} else {
1844+
/* Bad _FIT, restore old nfit */
1845+
dev_err(dev, "Invalid _FIT\n");
18171846
}
18181847
kfree(buf.pointer);
18191848

drivers/acpi/nfit.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ struct nfit_mem {
9696

9797
struct acpi_nfit_desc {
9898
struct nvdimm_bus_descriptor nd_desc;
99-
struct acpi_table_nfit *nfit;
99+
struct acpi_table_header acpi_header;
100+
struct acpi_nfit_header *nfit;
100101
struct mutex spa_map_mutex;
101102
struct mutex init_mutex;
102103
struct list_head spa_maps;

tools/testing/nvdimm/test/nfit.c

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,7 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
420420

421421
static int nfit_test0_alloc(struct nfit_test *t)
422422
{
423-
size_t nfit_size = sizeof(struct acpi_table_nfit)
424-
+ sizeof(struct acpi_nfit_system_address) * NUM_SPA
423+
size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA
425424
+ sizeof(struct acpi_nfit_memory_map) * NUM_MEM
426425
+ sizeof(struct acpi_nfit_control_region) * NUM_DCR
427426
+ sizeof(struct acpi_nfit_data_region) * NUM_BDW
@@ -471,8 +470,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
471470

472471
static int nfit_test1_alloc(struct nfit_test *t)
473472
{
474-
size_t nfit_size = sizeof(struct acpi_table_nfit)
475-
+ sizeof(struct acpi_nfit_system_address)
473+
size_t nfit_size = sizeof(struct acpi_nfit_system_address)
476474
+ sizeof(struct acpi_nfit_memory_map)
477475
+ sizeof(struct acpi_nfit_control_region);
478476

@@ -488,39 +486,24 @@ static int nfit_test1_alloc(struct nfit_test *t)
488486
return 0;
489487
}
490488

491-
static void nfit_test_init_header(struct acpi_table_nfit *nfit, size_t size)
492-
{
493-
memcpy(nfit->header.signature, ACPI_SIG_NFIT, 4);
494-
nfit->header.length = size;
495-
nfit->header.revision = 1;
496-
memcpy(nfit->header.oem_id, "LIBND", 6);
497-
memcpy(nfit->header.oem_table_id, "TEST", 5);
498-
nfit->header.oem_revision = 1;
499-
memcpy(nfit->header.asl_compiler_id, "TST", 4);
500-
nfit->header.asl_compiler_revision = 1;
501-
}
502-
503489
static void nfit_test0_setup(struct nfit_test *t)
504490
{
505491
struct nvdimm_bus_descriptor *nd_desc;
506492
struct acpi_nfit_desc *acpi_desc;
507493
struct acpi_nfit_memory_map *memdev;
508494
void *nfit_buf = t->nfit_buf;
509-
size_t size = t->nfit_size;
510495
struct acpi_nfit_system_address *spa;
511496
struct acpi_nfit_control_region *dcr;
512497
struct acpi_nfit_data_region *bdw;
513498
struct acpi_nfit_flush_address *flush;
514499
unsigned int offset;
515500

516-
nfit_test_init_header(nfit_buf, size);
517-
518501
/*
519502
* spa0 (interleave first half of dimm0 and dimm1, note storage
520503
* does not actually alias the related block-data-window
521504
* regions)
522505
*/
523-
spa = nfit_buf + sizeof(struct acpi_table_nfit);
506+
spa = nfit_buf;
524507
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
525508
spa->header.length = sizeof(*spa);
526509
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -533,7 +516,7 @@ static void nfit_test0_setup(struct nfit_test *t)
533516
* does not actually alias the related block-data-window
534517
* regions)
535518
*/
536-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa);
519+
spa = nfit_buf + sizeof(*spa);
537520
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
538521
spa->header.length = sizeof(*spa);
539522
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -542,7 +525,7 @@ static void nfit_test0_setup(struct nfit_test *t)
542525
spa->length = SPA1_SIZE;
543526

544527
/* spa2 (dcr0) dimm0 */
545-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 2;
528+
spa = nfit_buf + sizeof(*spa) * 2;
546529
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
547530
spa->header.length = sizeof(*spa);
548531
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -551,7 +534,7 @@ static void nfit_test0_setup(struct nfit_test *t)
551534
spa->length = DCR_SIZE;
552535

553536
/* spa3 (dcr1) dimm1 */
554-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 3;
537+
spa = nfit_buf + sizeof(*spa) * 3;
555538
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
556539
spa->header.length = sizeof(*spa);
557540
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -560,7 +543,7 @@ static void nfit_test0_setup(struct nfit_test *t)
560543
spa->length = DCR_SIZE;
561544

562545
/* spa4 (dcr2) dimm2 */
563-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 4;
546+
spa = nfit_buf + sizeof(*spa) * 4;
564547
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
565548
spa->header.length = sizeof(*spa);
566549
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -569,7 +552,7 @@ static void nfit_test0_setup(struct nfit_test *t)
569552
spa->length = DCR_SIZE;
570553

571554
/* spa5 (dcr3) dimm3 */
572-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 5;
555+
spa = nfit_buf + sizeof(*spa) * 5;
573556
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
574557
spa->header.length = sizeof(*spa);
575558
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -578,7 +561,7 @@ static void nfit_test0_setup(struct nfit_test *t)
578561
spa->length = DCR_SIZE;
579562

580563
/* spa6 (bdw for dcr0) dimm0 */
581-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 6;
564+
spa = nfit_buf + sizeof(*spa) * 6;
582565
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
583566
spa->header.length = sizeof(*spa);
584567
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -587,7 +570,7 @@ static void nfit_test0_setup(struct nfit_test *t)
587570
spa->length = DIMM_SIZE;
588571

589572
/* spa7 (bdw for dcr1) dimm1 */
590-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 7;
573+
spa = nfit_buf + sizeof(*spa) * 7;
591574
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
592575
spa->header.length = sizeof(*spa);
593576
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -596,7 +579,7 @@ static void nfit_test0_setup(struct nfit_test *t)
596579
spa->length = DIMM_SIZE;
597580

598581
/* spa8 (bdw for dcr2) dimm2 */
599-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 8;
582+
spa = nfit_buf + sizeof(*spa) * 8;
600583
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
601584
spa->header.length = sizeof(*spa);
602585
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -605,15 +588,15 @@ static void nfit_test0_setup(struct nfit_test *t)
605588
spa->length = DIMM_SIZE;
606589

607590
/* spa9 (bdw for dcr3) dimm3 */
608-
spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 9;
591+
spa = nfit_buf + sizeof(*spa) * 9;
609592
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
610593
spa->header.length = sizeof(*spa);
611594
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
612595
spa->range_index = 9+1;
613596
spa->address = t->dimm_dma[3];
614597
spa->length = DIMM_SIZE;
615598

616-
offset = sizeof(struct acpi_table_nfit) + sizeof(*spa) * 10;
599+
offset = sizeof(*spa) * 10;
617600
/* mem-region0 (spa0, dimm0) */
618601
memdev = nfit_buf + offset;
619602
memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
@@ -1100,15 +1083,13 @@ static void nfit_test0_setup(struct nfit_test *t)
11001083

11011084
static void nfit_test1_setup(struct nfit_test *t)
11021085
{
1103-
size_t size = t->nfit_size, offset;
1086+
size_t offset;
11041087
void *nfit_buf = t->nfit_buf;
11051088
struct acpi_nfit_memory_map *memdev;
11061089
struct acpi_nfit_control_region *dcr;
11071090
struct acpi_nfit_system_address *spa;
11081091

1109-
nfit_test_init_header(nfit_buf, size);
1110-
1111-
offset = sizeof(struct acpi_table_nfit);
1092+
offset = 0;
11121093
/* spa0 (flat range with no bdw aliasing) */
11131094
spa = nfit_buf + offset;
11141095
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;

0 commit comments

Comments
 (0)