diff options
-rw-r--r-- | Documentation/filesystems/proc.txt | 22 | ||||
-rw-r--r-- | arch/x86/mm/init.c | 4 | ||||
-rw-r--r-- | arch/x86/mm/init_64.c | 4 | ||||
-rw-r--r-- | drivers/acpi/nfit.c | 298 | ||||
-rw-r--r-- | drivers/acpi/nfit.h | 2 | ||||
-rw-r--r-- | drivers/base/devres.c | 19 | ||||
-rw-r--r-- | drivers/nvdimm/pmem.c | 28 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 10 | ||||
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 15 | ||||
-rw-r--r-- | include/linux/device.h | 16 | ||||
-rw-r--r-- | include/linux/pmem.h | 26 | ||||
-rw-r--r-- | include/linux/sched.h | 4 | ||||
-rw-r--r-- | kernel/memremap.c | 16 | ||||
-rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 164 |
14 files changed, 494 insertions, 134 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 1e4a6cc1b6ea..402ab99e409f 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt | |||
@@ -1605,16 +1605,16 @@ Documentation/accounting. | |||
1605 | --------------------------------------------------------------- | 1605 | --------------------------------------------------------------- |
1606 | When a process is dumped, all anonymous memory is written to a core file as | 1606 | When a process is dumped, all anonymous memory is written to a core file as |
1607 | long as the size of the core file isn't limited. But sometimes we don't want | 1607 | long as the size of the core file isn't limited. But sometimes we don't want |
1608 | to dump some memory segments, for example, huge shared memory. Conversely, | 1608 | to dump some memory segments, for example, huge shared memory or DAX. |
1609 | sometimes we want to save file-backed memory segments into a core file, not | 1609 | Conversely, sometimes we want to save file-backed memory segments into a core |
1610 | only the individual files. | 1610 | file, not only the individual files. |
1611 | 1611 | ||
1612 | /proc/<pid>/coredump_filter allows you to customize which memory segments | 1612 | /proc/<pid>/coredump_filter allows you to customize which memory segments |
1613 | will be dumped when the <pid> process is dumped. coredump_filter is a bitmask | 1613 | will be dumped when the <pid> process is dumped. coredump_filter is a bitmask |
1614 | of memory types. If a bit of the bitmask is set, memory segments of the | 1614 | of memory types. If a bit of the bitmask is set, memory segments of the |
1615 | corresponding memory type are dumped, otherwise they are not dumped. | 1615 | corresponding memory type are dumped, otherwise they are not dumped. |
1616 | 1616 | ||
1617 | The following 7 memory types are supported: | 1617 | The following 9 memory types are supported: |
1618 | - (bit 0) anonymous private memory | 1618 | - (bit 0) anonymous private memory |
1619 | - (bit 1) anonymous shared memory | 1619 | - (bit 1) anonymous shared memory |
1620 | - (bit 2) file-backed private memory | 1620 | - (bit 2) file-backed private memory |
@@ -1623,20 +1623,22 @@ The following 7 memory types are supported: | |||
1623 | effective only if the bit 2 is cleared) | 1623 | effective only if the bit 2 is cleared) |
1624 | - (bit 5) hugetlb private memory | 1624 | - (bit 5) hugetlb private memory |
1625 | - (bit 6) hugetlb shared memory | 1625 | - (bit 6) hugetlb shared memory |
1626 | - (bit 7) DAX private memory | ||
1627 | - (bit 8) DAX shared memory | ||
1626 | 1628 | ||
1627 | Note that MMIO pages such as frame buffer are never dumped and vDSO pages | 1629 | Note that MMIO pages such as frame buffer are never dumped and vDSO pages |
1628 | are always dumped regardless of the bitmask status. | 1630 | are always dumped regardless of the bitmask status. |
1629 | 1631 | ||
1630 | Note bit 0-4 doesn't effect any hugetlb memory. hugetlb memory are only | 1632 | Note that bits 0-4 don't affect hugetlb or DAX memory. hugetlb memory is |
1631 | effected by bit 5-6. | 1633 | only affected by bit 5-6, and DAX is only affected by bits 7-8. |
1632 | 1634 | ||
1633 | Default value of coredump_filter is 0x23; this means all anonymous memory | 1635 | The default value of coredump_filter is 0x33; this means all anonymous memory |
1634 | segments and hugetlb private memory are dumped. | 1636 | segments, ELF header pages and hugetlb private memory are dumped. |
1635 | 1637 | ||
1636 | If you don't want to dump all shared memory segments attached to pid 1234, | 1638 | If you don't want to dump all shared memory segments attached to pid 1234, |
1637 | write 0x21 to the process's proc file. | 1639 | write 0x31 to the process's proc file. |
1638 | 1640 | ||
1639 | $ echo 0x21 > /proc/1234/coredump_filter | 1641 | $ echo 0x31 > /proc/1234/coredump_filter |
1640 | 1642 | ||
1641 | When a new process is created, the process inherits the bitmask status from its | 1643 | When a new process is created, the process inherits the bitmask status from its |
1642 | parent. It is useful to set up coredump_filter before the program runs. | 1644 | parent. It is useful to set up coredump_filter before the program runs. |
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 1f37cb2b56a9..493f54172b4a 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
@@ -354,7 +354,7 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range, | |||
354 | } | 354 | } |
355 | 355 | ||
356 | for (i = 0; i < nr_range; i++) | 356 | for (i = 0; i < nr_range; i++) |
357 | printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n", | 357 | pr_debug(" [mem %#010lx-%#010lx] page %s\n", |
358 | mr[i].start, mr[i].end - 1, | 358 | mr[i].start, mr[i].end - 1, |
359 | page_size_string(&mr[i])); | 359 | page_size_string(&mr[i])); |
360 | 360 | ||
@@ -401,7 +401,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
401 | unsigned long ret = 0; | 401 | unsigned long ret = 0; |
402 | int nr_range, i; | 402 | int nr_range, i; |
403 | 403 | ||
404 | pr_info("init_memory_mapping: [mem %#010lx-%#010lx]\n", | 404 | pr_debug("init_memory_mapping: [mem %#010lx-%#010lx]\n", |
405 | start, end - 1); | 405 | start, end - 1); |
406 | 406 | ||
407 | memset(mr, 0, sizeof(mr)); | 407 | memset(mr, 0, sizeof(mr)); |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 5ed62eff31bd..ec081fe0ce2c 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -1270,7 +1270,7 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start, | |||
1270 | /* check to see if we have contiguous blocks */ | 1270 | /* check to see if we have contiguous blocks */ |
1271 | if (p_end != p || node_start != node) { | 1271 | if (p_end != p || node_start != node) { |
1272 | if (p_start) | 1272 | if (p_start) |
1273 | printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n", | 1273 | pr_debug(" [%lx-%lx] PMD -> [%p-%p] on node %d\n", |
1274 | addr_start, addr_end-1, p_start, p_end-1, node_start); | 1274 | addr_start, addr_end-1, p_start, p_end-1, node_start); |
1275 | addr_start = addr; | 1275 | addr_start = addr; |
1276 | node_start = node; | 1276 | node_start = node; |
@@ -1368,7 +1368,7 @@ void register_page_bootmem_memmap(unsigned long section_nr, | |||
1368 | void __meminit vmemmap_populate_print_last(void) | 1368 | void __meminit vmemmap_populate_print_last(void) |
1369 | { | 1369 | { |
1370 | if (p_start) { | 1370 | if (p_start) { |
1371 | printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n", | 1371 | pr_debug(" [%lx-%lx] PMD -> [%p-%p] on node %d\n", |
1372 | addr_start, addr_end-1, p_start, p_end-1, node_start); | 1372 | addr_start, addr_end-1, p_start, p_end-1, node_start); |
1373 | p_start = NULL; | 1373 | p_start = NULL; |
1374 | p_end = NULL; | 1374 | p_end = NULL; |
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; | |||
33 | module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR); | 33 | module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR); |
34 | MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status"); | 34 | MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status"); |
35 | 35 | ||
36 | struct 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 | |||
36 | static u8 nfit_uuid[NFIT_UUID_MAX][16]; | 45 | static u8 nfit_uuid[NFIT_UUID_MAX][16]; |
37 | 46 | ||
38 | const u8 *to_nfit_uuid(enum nfit_uuids id) | 47 | const 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 | ||
223 | static bool add_spa(struct acpi_nfit_desc *acpi_desc, | 232 | static 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 | ||
241 | static bool add_memdev(struct acpi_nfit_desc *acpi_desc, | 258 | static 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 | ||
259 | static bool add_dcr(struct acpi_nfit_desc *acpi_desc, | 283 | static 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 | ||
276 | static bool add_bdw(struct acpi_nfit_desc *acpi_desc, | 307 | static 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 | ||
293 | static bool add_idt(struct acpi_nfit_desc *acpi_desc, | 331 | static 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 | ||
310 | static bool add_flush(struct acpi_nfit_desc *acpi_desc, | 355 | static 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 | ||
327 | static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, | 379 | static 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 | ||
1606 | static 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 | |||
1548 | int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) | 1623 | int 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 | } |
1588 | EXPORT_SYMBOL_GPL(acpi_nfit_init); | 1687 | EXPORT_SYMBOL_GPL(acpi_nfit_init); |
1589 | 1688 | ||
1590 | static int acpi_nfit_add(struct acpi_device *adev) | 1689 | static 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 | |||
1727 | static 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 | ||
1776 | static 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 | |||
1639 | static const struct acpi_device_id acpi_nfit_ids[] = { | 1824 | static 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 | ||
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 329a1eba0c16..2ea5c0797c8f 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h | |||
@@ -48,6 +48,7 @@ enum { | |||
48 | struct nfit_spa { | 48 | struct nfit_spa { |
49 | struct acpi_nfit_system_address *spa; | 49 | struct acpi_nfit_system_address *spa; |
50 | struct list_head list; | 50 | struct list_head list; |
51 | int is_registered; | ||
51 | }; | 52 | }; |
52 | 53 | ||
53 | struct nfit_dcr { | 54 | struct nfit_dcr { |
@@ -97,6 +98,7 @@ struct acpi_nfit_desc { | |||
97 | struct nvdimm_bus_descriptor nd_desc; | 98 | struct nvdimm_bus_descriptor nd_desc; |
98 | struct acpi_table_nfit *nfit; | 99 | struct acpi_table_nfit *nfit; |
99 | struct mutex spa_map_mutex; | 100 | struct mutex spa_map_mutex; |
101 | struct mutex init_mutex; | ||
100 | struct list_head spa_maps; | 102 | struct list_head spa_maps; |
101 | struct list_head memdevs; | 103 | struct list_head memdevs; |
102 | struct list_head flushes; | 104 | struct list_head flushes; |
diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 875464690117..8fc654f0807b 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c | |||
@@ -82,12 +82,12 @@ static struct devres_group * node_to_group(struct devres_node *node) | |||
82 | } | 82 | } |
83 | 83 | ||
84 | static __always_inline struct devres * alloc_dr(dr_release_t release, | 84 | static __always_inline struct devres * alloc_dr(dr_release_t release, |
85 | size_t size, gfp_t gfp) | 85 | size_t size, gfp_t gfp, int nid) |
86 | { | 86 | { |
87 | size_t tot_size = sizeof(struct devres) + size; | 87 | size_t tot_size = sizeof(struct devres) + size; |
88 | struct devres *dr; | 88 | struct devres *dr; |
89 | 89 | ||
90 | dr = kmalloc_track_caller(tot_size, gfp); | 90 | dr = kmalloc_node_track_caller(tot_size, gfp, nid); |
91 | if (unlikely(!dr)) | 91 | if (unlikely(!dr)) |
92 | return NULL; | 92 | return NULL; |
93 | 93 | ||
@@ -106,24 +106,25 @@ static void add_dr(struct device *dev, struct devres_node *node) | |||
106 | } | 106 | } |
107 | 107 | ||
108 | #ifdef CONFIG_DEBUG_DEVRES | 108 | #ifdef CONFIG_DEBUG_DEVRES |
109 | void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp, | 109 | void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid, |
110 | const char *name) | 110 | const char *name) |
111 | { | 111 | { |
112 | struct devres *dr; | 112 | struct devres *dr; |
113 | 113 | ||
114 | dr = alloc_dr(release, size, gfp | __GFP_ZERO); | 114 | dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid); |
115 | if (unlikely(!dr)) | 115 | if (unlikely(!dr)) |
116 | return NULL; | 116 | return NULL; |
117 | set_node_dbginfo(&dr->node, name, size); | 117 | set_node_dbginfo(&dr->node, name, size); |
118 | return dr->data; | 118 | return dr->data; |
119 | } | 119 | } |
120 | EXPORT_SYMBOL_GPL(__devres_alloc); | 120 | EXPORT_SYMBOL_GPL(__devres_alloc_node); |
121 | #else | 121 | #else |
122 | /** | 122 | /** |
123 | * devres_alloc - Allocate device resource data | 123 | * devres_alloc - Allocate device resource data |
124 | * @release: Release function devres will be associated with | 124 | * @release: Release function devres will be associated with |
125 | * @size: Allocation size | 125 | * @size: Allocation size |
126 | * @gfp: Allocation flags | 126 | * @gfp: Allocation flags |
127 | * @nid: NUMA node | ||
127 | * | 128 | * |
128 | * Allocate devres of @size bytes. The allocated area is zeroed, then | 129 | * Allocate devres of @size bytes. The allocated area is zeroed, then |
129 | * associated with @release. The returned pointer can be passed to | 130 | * associated with @release. The returned pointer can be passed to |
@@ -132,16 +133,16 @@ EXPORT_SYMBOL_GPL(__devres_alloc); | |||
132 | * RETURNS: | 133 | * RETURNS: |
133 | * Pointer to allocated devres on success, NULL on failure. | 134 | * Pointer to allocated devres on success, NULL on failure. |
134 | */ | 135 | */ |
135 | void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp) | 136 | void * devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid) |
136 | { | 137 | { |
137 | struct devres *dr; | 138 | struct devres *dr; |
138 | 139 | ||
139 | dr = alloc_dr(release, size, gfp | __GFP_ZERO); | 140 | dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid); |
140 | if (unlikely(!dr)) | 141 | if (unlikely(!dr)) |
141 | return NULL; | 142 | return NULL; |
142 | return dr->data; | 143 | return dr->data; |
143 | } | 144 | } |
144 | EXPORT_SYMBOL_GPL(devres_alloc); | 145 | EXPORT_SYMBOL_GPL(devres_alloc_node); |
145 | #endif | 146 | #endif |
146 | 147 | ||
147 | /** | 148 | /** |
@@ -776,7 +777,7 @@ void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) | |||
776 | struct devres *dr; | 777 | struct devres *dr; |
777 | 778 | ||
778 | /* use raw alloc_dr for kmalloc caller tracing */ | 779 | /* use raw alloc_dr for kmalloc caller tracing */ |
779 | dr = alloc_dr(devm_kmalloc_release, size, gfp); | 780 | dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev)); |
780 | if (unlikely(!dr)) | 781 | if (unlikely(!dr)) |
781 | return NULL; | 782 | return NULL; |
782 | 783 | ||
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 0ba6a978f227..349f03e7ed06 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c | |||
@@ -150,18 +150,15 @@ static struct pmem_device *pmem_alloc(struct device *dev, | |||
150 | return ERR_PTR(-EBUSY); | 150 | return ERR_PTR(-EBUSY); |
151 | } | 151 | } |
152 | 152 | ||
153 | if (pmem_should_map_pages(dev)) { | 153 | if (pmem_should_map_pages(dev)) |
154 | void *addr = devm_memremap_pages(dev, res); | 154 | pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res); |
155 | else | ||
156 | pmem->virt_addr = (void __pmem *) devm_memremap(dev, | ||
157 | pmem->phys_addr, pmem->size, | ||
158 | ARCH_MEMREMAP_PMEM); | ||
155 | 159 | ||
156 | if (IS_ERR(addr)) | 160 | if (IS_ERR(pmem->virt_addr)) |
157 | return addr; | 161 | return (void __force *) pmem->virt_addr; |
158 | pmem->virt_addr = (void __pmem *) addr; | ||
159 | } else { | ||
160 | pmem->virt_addr = memremap_pmem(dev, pmem->phys_addr, | ||
161 | pmem->size); | ||
162 | if (!pmem->virt_addr) | ||
163 | return ERR_PTR(-ENXIO); | ||
164 | } | ||
165 | 162 | ||
166 | return pmem; | 163 | return pmem; |
167 | } | 164 | } |
@@ -179,9 +176,10 @@ static void pmem_detach_disk(struct pmem_device *pmem) | |||
179 | static int pmem_attach_disk(struct device *dev, | 176 | static int pmem_attach_disk(struct device *dev, |
180 | struct nd_namespace_common *ndns, struct pmem_device *pmem) | 177 | struct nd_namespace_common *ndns, struct pmem_device *pmem) |
181 | { | 178 | { |
179 | int nid = dev_to_node(dev); | ||
182 | struct gendisk *disk; | 180 | struct gendisk *disk; |
183 | 181 | ||
184 | pmem->pmem_queue = blk_alloc_queue(GFP_KERNEL); | 182 | pmem->pmem_queue = blk_alloc_queue_node(GFP_KERNEL, nid); |
185 | if (!pmem->pmem_queue) | 183 | if (!pmem->pmem_queue) |
186 | return -ENOMEM; | 184 | return -ENOMEM; |
187 | 185 | ||
@@ -191,7 +189,7 @@ static int pmem_attach_disk(struct device *dev, | |||
191 | blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY); | 189 | blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY); |
192 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, pmem->pmem_queue); | 190 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, pmem->pmem_queue); |
193 | 191 | ||
194 | disk = alloc_disk(0); | 192 | disk = alloc_disk_node(0, nid); |
195 | if (!disk) { | 193 | if (!disk) { |
196 | blk_cleanup_queue(pmem->pmem_queue); | 194 | blk_cleanup_queue(pmem->pmem_queue); |
197 | return -ENOMEM; | 195 | return -ENOMEM; |
@@ -363,8 +361,8 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns) | |||
363 | 361 | ||
364 | /* establish pfn range for lookup, and switch to direct map */ | 362 | /* establish pfn range for lookup, and switch to direct map */ |
365 | pmem = dev_get_drvdata(dev); | 363 | pmem = dev_get_drvdata(dev); |
366 | memunmap_pmem(dev, pmem->virt_addr); | 364 | devm_memunmap(dev, (void __force *) pmem->virt_addr); |
367 | pmem->virt_addr = (void __pmem *)devm_memremap_pages(dev, &nsio->res); | 365 | pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res); |
368 | if (IS_ERR(pmem->virt_addr)) { | 366 | if (IS_ERR(pmem->virt_addr)) { |
369 | rc = PTR_ERR(pmem->virt_addr); | 367 | rc = PTR_ERR(pmem->virt_addr); |
370 | goto err; | 368 | goto err; |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6b659967898e..5f399ea1d20a 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/utsname.h> | 35 | #include <linux/utsname.h> |
36 | #include <linux/coredump.h> | 36 | #include <linux/coredump.h> |
37 | #include <linux/sched.h> | 37 | #include <linux/sched.h> |
38 | #include <linux/dax.h> | ||
38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
39 | #include <asm/param.h> | 40 | #include <asm/param.h> |
40 | #include <asm/page.h> | 41 | #include <asm/page.h> |
@@ -1236,6 +1237,15 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, | |||
1236 | if (vma->vm_flags & VM_DONTDUMP) | 1237 | if (vma->vm_flags & VM_DONTDUMP) |
1237 | return 0; | 1238 | return 0; |
1238 | 1239 | ||
1240 | /* support for DAX */ | ||
1241 | if (vma_is_dax(vma)) { | ||
1242 | if ((vma->vm_flags & VM_SHARED) && FILTER(DAX_SHARED)) | ||
1243 | goto whole; | ||
1244 | if (!(vma->vm_flags & VM_SHARED) && FILTER(DAX_PRIVATE)) | ||
1245 | goto whole; | ||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1239 | /* Hugetlb memory check */ | 1249 | /* Hugetlb memory check */ |
1240 | if (vma->vm_flags & VM_HUGETLB) { | 1250 | if (vma->vm_flags & VM_HUGETLB) { |
1241 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) | 1251 | if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED)) |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 50d15b7b0ca9..b1adb92e69de 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/elf-fdpic.h> | 35 | #include <linux/elf-fdpic.h> |
36 | #include <linux/elfcore.h> | 36 | #include <linux/elfcore.h> |
37 | #include <linux/coredump.h> | 37 | #include <linux/coredump.h> |
38 | #include <linux/dax.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | #include <asm/param.h> | 41 | #include <asm/param.h> |
@@ -1231,6 +1232,20 @@ static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) | |||
1231 | return 0; | 1232 | return 0; |
1232 | } | 1233 | } |
1233 | 1234 | ||
1235 | /* support for DAX */ | ||
1236 | if (vma_is_dax(vma)) { | ||
1237 | if (vma->vm_flags & VM_SHARED) { | ||
1238 | dump_ok = test_bit(MMF_DUMP_DAX_SHARED, &mm_flags); | ||
1239 | kdcore("%08lx: %08lx: %s (DAX shared)", vma->vm_start, | ||
1240 | vma->vm_flags, dump_ok ? "yes" : "no"); | ||
1241 | } else { | ||
1242 | dump_ok = test_bit(MMF_DUMP_DAX_PRIVATE, &mm_flags); | ||
1243 | kdcore("%08lx: %08lx: %s (DAX private)", vma->vm_start, | ||
1244 | vma->vm_flags, dump_ok ? "yes" : "no"); | ||
1245 | } | ||
1246 | return dump_ok; | ||
1247 | } | ||
1248 | |||
1234 | /* By default, dump shared memory if mapped from an anonymous file. */ | 1249 | /* By default, dump shared memory if mapped from an anonymous file. */ |
1235 | if (vma->vm_flags & VM_SHARED) { | 1250 | if (vma->vm_flags & VM_SHARED) { |
1236 | if (file_inode(vma->vm_file)->i_nlink == 0) { | 1251 | if (file_inode(vma->vm_file)->i_nlink == 0) { |
diff --git a/include/linux/device.h b/include/linux/device.h index 5d7bc6349930..b8f411b57dcb 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -604,13 +604,21 @@ typedef void (*dr_release_t)(struct device *dev, void *res); | |||
604 | typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); | 604 | typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); |
605 | 605 | ||
606 | #ifdef CONFIG_DEBUG_DEVRES | 606 | #ifdef CONFIG_DEBUG_DEVRES |
607 | extern void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, | 607 | extern void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, |
608 | const char *name); | 608 | int nid, const char *name); |
609 | #define devres_alloc(release, size, gfp) \ | 609 | #define devres_alloc(release, size, gfp) \ |
610 | __devres_alloc(release, size, gfp, #release) | 610 | __devres_alloc_node(release, size, gfp, NUMA_NO_NODE, #release) |
611 | #define devres_alloc_node(release, size, gfp, nid) \ | ||
612 | __devres_alloc_node(release, size, gfp, nid, #release) | ||
611 | #else | 613 | #else |
612 | extern void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp); | 614 | extern void *devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, |
615 | int nid); | ||
616 | static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp) | ||
617 | { | ||
618 | return devres_alloc_node(release, size, gfp, NUMA_NO_NODE); | ||
619 | } | ||
613 | #endif | 620 | #endif |
621 | |||
614 | extern void devres_for_each_res(struct device *dev, dr_release_t release, | 622 | extern void devres_for_each_res(struct device *dev, dr_release_t release, |
615 | dr_match_t match, void *match_data, | 623 | dr_match_t match, void *match_data, |
616 | void (*fn)(struct device *, void *, void *), | 624 | void (*fn)(struct device *, void *, void *), |
diff --git a/include/linux/pmem.h b/include/linux/pmem.h index 85f810b33917..acfea8ce4a07 100644 --- a/include/linux/pmem.h +++ b/include/linux/pmem.h | |||
@@ -65,11 +65,6 @@ static inline void memcpy_from_pmem(void *dst, void __pmem const *src, size_t si | |||
65 | memcpy(dst, (void __force const *) src, size); | 65 | memcpy(dst, (void __force const *) src, size); |
66 | } | 66 | } |
67 | 67 | ||
68 | static inline void memunmap_pmem(struct device *dev, void __pmem *addr) | ||
69 | { | ||
70 | devm_memunmap(dev, (void __force *) addr); | ||
71 | } | ||
72 | |||
73 | static inline bool arch_has_pmem_api(void) | 68 | static inline bool arch_has_pmem_api(void) |
74 | { | 69 | { |
75 | return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API); | 70 | return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API); |
@@ -93,7 +88,7 @@ static inline bool arch_has_wmb_pmem(void) | |||
93 | * These defaults seek to offer decent performance and minimize the | 88 | * These defaults seek to offer decent performance and minimize the |
94 | * window between i/o completion and writes being durable on media. | 89 | * window between i/o completion and writes being durable on media. |
95 | * However, it is undefined / architecture specific whether | 90 | * However, it is undefined / architecture specific whether |
96 | * default_memremap_pmem + default_memcpy_to_pmem is sufficient for | 91 | * ARCH_MEMREMAP_PMEM + default_memcpy_to_pmem is sufficient for |
97 | * making data durable relative to i/o completion. | 92 | * making data durable relative to i/o completion. |
98 | */ | 93 | */ |
99 | static inline void default_memcpy_to_pmem(void __pmem *dst, const void *src, | 94 | static inline void default_memcpy_to_pmem(void __pmem *dst, const void *src, |
@@ -117,25 +112,6 @@ static inline void default_clear_pmem(void __pmem *addr, size_t size) | |||
117 | } | 112 | } |
118 | 113 | ||
119 | /** | 114 | /** |
120 | * memremap_pmem - map physical persistent memory for pmem api | ||
121 | * @offset: physical address of persistent memory | ||
122 | * @size: size of the mapping | ||
123 | * | ||
124 | * Establish a mapping of the architecture specific memory type expected | ||
125 | * by memcpy_to_pmem() and wmb_pmem(). For example, it may be | ||
126 | * the case that an uncacheable or writethrough mapping is sufficient, | ||
127 | * or a writeback mapping provided memcpy_to_pmem() and | ||
128 | * wmb_pmem() arrange for the data to be written through the | ||
129 | * cache to persistent media. | ||
130 | */ | ||
131 | static inline void __pmem *memremap_pmem(struct device *dev, | ||
132 | resource_size_t offset, unsigned long size) | ||
133 | { | ||
134 | return (void __pmem *) devm_memremap(dev, offset, size, | ||
135 | ARCH_MEMREMAP_PMEM); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * memcpy_to_pmem - copy data to persistent memory | 115 | * memcpy_to_pmem - copy data to persistent memory |
140 | * @dst: destination buffer for the copy | 116 | * @dst: destination buffer for the copy |
141 | * @src: source buffer for the copy | 117 | * @src: source buffer for the copy |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 4069febaa34a..edad7a43edea 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -484,9 +484,11 @@ static inline int get_dumpable(struct mm_struct *mm) | |||
484 | #define MMF_DUMP_ELF_HEADERS 6 | 484 | #define MMF_DUMP_ELF_HEADERS 6 |
485 | #define MMF_DUMP_HUGETLB_PRIVATE 7 | 485 | #define MMF_DUMP_HUGETLB_PRIVATE 7 |
486 | #define MMF_DUMP_HUGETLB_SHARED 8 | 486 | #define MMF_DUMP_HUGETLB_SHARED 8 |
487 | #define MMF_DUMP_DAX_PRIVATE 9 | ||
488 | #define MMF_DUMP_DAX_SHARED 10 | ||
487 | 489 | ||
488 | #define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS | 490 | #define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS |
489 | #define MMF_DUMP_FILTER_BITS 7 | 491 | #define MMF_DUMP_FILTER_BITS 9 |
490 | #define MMF_DUMP_FILTER_MASK \ | 492 | #define MMF_DUMP_FILTER_MASK \ |
491 | (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) | 493 | (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) |
492 | #define MMF_DUMP_FILTER_DEFAULT \ | 494 | #define MMF_DUMP_FILTER_DEFAULT \ |
diff --git a/kernel/memremap.c b/kernel/memremap.c index 9d6b55587eaa..7658d32c5c78 100644 --- a/kernel/memremap.c +++ b/kernel/memremap.c | |||
@@ -124,9 +124,10 @@ void *devm_memremap(struct device *dev, resource_size_t offset, | |||
124 | { | 124 | { |
125 | void **ptr, *addr; | 125 | void **ptr, *addr; |
126 | 126 | ||
127 | ptr = devres_alloc(devm_memremap_release, sizeof(*ptr), GFP_KERNEL); | 127 | ptr = devres_alloc_node(devm_memremap_release, sizeof(*ptr), GFP_KERNEL, |
128 | dev_to_node(dev)); | ||
128 | if (!ptr) | 129 | if (!ptr) |
129 | return NULL; | 130 | return ERR_PTR(-ENOMEM); |
130 | 131 | ||
131 | addr = memremap(offset, size, flags); | 132 | addr = memremap(offset, size, flags); |
132 | if (addr) { | 133 | if (addr) { |
@@ -141,9 +142,8 @@ EXPORT_SYMBOL(devm_memremap); | |||
141 | 142 | ||
142 | void devm_memunmap(struct device *dev, void *addr) | 143 | void devm_memunmap(struct device *dev, void *addr) |
143 | { | 144 | { |
144 | WARN_ON(devres_destroy(dev, devm_memremap_release, devm_memremap_match, | 145 | WARN_ON(devres_release(dev, devm_memremap_release, |
145 | addr)); | 146 | devm_memremap_match, addr)); |
146 | memunmap(addr); | ||
147 | } | 147 | } |
148 | EXPORT_SYMBOL(devm_memunmap); | 148 | EXPORT_SYMBOL(devm_memunmap); |
149 | 149 | ||
@@ -176,8 +176,8 @@ void *devm_memremap_pages(struct device *dev, struct resource *res) | |||
176 | if (is_ram == REGION_INTERSECTS) | 176 | if (is_ram == REGION_INTERSECTS) |
177 | return __va(res->start); | 177 | return __va(res->start); |
178 | 178 | ||
179 | page_map = devres_alloc(devm_memremap_pages_release, | 179 | page_map = devres_alloc_node(devm_memremap_pages_release, |
180 | sizeof(*page_map), GFP_KERNEL); | 180 | sizeof(*page_map), GFP_KERNEL, dev_to_node(dev)); |
181 | if (!page_map) | 181 | if (!page_map) |
182 | return ERR_PTR(-ENOMEM); | 182 | return ERR_PTR(-ENOMEM); |
183 | 183 | ||
@@ -185,7 +185,7 @@ void *devm_memremap_pages(struct device *dev, struct resource *res) | |||
185 | 185 | ||
186 | nid = dev_to_node(dev); | 186 | nid = dev_to_node(dev); |
187 | if (nid < 0) | 187 | if (nid < 0) |
188 | nid = 0; | 188 | nid = numa_mem_id(); |
189 | 189 | ||
190 | error = arch_add_memory(nid, res->start, resource_size(res), true); | 190 | error = arch_add_memory(nid, res->start, resource_size(res), true); |
191 | if (error) { | 191 | if (error) { |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 021e6f97f33e..dce346aa94ea 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -17,8 +17,10 @@ | |||
17 | #include <linux/vmalloc.h> | 17 | #include <linux/vmalloc.h> |
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/mutex.h> | ||
20 | #include <linux/ndctl.h> | 21 | #include <linux/ndctl.h> |
21 | #include <linux/sizes.h> | 22 | #include <linux/sizes.h> |
23 | #include <linux/list.h> | ||
22 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
23 | #include <nfit.h> | 25 | #include <nfit.h> |
24 | #include <nd.h> | 26 | #include <nd.h> |
@@ -44,6 +46,15 @@ | |||
44 | * +------+ | blk5.0 | pm1.0 | 3 region5 | 46 | * +------+ | blk5.0 | pm1.0 | 3 region5 |
45 | * +-------------------------+----------+-+-------+ | 47 | * +-------------------------+----------+-+-------+ |
46 | * | 48 | * |
49 | * +--+---+ | ||
50 | * | cpu1 | | ||
51 | * +--+---+ (Hotplug DIMM) | ||
52 | * | +----------------------------------------------+ | ||
53 | * +--+---+ | blk6.0/pm7.0 | 4 region6/7 | ||
54 | * | imc0 +--+----------------------------------------------+ | ||
55 | * +------+ | ||
56 | * | ||
57 | * | ||
47 | * *) In this layout we have four dimms and two memory controllers in one | 58 | * *) In this layout we have four dimms and two memory controllers in one |
48 | * socket. Each unique interface (BLK or PMEM) to DPA space | 59 | * socket. Each unique interface (BLK or PMEM) to DPA space |
49 | * is identified by a region device with a dynamically assigned id. | 60 | * is identified by a region device with a dynamically assigned id. |
@@ -85,8 +96,8 @@ | |||
85 | * reference an NVDIMM. | 96 | * reference an NVDIMM. |
86 | */ | 97 | */ |
87 | enum { | 98 | enum { |
88 | NUM_PM = 2, | 99 | NUM_PM = 3, |
89 | NUM_DCR = 4, | 100 | NUM_DCR = 5, |
90 | NUM_BDW = NUM_DCR, | 101 | NUM_BDW = NUM_DCR, |
91 | NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, | 102 | NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, |
92 | NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */, | 103 | NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */, |
@@ -115,6 +126,7 @@ static u32 handle[NUM_DCR] = { | |||
115 | [1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1), | 126 | [1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1), |
116 | [2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0), | 127 | [2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0), |
117 | [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), | 128 | [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), |
129 | [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), | ||
118 | }; | 130 | }; |
119 | 131 | ||
120 | struct nfit_test { | 132 | struct nfit_test { |
@@ -138,6 +150,7 @@ struct nfit_test { | |||
138 | dma_addr_t *dcr_dma; | 150 | dma_addr_t *dcr_dma; |
139 | int (*alloc)(struct nfit_test *t); | 151 | int (*alloc)(struct nfit_test *t); |
140 | void (*setup)(struct nfit_test *t); | 152 | void (*setup)(struct nfit_test *t); |
153 | int setup_hotplug; | ||
141 | }; | 154 | }; |
142 | 155 | ||
143 | static struct nfit_test *to_nfit_test(struct device *dev) | 156 | static struct nfit_test *to_nfit_test(struct device *dev) |
@@ -428,6 +441,10 @@ static int nfit_test0_alloc(struct nfit_test *t) | |||
428 | if (!t->spa_set[1]) | 441 | if (!t->spa_set[1]) |
429 | return -ENOMEM; | 442 | return -ENOMEM; |
430 | 443 | ||
444 | t->spa_set[2] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[2]); | ||
445 | if (!t->spa_set[2]) | ||
446 | return -ENOMEM; | ||
447 | |||
431 | for (i = 0; i < NUM_DCR; i++) { | 448 | for (i = 0; i < NUM_DCR; i++) { |
432 | t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]); | 449 | t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]); |
433 | if (!t->dimm[i]) | 450 | if (!t->dimm[i]) |
@@ -950,6 +967,126 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
950 | flush->hint_count = 1; | 967 | flush->hint_count = 1; |
951 | flush->hint_address[0] = t->flush_dma[3]; | 968 | flush->hint_address[0] = t->flush_dma[3]; |
952 | 969 | ||
970 | if (t->setup_hotplug) { | ||
971 | offset = offset + sizeof(struct acpi_nfit_flush_address) * 4; | ||
972 | /* dcr-descriptor4 */ | ||
973 | dcr = nfit_buf + offset; | ||
974 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | ||
975 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | ||
976 | dcr->region_index = 4+1; | ||
977 | dcr->vendor_id = 0xabcd; | ||
978 | dcr->device_id = 0; | ||
979 | dcr->revision_id = 1; | ||
980 | dcr->serial_number = ~handle[4]; | ||
981 | dcr->windows = 1; | ||
982 | dcr->window_size = DCR_SIZE; | ||
983 | dcr->command_offset = 0; | ||
984 | dcr->command_size = 8; | ||
985 | dcr->status_offset = 8; | ||
986 | dcr->status_size = 4; | ||
987 | |||
988 | offset = offset + sizeof(struct acpi_nfit_control_region); | ||
989 | /* bdw4 (spa/dcr4, dimm4) */ | ||
990 | bdw = nfit_buf + offset; | ||
991 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | ||
992 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | ||
993 | bdw->region_index = 4+1; | ||
994 | bdw->windows = 1; | ||
995 | bdw->offset = 0; | ||
996 | bdw->size = BDW_SIZE; | ||
997 | bdw->capacity = DIMM_SIZE; | ||
998 | bdw->start_address = 0; | ||
999 | |||
1000 | offset = offset + sizeof(struct acpi_nfit_data_region); | ||
1001 | /* spa10 (dcr4) dimm4 */ | ||
1002 | spa = nfit_buf + offset; | ||
1003 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | ||
1004 | spa->header.length = sizeof(*spa); | ||
1005 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | ||
1006 | spa->range_index = 10+1; | ||
1007 | spa->address = t->dcr_dma[4]; | ||
1008 | spa->length = DCR_SIZE; | ||
1009 | |||
1010 | /* | ||
1011 | * spa11 (single-dimm interleave for hotplug, note storage | ||
1012 | * does not actually alias the related block-data-window | ||
1013 | * regions) | ||
1014 | */ | ||
1015 | spa = nfit_buf + offset + sizeof(*spa); | ||
1016 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | ||
1017 | spa->header.length = sizeof(*spa); | ||
1018 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); | ||
1019 | spa->range_index = 11+1; | ||
1020 | spa->address = t->spa_set_dma[2]; | ||
1021 | spa->length = SPA0_SIZE; | ||
1022 | |||
1023 | /* spa12 (bdw for dcr4) dimm4 */ | ||
1024 | spa = nfit_buf + offset + sizeof(*spa) * 2; | ||
1025 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | ||
1026 | spa->header.length = sizeof(*spa); | ||
1027 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | ||
1028 | spa->range_index = 12+1; | ||
1029 | spa->address = t->dimm_dma[4]; | ||
1030 | spa->length = DIMM_SIZE; | ||
1031 | |||
1032 | offset = offset + sizeof(*spa) * 3; | ||
1033 | /* mem-region14 (spa/dcr4, dimm4) */ | ||
1034 | memdev = nfit_buf + offset; | ||
1035 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | ||
1036 | memdev->header.length = sizeof(*memdev); | ||
1037 | memdev->device_handle = handle[4]; | ||
1038 | memdev->physical_id = 4; | ||
1039 | memdev->region_id = 0; | ||
1040 | memdev->range_index = 10+1; | ||
1041 | memdev->region_index = 4+1; | ||
1042 | memdev->region_size = 0; | ||
1043 | memdev->region_offset = 0; | ||
1044 | memdev->address = 0; | ||
1045 | memdev->interleave_index = 0; | ||
1046 | memdev->interleave_ways = 1; | ||
1047 | |||
1048 | /* mem-region15 (spa0, dimm4) */ | ||
1049 | memdev = nfit_buf + offset + | ||
1050 | sizeof(struct acpi_nfit_memory_map); | ||
1051 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | ||
1052 | memdev->header.length = sizeof(*memdev); | ||
1053 | memdev->device_handle = handle[4]; | ||
1054 | memdev->physical_id = 4; | ||
1055 | memdev->region_id = 0; | ||
1056 | memdev->range_index = 11+1; | ||
1057 | memdev->region_index = 4+1; | ||
1058 | memdev->region_size = SPA0_SIZE; | ||
1059 | memdev->region_offset = t->spa_set_dma[2]; | ||
1060 | memdev->address = 0; | ||
1061 | memdev->interleave_index = 0; | ||
1062 | memdev->interleave_ways = 1; | ||
1063 | |||
1064 | /* mem-region16 (spa/dcr4, dimm4) */ | ||
1065 | memdev = nfit_buf + offset + | ||
1066 | sizeof(struct acpi_nfit_memory_map) * 2; | ||
1067 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | ||
1068 | memdev->header.length = sizeof(*memdev); | ||
1069 | memdev->device_handle = handle[4]; | ||
1070 | memdev->physical_id = 4; | ||
1071 | memdev->region_id = 0; | ||
1072 | memdev->range_index = 12+1; | ||
1073 | memdev->region_index = 4+1; | ||
1074 | memdev->region_size = 0; | ||
1075 | memdev->region_offset = 0; | ||
1076 | memdev->address = 0; | ||
1077 | memdev->interleave_index = 0; | ||
1078 | memdev->interleave_ways = 1; | ||
1079 | |||
1080 | offset = offset + sizeof(struct acpi_nfit_memory_map) * 3; | ||
1081 | /* flush3 (dimm4) */ | ||
1082 | flush = nfit_buf + offset; | ||
1083 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | ||
1084 | flush->header.length = sizeof(struct acpi_nfit_flush_address); | ||
1085 | flush->device_handle = handle[4]; | ||
1086 | flush->hint_count = 1; | ||
1087 | flush->hint_address[0] = t->flush_dma[4]; | ||
1088 | } | ||
1089 | |||
953 | acpi_desc = &t->acpi_desc; | 1090 | acpi_desc = &t->acpi_desc; |
954 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); | 1091 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); |
955 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 1092 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); |
@@ -1108,6 +1245,29 @@ static int nfit_test_probe(struct platform_device *pdev) | |||
1108 | if (!acpi_desc->nvdimm_bus) | 1245 | if (!acpi_desc->nvdimm_bus) |
1109 | return -ENXIO; | 1246 | return -ENXIO; |
1110 | 1247 | ||
1248 | INIT_LIST_HEAD(&acpi_desc->spa_maps); | ||
1249 | INIT_LIST_HEAD(&acpi_desc->spas); | ||
1250 | INIT_LIST_HEAD(&acpi_desc->dcrs); | ||
1251 | INIT_LIST_HEAD(&acpi_desc->bdws); | ||
1252 | INIT_LIST_HEAD(&acpi_desc->idts); | ||
1253 | INIT_LIST_HEAD(&acpi_desc->flushes); | ||
1254 | INIT_LIST_HEAD(&acpi_desc->memdevs); | ||
1255 | INIT_LIST_HEAD(&acpi_desc->dimms); | ||
1256 | mutex_init(&acpi_desc->spa_map_mutex); | ||
1257 | mutex_init(&acpi_desc->init_mutex); | ||
1258 | |||
1259 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size); | ||
1260 | if (rc) { | ||
1261 | nvdimm_bus_unregister(acpi_desc->nvdimm_bus); | ||
1262 | return rc; | ||
1263 | } | ||
1264 | |||
1265 | if (nfit_test->setup != nfit_test0_setup) | ||
1266 | return 0; | ||
1267 | |||
1268 | nfit_test->setup_hotplug = 1; | ||
1269 | nfit_test->setup(nfit_test); | ||
1270 | |||
1111 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size); | 1271 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size); |
1112 | if (rc) { | 1272 | if (rc) { |
1113 | nvdimm_bus_unregister(acpi_desc->nvdimm_bus); | 1273 | nvdimm_bus_unregister(acpi_desc->nvdimm_bus); |