4) While this fixes my platform, it probably breaks the tests
that were used to test the original commit.
If we need to have a long discussion about whether our firmware
is correct, then perhaps we can remove the _FIT code from
acpi_nfit_add()
while we sort it out.
Reported-by: Jeff Moyer (jmoyer@xxxxxxxxxx>
Signed-off-by: Linda Knippers <linda.knippers@xxxxxx>
---
drivers/acpi/nfit.c | 55 +++++++++++++++++++++++++++++++++++++++++---
---------
drivers/acpi/nfit.h | 3 ++-
2 files changed, 45 insertions(+), 13 deletions(-)
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index f7dab53..ad95113 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -655,7 +655,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 +1652,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 +1747,34 @@ 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, make
+ * 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;
+
+ dev_dbg(dev, "%s _FIT ptr %p, length: %d\n",
+ __func__, buf.pointer, (int)buf.length);
+ print_hex_dump_debug("_FIT: ", DUMP_PREFIX_OFFSET,
16, 1,
+ buf.pointer, buf.length, true);
+
+ /*
+ * 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,8 +1796,9 @@ 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;
struct device *dev = &adev->dev;
+ union acpi_object *obj;
acpi_status status;
int ret;
@@ -1807,13 +1827,24 @@ static void acpi_nfit_notify(struct
acpi_device *adev, u32 event)
goto out_unlock;
}
+ dev_dbg(dev, "%s _FIT ptr %p, length: %d\n",
+ __func__, buf.pointer, (int)buf.length);
+ print_hex_dump_debug("_FIT: ", DUMP_PREFIX_OFFSET, 16, 1,
+ buf.pointer, buf.length, true);
+
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 2ea5c07..3d549a3 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;N�����r��y���b�X��ǧv�^�){.n�+����{�i�b�{ay�ʇڙ�,j��f���h���z��w������j:+v���w�j�m��������zZ+�����ݢj"��!tml=