aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/nfit.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/nfit.c')
-rw-r--r--drivers/acpi/nfit.c298
1 files changed, 242 insertions, 56 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index 6e26761a27da..f7dab53b352a 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -33,6 +33,15 @@ static bool force_enable_dimms;
33module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR); 33module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
34MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status"); 34MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
35 35
36struct nfit_table_prev {
37 struct list_head spas;
38 struct list_head memdevs;
39 struct list_head dcrs;
40 struct list_head bdws;
41 struct list_head idts;
42 struct list_head flushes;
43};
44
36static u8 nfit_uuid[NFIT_UUID_MAX][16]; 45static u8 nfit_uuid[NFIT_UUID_MAX][16];
37 46
38const u8 *to_nfit_uuid(enum nfit_uuids id) 47const u8 *to_nfit_uuid(enum nfit_uuids id)
@@ -221,12 +230,20 @@ static int nfit_spa_type(struct acpi_nfit_system_address *spa)
221} 230}
222 231
223static bool add_spa(struct acpi_nfit_desc *acpi_desc, 232static bool add_spa(struct acpi_nfit_desc *acpi_desc,
233 struct nfit_table_prev *prev,
224 struct acpi_nfit_system_address *spa) 234 struct acpi_nfit_system_address *spa)
225{ 235{
226 struct device *dev = acpi_desc->dev; 236 struct device *dev = acpi_desc->dev;
227 struct nfit_spa *nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa), 237 struct nfit_spa *nfit_spa;
228 GFP_KERNEL); 238
239 list_for_each_entry(nfit_spa, &prev->spas, list) {
240 if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) {
241 list_move_tail(&nfit_spa->list, &acpi_desc->spas);
242 return true;
243 }
244 }
229 245
246 nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa), GFP_KERNEL);
230 if (!nfit_spa) 247 if (!nfit_spa)
231 return false; 248 return false;
232 INIT_LIST_HEAD(&nfit_spa->list); 249 INIT_LIST_HEAD(&nfit_spa->list);
@@ -239,12 +256,19 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc,
239} 256}
240 257
241static bool add_memdev(struct acpi_nfit_desc *acpi_desc, 258static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
259 struct nfit_table_prev *prev,
242 struct acpi_nfit_memory_map *memdev) 260 struct acpi_nfit_memory_map *memdev)
243{ 261{
244 struct device *dev = acpi_desc->dev; 262 struct device *dev = acpi_desc->dev;
245 struct nfit_memdev *nfit_memdev = devm_kzalloc(dev, 263 struct nfit_memdev *nfit_memdev;
246 sizeof(*nfit_memdev), GFP_KERNEL);
247 264
265 list_for_each_entry(nfit_memdev, &prev->memdevs, list)
266 if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) {
267 list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
268 return true;
269 }
270
271 nfit_memdev = devm_kzalloc(dev, sizeof(*nfit_memdev), GFP_KERNEL);
248 if (!nfit_memdev) 272 if (!nfit_memdev)
249 return false; 273 return false;
250 INIT_LIST_HEAD(&nfit_memdev->list); 274 INIT_LIST_HEAD(&nfit_memdev->list);
@@ -257,12 +281,19 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
257} 281}
258 282
259static bool add_dcr(struct acpi_nfit_desc *acpi_desc, 283static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
284 struct nfit_table_prev *prev,
260 struct acpi_nfit_control_region *dcr) 285 struct acpi_nfit_control_region *dcr)
261{ 286{
262 struct device *dev = acpi_desc->dev; 287 struct device *dev = acpi_desc->dev;
263 struct nfit_dcr *nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr), 288 struct nfit_dcr *nfit_dcr;
264 GFP_KERNEL); 289
290 list_for_each_entry(nfit_dcr, &prev->dcrs, list)
291 if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) {
292 list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
293 return true;
294 }
265 295
296 nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr), GFP_KERNEL);
266 if (!nfit_dcr) 297 if (!nfit_dcr)
267 return false; 298 return false;
268 INIT_LIST_HEAD(&nfit_dcr->list); 299 INIT_LIST_HEAD(&nfit_dcr->list);
@@ -274,12 +305,19 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
274} 305}
275 306
276static bool add_bdw(struct acpi_nfit_desc *acpi_desc, 307static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
308 struct nfit_table_prev *prev,
277 struct acpi_nfit_data_region *bdw) 309 struct acpi_nfit_data_region *bdw)
278{ 310{
279 struct device *dev = acpi_desc->dev; 311 struct device *dev = acpi_desc->dev;
280 struct nfit_bdw *nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw), 312 struct nfit_bdw *nfit_bdw;
281 GFP_KERNEL); 313
314 list_for_each_entry(nfit_bdw, &prev->bdws, list)
315 if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) {
316 list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
317 return true;
318 }
282 319
320 nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw), GFP_KERNEL);
283 if (!nfit_bdw) 321 if (!nfit_bdw)
284 return false; 322 return false;
285 INIT_LIST_HEAD(&nfit_bdw->list); 323 INIT_LIST_HEAD(&nfit_bdw->list);
@@ -291,12 +329,19 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
291} 329}
292 330
293static bool add_idt(struct acpi_nfit_desc *acpi_desc, 331static bool add_idt(struct acpi_nfit_desc *acpi_desc,
332 struct nfit_table_prev *prev,
294 struct acpi_nfit_interleave *idt) 333 struct acpi_nfit_interleave *idt)
295{ 334{
296 struct device *dev = acpi_desc->dev; 335 struct device *dev = acpi_desc->dev;
297 struct nfit_idt *nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt), 336 struct nfit_idt *nfit_idt;
298 GFP_KERNEL); 337
338 list_for_each_entry(nfit_idt, &prev->idts, list)
339 if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) {
340 list_move_tail(&nfit_idt->list, &acpi_desc->idts);
341 return true;
342 }
299 343
344 nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt), GFP_KERNEL);
300 if (!nfit_idt) 345 if (!nfit_idt)
301 return false; 346 return false;
302 INIT_LIST_HEAD(&nfit_idt->list); 347 INIT_LIST_HEAD(&nfit_idt->list);
@@ -308,12 +353,19 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc,
308} 353}
309 354
310static bool add_flush(struct acpi_nfit_desc *acpi_desc, 355static bool add_flush(struct acpi_nfit_desc *acpi_desc,
356 struct nfit_table_prev *prev,
311 struct acpi_nfit_flush_address *flush) 357 struct acpi_nfit_flush_address *flush)
312{ 358{
313 struct device *dev = acpi_desc->dev; 359 struct device *dev = acpi_desc->dev;
314 struct nfit_flush *nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush), 360 struct nfit_flush *nfit_flush;
315 GFP_KERNEL);
316 361
362 list_for_each_entry(nfit_flush, &prev->flushes, list)
363 if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) {
364 list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
365 return true;
366 }
367
368 nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush), GFP_KERNEL);
317 if (!nfit_flush) 369 if (!nfit_flush)
318 return false; 370 return false;
319 INIT_LIST_HEAD(&nfit_flush->list); 371 INIT_LIST_HEAD(&nfit_flush->list);
@@ -324,8 +376,8 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc,
324 return true; 376 return true;
325} 377}
326 378
327static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, 379static void *add_table(struct acpi_nfit_desc *acpi_desc,
328 const void *end) 380 struct nfit_table_prev *prev, void *table, const void *end)
329{ 381{
330 struct device *dev = acpi_desc->dev; 382 struct device *dev = acpi_desc->dev;
331 struct acpi_nfit_header *hdr; 383 struct acpi_nfit_header *hdr;
@@ -335,29 +387,35 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table,
335 return NULL; 387 return NULL;
336 388
337 hdr = table; 389 hdr = table;
390 if (!hdr->length) {
391 dev_warn(dev, "found a zero length table '%d' parsing nfit\n",
392 hdr->type);
393 return NULL;
394 }
395
338 switch (hdr->type) { 396 switch (hdr->type) {
339 case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: 397 case ACPI_NFIT_TYPE_SYSTEM_ADDRESS:
340 if (!add_spa(acpi_desc, table)) 398 if (!add_spa(acpi_desc, prev, table))
341 return err; 399 return err;
342 break; 400 break;
343 case ACPI_NFIT_TYPE_MEMORY_MAP: 401 case ACPI_NFIT_TYPE_MEMORY_MAP:
344 if (!add_memdev(acpi_desc, table)) 402 if (!add_memdev(acpi_desc, prev, table))
345 return err; 403 return err;
346 break; 404 break;
347 case ACPI_NFIT_TYPE_CONTROL_REGION: 405 case ACPI_NFIT_TYPE_CONTROL_REGION:
348 if (!add_dcr(acpi_desc, table)) 406 if (!add_dcr(acpi_desc, prev, table))
349 return err; 407 return err;
350 break; 408 break;
351 case ACPI_NFIT_TYPE_DATA_REGION: 409 case ACPI_NFIT_TYPE_DATA_REGION:
352 if (!add_bdw(acpi_desc, table)) 410 if (!add_bdw(acpi_desc, prev, table))
353 return err; 411 return err;
354 break; 412 break;
355 case ACPI_NFIT_TYPE_INTERLEAVE: 413 case ACPI_NFIT_TYPE_INTERLEAVE:
356 if (!add_idt(acpi_desc, table)) 414 if (!add_idt(acpi_desc, prev, table))
357 return err; 415 return err;
358 break; 416 break;
359 case ACPI_NFIT_TYPE_FLUSH_ADDRESS: 417 case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
360 if (!add_flush(acpi_desc, table)) 418 if (!add_flush(acpi_desc, prev, table))
361 return err; 419 return err;
362 break; 420 break;
363 case ACPI_NFIT_TYPE_SMBIOS: 421 case ACPI_NFIT_TYPE_SMBIOS:
@@ -802,12 +860,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
802 device_handle = __to_nfit_memdev(nfit_mem)->device_handle; 860 device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
803 nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle); 861 nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle);
804 if (nvdimm) { 862 if (nvdimm) {
805 /* 863 dimm_count++;
806 * If for some reason we find multiple DCRs the
807 * first one wins
808 */
809 dev_err(acpi_desc->dev, "duplicate DCR detected: %s\n",
810 nvdimm_name(nvdimm));
811 continue; 864 continue;
812 } 865 }
813 866
@@ -1476,6 +1529,9 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
1476 struct resource res; 1529 struct resource res;
1477 int count = 0, rc; 1530 int count = 0, rc;
1478 1531
1532 if (nfit_spa->is_registered)
1533 return 0;
1534
1479 if (spa->range_index == 0) { 1535 if (spa->range_index == 0) {
1480 dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n", 1536 dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n",
1481 __func__); 1537 __func__);
@@ -1529,6 +1585,8 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
1529 if (!nvdimm_volatile_region_create(nvdimm_bus, ndr_desc)) 1585 if (!nvdimm_volatile_region_create(nvdimm_bus, ndr_desc))
1530 return -ENOMEM; 1586 return -ENOMEM;
1531 } 1587 }
1588
1589 nfit_spa->is_registered = 1;
1532 return 0; 1590 return 0;
1533} 1591}
1534 1592
@@ -1545,71 +1603,101 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
1545 return 0; 1603 return 0;
1546} 1604}
1547 1605
1606static int acpi_nfit_check_deletions(struct acpi_nfit_desc *acpi_desc,
1607 struct nfit_table_prev *prev)
1608{
1609 struct device *dev = acpi_desc->dev;
1610
1611 if (!list_empty(&prev->spas) ||
1612 !list_empty(&prev->memdevs) ||
1613 !list_empty(&prev->dcrs) ||
1614 !list_empty(&prev->bdws) ||
1615 !list_empty(&prev->idts) ||
1616 !list_empty(&prev->flushes)) {
1617 dev_err(dev, "new nfit deletes entries (unsupported)\n");
1618 return -ENXIO;
1619 }
1620 return 0;
1621}
1622
1548int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) 1623int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
1549{ 1624{
1550 struct device *dev = acpi_desc->dev; 1625 struct device *dev = acpi_desc->dev;
1626 struct nfit_table_prev prev;
1551 const void *end; 1627 const void *end;
1552 u8 *data; 1628 u8 *data;
1553 int rc; 1629 int rc;
1554 1630
1555 INIT_LIST_HEAD(&acpi_desc->spa_maps); 1631 mutex_lock(&acpi_desc->init_mutex);
1556 INIT_LIST_HEAD(&acpi_desc->spas); 1632
1557 INIT_LIST_HEAD(&acpi_desc->dcrs); 1633 INIT_LIST_HEAD(&prev.spas);
1558 INIT_LIST_HEAD(&acpi_desc->bdws); 1634 INIT_LIST_HEAD(&prev.memdevs);
1559 INIT_LIST_HEAD(&acpi_desc->idts); 1635 INIT_LIST_HEAD(&prev.dcrs);
1560 INIT_LIST_HEAD(&acpi_desc->flushes); 1636 INIT_LIST_HEAD(&prev.bdws);
1561 INIT_LIST_HEAD(&acpi_desc->memdevs); 1637 INIT_LIST_HEAD(&prev.idts);
1562 INIT_LIST_HEAD(&acpi_desc->dimms); 1638 INIT_LIST_HEAD(&prev.flushes);
1563 mutex_init(&acpi_desc->spa_map_mutex); 1639
1640 list_cut_position(&prev.spas, &acpi_desc->spas,
1641 acpi_desc->spas.prev);
1642 list_cut_position(&prev.memdevs, &acpi_desc->memdevs,
1643 acpi_desc->memdevs.prev);
1644 list_cut_position(&prev.dcrs, &acpi_desc->dcrs,
1645 acpi_desc->dcrs.prev);
1646 list_cut_position(&prev.bdws, &acpi_desc->bdws,
1647 acpi_desc->bdws.prev);
1648 list_cut_position(&prev.idts, &acpi_desc->idts,
1649 acpi_desc->idts.prev);
1650 list_cut_position(&prev.flushes, &acpi_desc->flushes,
1651 acpi_desc->flushes.prev);
1564 1652
1565 data = (u8 *) acpi_desc->nfit; 1653 data = (u8 *) acpi_desc->nfit;
1566 end = data + sz; 1654 end = data + sz;
1567 data += sizeof(struct acpi_table_nfit); 1655 data += sizeof(struct acpi_table_nfit);
1568 while (!IS_ERR_OR_NULL(data)) 1656 while (!IS_ERR_OR_NULL(data))
1569 data = add_table(acpi_desc, data, end); 1657 data = add_table(acpi_desc, &prev, data, end);
1570 1658
1571 if (IS_ERR(data)) { 1659 if (IS_ERR(data)) {
1572 dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__, 1660 dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__,
1573 PTR_ERR(data)); 1661 PTR_ERR(data));
1574 return PTR_ERR(data); 1662 rc = PTR_ERR(data);
1663 goto out_unlock;
1575 } 1664 }
1576 1665
1577 if (nfit_mem_init(acpi_desc) != 0) 1666 rc = acpi_nfit_check_deletions(acpi_desc, &prev);
1578 return -ENOMEM; 1667 if (rc)
1668 goto out_unlock;
1669
1670 if (nfit_mem_init(acpi_desc) != 0) {
1671 rc = -ENOMEM;
1672 goto out_unlock;
1673 }
1579 1674
1580 acpi_nfit_init_dsms(acpi_desc); 1675 acpi_nfit_init_dsms(acpi_desc);
1581 1676
1582 rc = acpi_nfit_register_dimms(acpi_desc); 1677 rc = acpi_nfit_register_dimms(acpi_desc);
1583 if (rc) 1678 if (rc)
1584 return rc; 1679 goto out_unlock;
1680
1681 rc = acpi_nfit_register_regions(acpi_desc);
1585 1682
1586 return acpi_nfit_register_regions(acpi_desc); 1683 out_unlock:
1684 mutex_unlock(&acpi_desc->init_mutex);
1685 return rc;
1587} 1686}
1588EXPORT_SYMBOL_GPL(acpi_nfit_init); 1687EXPORT_SYMBOL_GPL(acpi_nfit_init);
1589 1688
1590static int acpi_nfit_add(struct acpi_device *adev) 1689static struct acpi_nfit_desc *acpi_nfit_desc_init(struct acpi_device *adev)
1591{ 1690{
1592 struct nvdimm_bus_descriptor *nd_desc; 1691 struct nvdimm_bus_descriptor *nd_desc;
1593 struct acpi_nfit_desc *acpi_desc; 1692 struct acpi_nfit_desc *acpi_desc;
1594 struct device *dev = &adev->dev; 1693 struct device *dev = &adev->dev;
1595 struct acpi_table_header *tbl;
1596 acpi_status status = AE_OK;
1597 acpi_size sz;
1598 int rc;
1599
1600 status = acpi_get_table_with_size("NFIT", 0, &tbl, &sz);
1601 if (ACPI_FAILURE(status)) {
1602 dev_err(dev, "failed to find NFIT\n");
1603 return -ENXIO;
1604 }
1605 1694
1606 acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL); 1695 acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
1607 if (!acpi_desc) 1696 if (!acpi_desc)
1608 return -ENOMEM; 1697 return ERR_PTR(-ENOMEM);
1609 1698
1610 dev_set_drvdata(dev, acpi_desc); 1699 dev_set_drvdata(dev, acpi_desc);
1611 acpi_desc->dev = dev; 1700 acpi_desc->dev = dev;
1612 acpi_desc->nfit = (struct acpi_table_nfit *) tbl;
1613 acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io; 1701 acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io;
1614 nd_desc = &acpi_desc->nd_desc; 1702 nd_desc = &acpi_desc->nd_desc;
1615 nd_desc->provider_name = "ACPI.NFIT"; 1703 nd_desc->provider_name = "ACPI.NFIT";
@@ -1617,8 +1705,57 @@ static int acpi_nfit_add(struct acpi_device *adev)
1617 nd_desc->attr_groups = acpi_nfit_attribute_groups; 1705 nd_desc->attr_groups = acpi_nfit_attribute_groups;
1618 1706
1619 acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, nd_desc); 1707 acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, nd_desc);
1620 if (!acpi_desc->nvdimm_bus) 1708 if (!acpi_desc->nvdimm_bus) {
1621 return -ENXIO; 1709 devm_kfree(dev, acpi_desc);
1710 return ERR_PTR(-ENXIO);
1711 }
1712
1713 INIT_LIST_HEAD(&acpi_desc->spa_maps);
1714 INIT_LIST_HEAD(&acpi_desc->spas);
1715 INIT_LIST_HEAD(&acpi_desc->dcrs);
1716 INIT_LIST_HEAD(&acpi_desc->bdws);
1717 INIT_LIST_HEAD(&acpi_desc->idts);
1718 INIT_LIST_HEAD(&acpi_desc->flushes);
1719 INIT_LIST_HEAD(&acpi_desc->memdevs);
1720 INIT_LIST_HEAD(&acpi_desc->dimms);
1721 mutex_init(&acpi_desc->spa_map_mutex);
1722 mutex_init(&acpi_desc->init_mutex);
1723
1724 return acpi_desc;
1725}
1726
1727static int acpi_nfit_add(struct acpi_device *adev)
1728{
1729 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
1730 struct acpi_nfit_desc *acpi_desc;
1731 struct device *dev = &adev->dev;
1732 struct acpi_table_header *tbl;
1733 acpi_status status = AE_OK;
1734 acpi_size sz;
1735 int rc;
1736
1737 status = acpi_get_table_with_size("NFIT", 0, &tbl, &sz);
1738 if (ACPI_FAILURE(status)) {
1739 /* This is ok, we could have an nvdimm hotplugged later */
1740 dev_dbg(dev, "failed to find NFIT at startup\n");
1741 return 0;
1742 }
1743
1744 acpi_desc = acpi_nfit_desc_init(adev);
1745 if (IS_ERR(acpi_desc)) {
1746 dev_err(dev, "%s: error initializing acpi_desc: %ld\n",
1747 __func__, PTR_ERR(acpi_desc));
1748 return PTR_ERR(acpi_desc);
1749 }
1750
1751 acpi_desc->nfit = (struct acpi_table_nfit *) tbl;
1752
1753 /* Evaluate _FIT and override with that if present */
1754 status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
1755 if (ACPI_SUCCESS(status) && buf.length > 0) {
1756 acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
1757 sz = buf.length;
1758 }
1622 1759
1623 rc = acpi_nfit_init(acpi_desc, sz); 1760 rc = acpi_nfit_init(acpi_desc, sz);
1624 if (rc) { 1761 if (rc) {
@@ -1636,6 +1773,54 @@ static int acpi_nfit_remove(struct acpi_device *adev)
1636 return 0; 1773 return 0;
1637} 1774}
1638 1775
1776static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
1777{
1778 struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
1779 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
1780 struct acpi_table_nfit *nfit_saved;
1781 struct device *dev = &adev->dev;
1782 acpi_status status;
1783 int ret;
1784
1785 dev_dbg(dev, "%s: event: %d\n", __func__, event);
1786
1787 device_lock(dev);
1788 if (!dev->driver) {
1789 /* dev->driver may be null if we're being removed */
1790 dev_dbg(dev, "%s: no driver found for dev\n", __func__);
1791 return;
1792 }
1793
1794 if (!acpi_desc) {
1795 acpi_desc = acpi_nfit_desc_init(adev);
1796 if (IS_ERR(acpi_desc)) {
1797 dev_err(dev, "%s: error initializing acpi_desc: %ld\n",
1798 __func__, PTR_ERR(acpi_desc));
1799 goto out_unlock;
1800 }
1801 }
1802
1803 /* Evaluate _FIT */
1804 status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
1805 if (ACPI_FAILURE(status)) {
1806 dev_err(dev, "failed to evaluate _FIT\n");
1807 goto out_unlock;
1808 }
1809
1810 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");
1817 }
1818 kfree(buf.pointer);
1819
1820 out_unlock:
1821 device_unlock(dev);
1822}
1823
1639static const struct acpi_device_id acpi_nfit_ids[] = { 1824static const struct acpi_device_id acpi_nfit_ids[] = {
1640 { "ACPI0012", 0 }, 1825 { "ACPI0012", 0 },
1641 { "", 0 }, 1826 { "", 0 },
@@ -1648,6 +1833,7 @@ static struct acpi_driver acpi_nfit_driver = {
1648 .ops = { 1833 .ops = {
1649 .add = acpi_nfit_add, 1834 .add = acpi_nfit_add,
1650 .remove = acpi_nfit_remove, 1835 .remove = acpi_nfit_remove,
1836 .notify = acpi_nfit_notify,
1651 }, 1837 },
1652}; 1838};
1653 1839