aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2015-04-25 03:56:17 -0400
committerDan Williams <dan.j.williams@intel.com>2015-06-24 21:24:10 -0400
commite6dfb2de47768efe8cc37c9a1863d2aff81440fb (patch)
treea1ad89328d88a37195f23ca9421071fc29e6722f
parent45def22c1fab85764646746ce38d45b2f3281fa5 (diff)
libnvdimm, nfit: dimm/memory-devices
Enable nvdimm devices to be registered on a nvdimm_bus. The kernel assigned device id for nvdimm devicesis dynamic. If userspace needs a more static identifier it should consult a provider-specific attribute. In the case where NFIT is the provider, the 'nmemX/nfit/handle' or 'nmemX/nfit/serial' attributes may be used for this purpose. Cc: Neil Brown <neilb@suse.de> Cc: <linux-acpi@vger.kernel.org> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Robert Moore <robert.moore@intel.com> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Christoph Hellwig <hch@lst.de> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Toshi Kani <toshi.kani@hp.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/acpi/nfit.c161
-rw-r--r--drivers/acpi/nfit.h1
-rw-r--r--drivers/nvdimm/Makefile1
-rw-r--r--drivers/nvdimm/bus.c14
-rw-r--r--drivers/nvdimm/core.c33
-rw-r--r--drivers/nvdimm/dimm_devs.c92
-rw-r--r--drivers/nvdimm/nd-core.h12
-rw-r--r--include/linux/libnvdimm.h11
8 files changed, 321 insertions, 4 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index 162391b32022..9fd7781f966e 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -381,6 +381,165 @@ static const struct attribute_group *acpi_nfit_attribute_groups[] = {
381 NULL, 381 NULL,
382}; 382};
383 383
384static struct acpi_nfit_memory_map *to_nfit_memdev(struct device *dev)
385{
386 struct nvdimm *nvdimm = to_nvdimm(dev);
387 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
388
389 return __to_nfit_memdev(nfit_mem);
390}
391
392static struct acpi_nfit_control_region *to_nfit_dcr(struct device *dev)
393{
394 struct nvdimm *nvdimm = to_nvdimm(dev);
395 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
396
397 return nfit_mem->dcr;
398}
399
400static ssize_t handle_show(struct device *dev,
401 struct device_attribute *attr, char *buf)
402{
403 struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
404
405 return sprintf(buf, "%#x\n", memdev->device_handle);
406}
407static DEVICE_ATTR_RO(handle);
408
409static ssize_t phys_id_show(struct device *dev,
410 struct device_attribute *attr, char *buf)
411{
412 struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
413
414 return sprintf(buf, "%#x\n", memdev->physical_id);
415}
416static DEVICE_ATTR_RO(phys_id);
417
418static ssize_t vendor_show(struct device *dev,
419 struct device_attribute *attr, char *buf)
420{
421 struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
422
423 return sprintf(buf, "%#x\n", dcr->vendor_id);
424}
425static DEVICE_ATTR_RO(vendor);
426
427static ssize_t rev_id_show(struct device *dev,
428 struct device_attribute *attr, char *buf)
429{
430 struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
431
432 return sprintf(buf, "%#x\n", dcr->revision_id);
433}
434static DEVICE_ATTR_RO(rev_id);
435
436static ssize_t device_show(struct device *dev,
437 struct device_attribute *attr, char *buf)
438{
439 struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
440
441 return sprintf(buf, "%#x\n", dcr->device_id);
442}
443static DEVICE_ATTR_RO(device);
444
445static ssize_t format_show(struct device *dev,
446 struct device_attribute *attr, char *buf)
447{
448 struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
449
450 return sprintf(buf, "%#x\n", dcr->code);
451}
452static DEVICE_ATTR_RO(format);
453
454static ssize_t serial_show(struct device *dev,
455 struct device_attribute *attr, char *buf)
456{
457 struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
458
459 return sprintf(buf, "%#x\n", dcr->serial_number);
460}
461static DEVICE_ATTR_RO(serial);
462
463static struct attribute *acpi_nfit_dimm_attributes[] = {
464 &dev_attr_handle.attr,
465 &dev_attr_phys_id.attr,
466 &dev_attr_vendor.attr,
467 &dev_attr_device.attr,
468 &dev_attr_format.attr,
469 &dev_attr_serial.attr,
470 &dev_attr_rev_id.attr,
471 NULL,
472};
473
474static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
475 struct attribute *a, int n)
476{
477 struct device *dev = container_of(kobj, struct device, kobj);
478
479 if (to_nfit_dcr(dev))
480 return a->mode;
481 else
482 return 0;
483}
484
485static struct attribute_group acpi_nfit_dimm_attribute_group = {
486 .name = "nfit",
487 .attrs = acpi_nfit_dimm_attributes,
488 .is_visible = acpi_nfit_dimm_attr_visible,
489};
490
491static const struct attribute_group *acpi_nfit_dimm_attribute_groups[] = {
492 &acpi_nfit_dimm_attribute_group,
493 NULL,
494};
495
496static struct nvdimm *acpi_nfit_dimm_by_handle(struct acpi_nfit_desc *acpi_desc,
497 u32 device_handle)
498{
499 struct nfit_mem *nfit_mem;
500
501 list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
502 if (__to_nfit_memdev(nfit_mem)->device_handle == device_handle)
503 return nfit_mem->nvdimm;
504
505 return NULL;
506}
507
508static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
509{
510 struct nfit_mem *nfit_mem;
511
512 list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
513 struct nvdimm *nvdimm;
514 unsigned long flags = 0;
515 u32 device_handle;
516
517 device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
518 nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle);
519 if (nvdimm) {
520 /*
521 * If for some reason we find multiple DCRs the
522 * first one wins
523 */
524 dev_err(acpi_desc->dev, "duplicate DCR detected: %s\n",
525 nvdimm_name(nvdimm));
526 continue;
527 }
528
529 if (nfit_mem->bdw && nfit_mem->memdev_pmem)
530 flags |= NDD_ALIASING;
531
532 nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
533 acpi_nfit_dimm_attribute_groups, flags);
534 if (!nvdimm)
535 return -ENOMEM;
536
537 nfit_mem->nvdimm = nvdimm;
538 }
539
540 return 0;
541}
542
384static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) 543static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
385{ 544{
386 struct device *dev = acpi_desc->dev; 545 struct device *dev = acpi_desc->dev;
@@ -408,7 +567,7 @@ static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
408 if (nfit_mem_init(acpi_desc) != 0) 567 if (nfit_mem_init(acpi_desc) != 0)
409 return -ENOMEM; 568 return -ENOMEM;
410 569
411 return 0; 570 return acpi_nfit_register_dimms(acpi_desc);
412} 571}
413 572
414static int acpi_nfit_add(struct acpi_device *adev) 573static int acpi_nfit_add(struct acpi_device *adev)
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
index eda565fa81ef..9dd437fe5563 100644
--- a/drivers/acpi/nfit.h
+++ b/drivers/acpi/nfit.h
@@ -59,6 +59,7 @@ struct nfit_memdev {
59 59
60/* assembled tables for a given dimm/memory-device */ 60/* assembled tables for a given dimm/memory-device */
61struct nfit_mem { 61struct nfit_mem {
62 struct nvdimm *nvdimm;
62 struct acpi_nfit_memory_map *memdev_dcr; 63 struct acpi_nfit_memory_map *memdev_dcr;
63 struct acpi_nfit_memory_map *memdev_pmem; 64 struct acpi_nfit_memory_map *memdev_pmem;
64 struct acpi_nfit_control_region *dcr; 65 struct acpi_nfit_control_region *dcr;
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
index 8a8293c72c7c..5b68738ba406 100644
--- a/drivers/nvdimm/Makefile
+++ b/drivers/nvdimm/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
2 2
3libnvdimm-y := core.o 3libnvdimm-y := core.o
4libnvdimm-y += bus.o 4libnvdimm-y += bus.o
5libnvdimm-y += dimm_devs.o
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 3f7c690a5d0c..a8802577fb55 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -13,6 +13,7 @@
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14#include <linux/uaccess.h> 14#include <linux/uaccess.h>
15#include <linux/fcntl.h> 15#include <linux/fcntl.h>