diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-12-04 11:30:45 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-12-04 11:30:45 -0800 |
commit | fb39cbda147082a2e7dc4e2b5f3298448295e3c4 (patch) | |
tree | 7dcbed6849a900f66f1d2a0b31d82721c6b4ed1e | |
parent | db281766baf4f88da2892f329381e9d9baa9756d (diff) | |
parent | 6b577c9d772c45448aec784ec235cea228b4d3ad (diff) |
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
-rw-r--r-- | arch/x86/kernel/pmem.c | 12 | ||||
-rw-r--r-- | drivers/acpi/nfit.c | 65 | ||||
-rw-r--r-- | drivers/acpi/nfit.h | 3 | ||||
-rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 49 |
4 files changed, 76 insertions, 53 deletions
diff --git a/arch/x86/kernel/pmem.c b/arch/x86/kernel/pmem.c index 4f00b63d7ff3..14415aff1813 100644 --- a/arch/x86/kernel/pmem.c +++ b/arch/x86/kernel/pmem.c @@ -4,10 +4,22 @@ */ #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/ioport.h> + +static int found(u64 start, u64 end, void *data) +{ + return 1; +} static __init int register_e820_pmem(void) { + char *pmem = "Persistent Memory (legacy)"; struct platform_device *pdev; + int rc; + + rc = walk_iomem_res(pmem, IORESOURCE_MEM, 0, -1, NULL, found); + if (rc <= 0) + return 0; /* * See drivers/nvdimm/e820.c for the implementation, this is diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index f7dab53b352a..e7ed39bab97d 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -233,11 +233,12 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_system_address *spa) { + size_t length = min_t(size_t, sizeof(*spa), spa->header.length); struct device *dev = acpi_desc->dev; struct nfit_spa *nfit_spa; list_for_each_entry(nfit_spa, &prev->spas, list) { - if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) { + if (memcmp(nfit_spa->spa, spa, length) == 0) { list_move_tail(&nfit_spa->list, &acpi_desc->spas); return true; } @@ -259,11 +260,12 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_memory_map *memdev) { + size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length); struct device *dev = acpi_desc->dev; struct nfit_memdev *nfit_memdev; list_for_each_entry(nfit_memdev, &prev->memdevs, list) - if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) { + if (memcmp(nfit_memdev->memdev, memdev, length) == 0) { list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs); return true; } @@ -284,11 +286,12 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_control_region *dcr) { + size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length); struct device *dev = acpi_desc->dev; struct nfit_dcr *nfit_dcr; list_for_each_entry(nfit_dcr, &prev->dcrs, list) - if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) { + if (memcmp(nfit_dcr->dcr, dcr, length) == 0) { list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs); return true; } @@ -308,11 +311,12 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_data_region *bdw) { + size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length); struct device *dev = acpi_desc->dev; struct nfit_bdw *nfit_bdw; list_for_each_entry(nfit_bdw, &prev->bdws, list) - if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) { + if (memcmp(nfit_bdw->bdw, bdw, length) == 0) { list_move_tail(&nfit_bdw->list, &acpi_desc->bdws); return true; } @@ -332,11 +336,12 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_interleave *idt) { + size_t length = min_t(size_t, sizeof(*idt), idt->header.length); struct device *dev = acpi_desc->dev; struct nfit_idt *nfit_idt; list_for_each_entry(nfit_idt, &prev->idts, list) - if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) { + if (memcmp(nfit_idt->idt, idt, length) == 0) { list_move_tail(&nfit_idt->list, &acpi_desc->idts); return true; } @@ -356,11 +361,12 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_flush_address *flush) { + size_t length = min_t(size_t, sizeof(*flush), flush->header.length); struct device *dev = acpi_desc->dev; struct nfit_flush *nfit_flush; list_for_each_entry(nfit_flush, &prev->flushes, list) - if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) { + if (memcmp(nfit_flush->flush, flush, length) == 0) { list_move_tail(&nfit_flush->list, &acpi_desc->flushes); return true; } @@ -655,7 +661,7 @@ static ssize_t revision_show(struct device *dev, struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); - return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision); + return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision); } static DEVICE_ATTR_RO(revision); @@ -1652,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) data = (u8 *) acpi_desc->nfit; end = data + sz; - data += sizeof(struct acpi_table_nfit); while (!IS_ERR_OR_NULL(data)) data = add_table(acpi_desc, &prev, data, end); @@ -1748,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev) return PTR_ERR(acpi_desc); } - acpi_desc->nfit = (struct acpi_table_nfit *) tbl; + /* + * Save the acpi header for later and then skip it, + * making nfit point to the first nfit table header. + */ + acpi_desc->acpi_header = *tbl; + acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit); + sz -= sizeof(struct acpi_table_nfit); /* Evaluate _FIT and override with that if present */ status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf); if (ACPI_SUCCESS(status) && buf.length > 0) { - acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; - sz = buf.length; + union acpi_object *obj; + /* + * Adjust for the acpi_object header of the _FIT + */ + obj = buf.pointer; + if (obj->type == ACPI_TYPE_BUFFER) { + acpi_desc->nfit = + (struct acpi_nfit_header *)obj->buffer.pointer; + sz = obj->buffer.length; + } else + dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n", + __func__, (int) obj->type); } rc = acpi_nfit_init(acpi_desc, sz); @@ -1777,7 +1798,8 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) { struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev); struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_table_nfit *nfit_saved; + struct acpi_nfit_header *nfit_saved; + union acpi_object *obj; struct device *dev = &adev->dev; acpi_status status; int ret; @@ -1808,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) } nfit_saved = acpi_desc->nfit; - acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; - ret = acpi_nfit_init(acpi_desc, buf.length); - if (!ret) { - /* Merge failed, restore old nfit, and exit */ - acpi_desc->nfit = nfit_saved; - dev_err(dev, "failed to merge updated NFIT\n"); + obj = buf.pointer; + if (obj->type == ACPI_TYPE_BUFFER) { + acpi_desc->nfit = + (struct acpi_nfit_header *)obj->buffer.pointer; + ret = acpi_nfit_init(acpi_desc, obj->buffer.length); + if (ret) { + /* Merge failed, restore old nfit, and exit */ + acpi_desc->nfit = nfit_saved; + dev_err(dev, "failed to merge updated NFIT\n"); + } + } else { + /* Bad _FIT, restore old nfit */ + dev_err(dev, "Invalid _FIT\n"); } kfree(buf.pointer); diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 2ea5c0797c8f..3d549a383659 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -96,7 +96,8 @@ struct nfit_mem { struct acpi_nfit_desc { struct nvdimm_bus_descriptor nd_desc; - struct acpi_table_nfit *nfit; + struct acpi_table_header acpi_header; + struct acpi_nfit_header *nfit; struct mutex spa_map_mutex; struct mutex init_mutex; struct list_head spa_maps; diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 40ab4476c80a..51cf8256c6cd 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -420,8 +420,7 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr) static int nfit_test0_alloc(struct nfit_test *t) { - size_t nfit_size = sizeof(struct acpi_table_nfit) - + sizeof(struct acpi_nfit_system_address) * NUM_SPA + size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA + sizeof(struct acpi_nfit_memory_map) * NUM_MEM + sizeof(struct acpi_nfit_control_region) * NUM_DCR + sizeof(struct acpi_nfit_data_region) * NUM_BDW @@ -471,8 +470,7 @@ static int nfit_test0_alloc(struct nfit_test *t) static int nfit_test1_alloc(struct nfit_test *t) { - size_t nfit_size = sizeof(struct acpi_table_nfit) - + sizeof(struct acpi_nfit_system_address) + size_t nfit_size = sizeof(struct acpi_nfit_system_address) + sizeof(struct acpi_nfit_memory_map) + sizeof(struct acpi_nfit_control_region); @@ -488,39 +486,24 @@ static int nfit_test1_alloc(struct nfit_test *t) return 0; } -static void nfit_test_init_header(struct acpi_table_nfit *nfit, size_t size) -{ - memcpy(nfit->header.signature, ACPI_SIG_NFIT, 4); - nfit->header.length = size; - nfit->header.revision = 1; - memcpy(nfit->header.oem_id, "LIBND", 6); - memcpy(nfit->header.oem_table_id, "TEST", 5); - nfit->header.oem_revision = 1; - memcpy(nfit->header.asl_compiler_id, "TST", 4); - nfit->header.asl_compiler_revision = 1; -} - static void nfit_test0_setup(struct nfit_test *t) { struct nvdimm_bus_descriptor *nd_desc; struct acpi_nfit_desc *acpi_desc; struct acpi_nfit_memory_map *memdev; void *nfit_buf = t->nfit_buf; - size_t size = t->nfit_size; struct acpi_nfit_system_address *spa; struct acpi_nfit_control_region *dcr; struct acpi_nfit_data_region *bdw; struct acpi_nfit_flush_address *flush; unsigned int offset; - nfit_test_init_header(nfit_buf, size); - /* * spa0 (interleave first half of dimm0 and dimm1, note storage * does not actually alias the related block-data-window * regions) */ - spa = nfit_buf + sizeof(struct acpi_table_nfit); + spa = nfit_buf; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); @@ -533,7 +516,7 @@ static void nfit_test0_setup(struct nfit_test *t) * does not actually alias the related block-data-window * regions) */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa); + spa = nfit_buf + sizeof(*spa); spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); @@ -542,7 +525,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = SPA1_SIZE; /* spa2 (dcr0) dimm0 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 2; + spa = nfit_buf + sizeof(*spa) * 2; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -551,7 +534,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa3 (dcr1) dimm1 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 3; + spa = nfit_buf + sizeof(*spa) * 3; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -560,7 +543,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa4 (dcr2) dimm2 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 4; + spa = nfit_buf + sizeof(*spa) * 4; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -569,7 +552,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa5 (dcr3) dimm3 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 5; + spa = nfit_buf + sizeof(*spa) * 5; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -578,7 +561,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa6 (bdw for dcr0) dimm0 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 6; + spa = nfit_buf + sizeof(*spa) * 6; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -587,7 +570,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DIMM_SIZE; /* spa7 (bdw for dcr1) dimm1 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 7; + spa = nfit_buf + sizeof(*spa) * 7; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -596,7 +579,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DIMM_SIZE; /* spa8 (bdw for dcr2) dimm2 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 8; + spa = nfit_buf + sizeof(*spa) * 8; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -605,7 +588,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DIMM_SIZE; /* spa9 (bdw for dcr3) dimm3 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 9; + spa = nfit_buf + sizeof(*spa) * 9; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -613,7 +596,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->address = t->dimm_dma[3]; spa->length = DIMM_SIZE; - offset = sizeof(struct acpi_table_nfit) + sizeof(*spa) * 10; + offset = sizeof(*spa) * 10; /* mem-region0 (spa0, dimm0) */ memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; @@ -1100,15 +1083,13 @@ static void nfit_test0_setup(struct nfit_test *t) static void nfit_test1_setup(struct nfit_test *t) { - size_t size = t->nfit_size, offset; + size_t offset; void *nfit_buf = t->nfit_buf; struct acpi_nfit_memory_map *memdev; struct acpi_nfit_control_region *dcr; struct acpi_nfit_system_address *spa; - nfit_test_init_header(nfit_buf, size); - - offset = sizeof(struct acpi_table_nfit); + offset = 0; /* spa0 (flat range with no bdw aliasing) */ spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |