aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2015-06-09 20:13:14 -0400
committerDan Williams <dan.j.williams@intel.com>2015-06-24 21:24:10 -0400
commit1f7df6f88b9245a7f2d0f8ecbc97dc88c8d0d8e1 (patch)
treec3653a346b905a1e58e4caa97e4daa1c18476bbc
parent4d88a97aa9e8cfa6460aab119c5da60ad2267423 (diff)
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio block-data-window(s)), or a PMEM range (DAX-capable persistent memory or volatile memory), without regard for aliasing. Aliasing, in the dimm-local address space (DPA), is resolved by metadata on a dimm to designate which exclusive interface will access the aliased DPA ranges. Support for the per-dimm metadata/label arrvies is in a subsequent patch. The name format of "region" devices is "regionN" where, like dimms, N is a global ida index assigned at discovery time. This id is not reliable across reboots nor in the presence of hotplug. Look to attributes of the region or static id-data of the sub-namespace to generate a persistent name. However, if the platform configuration does not change it is reasonable to expect the same region id to be assigned at the next boot. "region"s have 2 generic attributes "size", and "mapping"s where: - size: the BLK accessible capacity or the span of the system physical address range in the case of PMEM. - mappingN: a tuple describing a dimm's contribution to the region's capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region there will be at least one mapping per dimm in the interleave set. For a BLK-region there is only "mapping0" listing the starting DPA of the BLK-region and the available DPA capacity of that space (matches "size" above). The max number of mappings per "region" is hard coded per the constraints of sysfs attribute groups. That said the number of mappings per region should never exceed the maximum number of possible dimms in the system. If the current number turns out to not be enough then the "mappings" attribute clarifies how many there are supposed to be. "32 should be enough for anybody...". 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.c148
-rw-r--r--drivers/nvdimm/Makefile1
-rw-r--r--drivers/nvdimm/nd-core.h3
-rw-r--r--drivers/nvdimm/nd.h11
-rw-r--r--drivers/nvdimm/region_devs.c297
-rw-r--r--include/linux/libnvdimm.h25
6 files changed, 484 insertions, 1 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index c4ccec1bc60b..068f69d70c9e 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -757,11 +757,153 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
757 set_bit(i, &nd_desc->dsm_mask); 757 set_bit(i, &nd_desc->dsm_mask);
758} 758}
759 759
760static ssize_t range_index_show(struct device *dev,
761 struct device_attribute *attr, char *buf)
762{
763 struct nd_region *nd_region = to_nd_region(dev);
764 struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region);
765
766 return sprintf(buf, "%d\n", nfit_spa->spa->range_index);
767}
768static DEVICE_ATTR_RO(range_index);
769
770static struct attribute *acpi_nfit_region_attributes[] = {
771 &dev_attr_range_index.attr,
772 NULL,
773};
774
775static struct attribute_group acpi_nfit_region_attribute_group = {
776 .name = "nfit",
777 .attrs = acpi_nfit_region_attributes,
778};
779
780static const struct attribute_group *acpi_nfit_region_attribute_groups[] = {
781 &nd_region_attribute_group,
782 &nd_mapping_attribute_group,
783 &acpi_nfit_region_attribute_group,
784 NULL,
785};
786
787static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc,
788 struct nd_mapping *nd_mapping, struct nd_region_desc *ndr_desc,
789 struct acpi_nfit_memory_map *memdev,
790 struct acpi_nfit_system_address *spa)
791{
792 struct nvdimm *nvdimm = acpi_nfit_dimm_by_handle(acpi_desc,
793 memdev->device_handle);
794 struct nfit_mem *nfit_mem;
795 int blk_valid = 0;
796
797 if (!nvdimm) {
798 dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n",
799 spa->range_index, memdev->device_handle);
800 return -ENODEV;
801 }
802
803 nd_mapping->nvdimm = nvdimm;
804 switch (nfit_spa_type(spa)) {
805 case NFIT_SPA_PM:
806 case NFIT_SPA_VOLATILE:
807 nd_mapping->start = memdev->address;
808 nd_mapping->size = memdev->region_size;
809 break;
810 case NFIT_SPA_DCR:
811 nfit_mem = nvdimm_provider_data(nvdimm);
812 if (!nfit_mem || !nfit_mem->bdw) {
813 dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n",
814 spa->range_index, nvdimm_name(nvdimm));
815 } else {
816 nd_mapping->size = nfit_mem->bdw->capacity;
817 nd_mapping->start = nfit_mem->bdw->start_address;
818 blk_valid = 1;
819 }
820
821 ndr_desc->nd_mapping = nd_mapping;
822 ndr_desc->num_mappings = blk_valid;
823 if (!nvdimm_blk_region_create(acpi_desc->nvdimm_bus, ndr_desc))
824 return -ENOMEM;
825 break;
826 }
827
828 return 0;
829}
830
831static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
832 struct nfit_spa *nfit_spa)
833{
834 static struct nd_mapping nd_mappings[ND_MAX_MAPPINGS];
835 struct acpi_nfit_system_address *spa = nfit_spa->spa;
836 struct nfit_memdev *nfit_memdev;
837 struct nd_region_desc ndr_desc;
838 struct nvdimm_bus *nvdimm_bus;
839 struct resource res;
840 int count = 0;
841
842 if (spa->range_index == 0) {
843 dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n",
844 __func__);
845 return 0;
846 }
847
848 memset(&res, 0, sizeof(res));
849 memset(&nd_mappings, 0, sizeof(nd_mappings));
850 memset(&ndr_desc, 0, sizeof(ndr_desc));
851 res.start = spa->address;
852 res.end = res.start + spa->length - 1;
853 ndr_desc.res = &res;
854 ndr_desc.provider_data = nfit_spa;
855 ndr_desc.attr_groups = acpi_nfit_region_attribute_groups;
856 list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
857 struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
858 struct nd_mapping *nd_mapping;
859 int rc;
860
861 if (memdev->range_index != spa->range_index)
862 continue;
863 if (count >= ND_MAX_MAPPINGS) {
864 dev_err(acpi_desc->dev, "spa%d exceeds max mappings %d\n",
865 spa->range_index, ND_MAX_MAPPINGS);
866 return -ENXIO;
867 }
868 nd_mapping = &nd_mappings[count++];
869 rc = acpi_nfit_init_mapping(acpi_desc, nd_mapping, &ndr_desc,
870 memdev, spa);
871 if (rc)
872 return rc;
873 }
874
875 ndr_desc.nd_mapping = nd_mappings;
876 ndr_desc.num_mappings = count;
877 nvdimm_bus = acpi_desc->nvdimm_bus;
878 if (nfit_spa_type(spa) == NFIT_SPA_PM) {
879 if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
880 return -ENOMEM;
881 } else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) {
882 if (!nvdimm_volatile_region_create(nvdimm_bus, &ndr_desc))
883 return -ENOMEM;
884 }
885 return 0;
886}
887
888static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
889{
890 struct nfit_spa *nfit_spa;
891
892 list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
893 int rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
894
895 if (rc)
896 return rc;
897 }
898 return 0;
899}
900
760static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) 901static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
761{ 902{
762 struct device *dev = acpi_desc->dev; 903 struct device *dev = acpi_desc->dev;
763 const void *end; 904 const void *end;
764 u8 *data; 905 u8 *data;
906 int rc;
765 907
766 INIT_LIST_HEAD(&acpi_desc->spas); 908 INIT_LIST_HEAD(&acpi_desc->spas);
767 INIT_LIST_HEAD(&acpi_desc->dcrs); 909 INIT_LIST_HEAD(&acpi_desc->dcrs);
@@ -786,7 +928,11 @@ static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
786 928
787 acpi_nfit_init_dsms(acpi_desc); 929 acpi_nfit_init_dsms(acpi_desc);
788 930
789 return acpi_nfit_register_dimms(acpi_desc); 931 rc = acpi_nfit_register_dimms(acpi_desc);
932 if (rc)
933 return rc;
934
935 return acpi_nfit_register_regions(acpi_desc);
790} 936}
791 937
792static int acpi_nfit_add(struct acpi_device *adev) 938static int acpi_nfit_add(struct acpi_device *adev)
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
index d44b5c1fcd3b..88afd0d849c3 100644
--- a/drivers/nvdimm/Makefile
+++ b/drivers/nvdimm/Makefile
@@ -4,3 +4,4 @@ libnvdimm-y := core.o
4libnvdimm-y += bus.o 4libnvdimm-y += bus.o
5libnvdimm-y += dimm_devs.o 5libnvdimm-y += dimm_devs.o
6libnvdimm-y += dimm.o 6libnvdimm-y += dimm.o
7libnvdimm-y += region_devs.o
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index f2004b790874..1d760bf24857 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -40,5 +40,8 @@ void nvdimm_bus_exit(void);
40int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); 40int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
41void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); 41void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
42void nd_synchronize(void); 42void nd_synchronize(void);
43int nvdimm_bus_register_dimms(struct nvdimm_bus *nvdimm_bus);
44int nvdimm_bus_register_regions(struct nvdimm_bus *nvdimm_bus);
45int nd_match_dimm(struct device *dev, void *data);
43bool is_nvdimm(struct device *dev); 46bool is_nvdimm(struct device *dev);
44#endif /* __ND_CORE_H__ */ 47#endif /* __ND_CORE_H__ */
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 1f7f6ecab0fc..ea0cca337aa6 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -12,6 +12,7 @@
12 */ 12 */
13#ifndef __ND_H__ 13#ifndef __ND_H__