nfit: Adjust for different _FIT and NFIT headers
When support for _FIT was added, the code presumed that the data returned by the _FIT method is identical to the NFIT table, which starts with an acpi_table_header. However, the _FIT is defined to return a data in the format of a series of NFIT type structure entries and as a method, has an acpi_object header rather tahn an acpi_table_header. To address the differences, explicitly save the acpi_table_header from the NFIT, since it is accessible through /sys, and change the nfit pointer in the acpi_desc structure to point to the table entries rather than the headers. Reported-by: Jeff Moyer (jmoyer@redhat.com> Signed-off-by: Linda Knippers <linda.knippers@hpe.com> Acked-by: Vishal Verma <vishal.l.verma@intel.com> [vishal: fix up unit test for new header assumptions] Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Родитель
ff5a55f89c
Коммит
6b577c9d77
|
@ -661,7 +661,7 @@ static ssize_t revision_show(struct device *dev,
|
||||||
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
|
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
|
||||||
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
|
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);
|
static DEVICE_ATTR_RO(revision);
|
||||||
|
|
||||||
|
@ -1658,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
|
||||||
|
|
||||||
data = (u8 *) acpi_desc->nfit;
|
data = (u8 *) acpi_desc->nfit;
|
||||||
end = data + sz;
|
end = data + sz;
|
||||||
data += sizeof(struct acpi_table_nfit);
|
|
||||||
while (!IS_ERR_OR_NULL(data))
|
while (!IS_ERR_OR_NULL(data))
|
||||||
data = add_table(acpi_desc, &prev, data, end);
|
data = add_table(acpi_desc, &prev, data, end);
|
||||||
|
|
||||||
|
@ -1754,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev)
|
||||||
return PTR_ERR(acpi_desc);
|
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 */
|
/* Evaluate _FIT and override with that if present */
|
||||||
status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
|
status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
|
||||||
if (ACPI_SUCCESS(status) && buf.length > 0) {
|
if (ACPI_SUCCESS(status) && buf.length > 0) {
|
||||||
acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
|
union acpi_object *obj;
|
||||||
sz = buf.length;
|
/*
|
||||||
|
* 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);
|
rc = acpi_nfit_init(acpi_desc, sz);
|
||||||
|
@ -1783,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_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
|
||||||
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
|
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;
|
struct device *dev = &adev->dev;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1814,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
|
||||||
}
|
}
|
||||||
|
|
||||||
nfit_saved = acpi_desc->nfit;
|
nfit_saved = acpi_desc->nfit;
|
||||||
acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
|
obj = buf.pointer;
|
||||||
ret = acpi_nfit_init(acpi_desc, buf.length);
|
if (obj->type == ACPI_TYPE_BUFFER) {
|
||||||
if (ret) {
|
acpi_desc->nfit =
|
||||||
/* Merge failed, restore old nfit, and exit */
|
(struct acpi_nfit_header *)obj->buffer.pointer;
|
||||||
acpi_desc->nfit = nfit_saved;
|
ret = acpi_nfit_init(acpi_desc, obj->buffer.length);
|
||||||
dev_err(dev, "failed to merge updated NFIT\n");
|
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);
|
kfree(buf.pointer);
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,8 @@ struct nfit_mem {
|
||||||
|
|
||||||
struct acpi_nfit_desc {
|
struct acpi_nfit_desc {
|
||||||
struct nvdimm_bus_descriptor nd_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 spa_map_mutex;
|
||||||
struct mutex init_mutex;
|
struct mutex init_mutex;
|
||||||
struct list_head spa_maps;
|
struct list_head spa_maps;
|
||||||
|
|
|
@ -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)
|
static int nfit_test0_alloc(struct nfit_test *t)
|
||||||
{
|
{
|
||||||
size_t nfit_size = sizeof(struct acpi_table_nfit)
|
size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA
|
||||||
+ sizeof(struct acpi_nfit_system_address) * NUM_SPA
|
|
||||||
+ sizeof(struct acpi_nfit_memory_map) * NUM_MEM
|
+ sizeof(struct acpi_nfit_memory_map) * NUM_MEM
|
||||||
+ sizeof(struct acpi_nfit_control_region) * NUM_DCR
|
+ sizeof(struct acpi_nfit_control_region) * NUM_DCR
|
||||||
+ sizeof(struct acpi_nfit_data_region) * NUM_BDW
|
+ 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)
|
static int nfit_test1_alloc(struct nfit_test *t)
|
||||||
{
|
{
|
||||||
size_t nfit_size = sizeof(struct acpi_table_nfit)
|
size_t nfit_size = sizeof(struct acpi_nfit_system_address)
|
||||||
+ sizeof(struct acpi_nfit_system_address)
|
|
||||||
+ sizeof(struct acpi_nfit_memory_map)
|
+ sizeof(struct acpi_nfit_memory_map)
|
||||||
+ sizeof(struct acpi_nfit_control_region);
|
+ sizeof(struct acpi_nfit_control_region);
|
||||||
|
|
||||||
|
@ -488,39 +486,24 @@ static int nfit_test1_alloc(struct nfit_test *t)
|
||||||
return 0;
|
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)
|
static void nfit_test0_setup(struct nfit_test *t)
|
||||||
{
|
{
|
||||||
struct nvdimm_bus_descriptor *nd_desc;
|
struct nvdimm_bus_descriptor *nd_desc;
|
||||||
struct acpi_nfit_desc *acpi_desc;
|
struct acpi_nfit_desc *acpi_desc;
|
||||||
struct acpi_nfit_memory_map *memdev;
|
struct acpi_nfit_memory_map *memdev;
|
||||||
void *nfit_buf = t->nfit_buf;
|
void *nfit_buf = t->nfit_buf;
|
||||||
size_t size = t->nfit_size;
|
|
||||||
struct acpi_nfit_system_address *spa;
|
struct acpi_nfit_system_address *spa;
|
||||||
struct acpi_nfit_control_region *dcr;
|
struct acpi_nfit_control_region *dcr;
|
||||||
struct acpi_nfit_data_region *bdw;
|
struct acpi_nfit_data_region *bdw;
|
||||||
struct acpi_nfit_flush_address *flush;
|
struct acpi_nfit_flush_address *flush;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
|
|
||||||
nfit_test_init_header(nfit_buf, size);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* spa0 (interleave first half of dimm0 and dimm1, note storage
|
* spa0 (interleave first half of dimm0 and dimm1, note storage
|
||||||
* does not actually alias the related block-data-window
|
* does not actually alias the related block-data-window
|
||||||
* regions)
|
* regions)
|
||||||
*/
|
*/
|
||||||
spa = nfit_buf + sizeof(struct acpi_table_nfit);
|
spa = nfit_buf;
|
||||||
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
|
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
|
* does not actually alias the related block-data-window
|
||||||
* regions)
|
* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
|
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;
|
spa->length = SPA1_SIZE;
|
||||||
|
|
||||||
/* spa2 (dcr0) dimm0 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
|
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;
|
spa->length = DCR_SIZE;
|
||||||
|
|
||||||
/* spa3 (dcr1) dimm1 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
|
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;
|
spa->length = DCR_SIZE;
|
||||||
|
|
||||||
/* spa4 (dcr2) dimm2 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
|
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;
|
spa->length = DCR_SIZE;
|
||||||
|
|
||||||
/* spa5 (dcr3) dimm3 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
|
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;
|
spa->length = DCR_SIZE;
|
||||||
|
|
||||||
/* spa6 (bdw for dcr0) dimm0 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
|
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;
|
spa->length = DIMM_SIZE;
|
||||||
|
|
||||||
/* spa7 (bdw for dcr1) dimm1 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
|
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;
|
spa->length = DIMM_SIZE;
|
||||||
|
|
||||||
/* spa8 (bdw for dcr2) dimm2 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
|
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;
|
spa->length = DIMM_SIZE;
|
||||||
|
|
||||||
/* spa9 (bdw for dcr3) dimm3 */
|
/* 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.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
spa->header.length = sizeof(*spa);
|
spa->header.length = sizeof(*spa);
|
||||||
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
|
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->address = t->dimm_dma[3];
|
||||||
spa->length = DIMM_SIZE;
|
spa->length = DIMM_SIZE;
|
||||||
|
|
||||||
offset = sizeof(struct acpi_table_nfit) + sizeof(*spa) * 10;
|
offset = sizeof(*spa) * 10;
|
||||||
/* mem-region0 (spa0, dimm0) */
|
/* mem-region0 (spa0, dimm0) */
|
||||||
memdev = nfit_buf + offset;
|
memdev = nfit_buf + offset;
|
||||||
memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
|
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)
|
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;
|
void *nfit_buf = t->nfit_buf;
|
||||||
struct acpi_nfit_memory_map *memdev;
|
struct acpi_nfit_memory_map *memdev;
|
||||||
struct acpi_nfit_control_region *dcr;
|
struct acpi_nfit_control_region *dcr;
|
||||||
struct acpi_nfit_system_address *spa;
|
struct acpi_nfit_system_address *spa;
|
||||||
|
|
||||||
nfit_test_init_header(nfit_buf, size);
|
offset = 0;
|
||||||
|
|
||||||
offset = sizeof(struct acpi_table_nfit);
|
|
||||||
/* spa0 (flat range with no bdw aliasing) */
|
/* spa0 (flat range with no bdw aliasing) */
|
||||||
spa = nfit_buf + offset;
|
spa = nfit_buf + offset;
|
||||||
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче