Skip to content

Commit 1f7df6f

Browse files
committed
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 <[email protected]> Cc: <[email protected]> Cc: Greg KH <[email protected]> Cc: Robert Moore <[email protected]> Cc: Rafael J. Wysocki <[email protected]> Acked-by: Christoph Hellwig <[email protected]> Acked-by: Rafael J. Wysocki <[email protected]> Tested-by: Toshi Kani <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent 4d88a97 commit 1f7df6f

File tree

6 files changed

+484
-1
lines changed

6 files changed

+484
-1
lines changed

drivers/acpi/nfit.c

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,11 +757,153 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
757757
set_bit(i, &nd_desc->dsm_mask);
758758
}
759759

760+
static 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+
}
768+
static DEVICE_ATTR_RO(range_index);
769+
770+
static struct attribute *acpi_nfit_region_attributes[] = {
771+
&dev_attr_range_index.attr,
772+
NULL,
773+
};
774+
775+
static struct attribute_group acpi_nfit_region_attribute_group = {
776+
.name = "nfit",
777+
.attrs = acpi_nfit_region_attributes,
778+
};
779+
780+
static 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+
787+
static 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+
831+
static 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+
888+
static 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+
760901
static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
761902
{
762903
struct device *dev = acpi_desc->dev;
763904
const void *end;
764905
u8 *data;
906+
int rc;
765907

766908
INIT_LIST_HEAD(&acpi_desc->spas);
767909
INIT_LIST_HEAD(&acpi_desc->dcrs);
@@ -786,7 +928,11 @@ static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
786928

787929
acpi_nfit_init_dsms(acpi_desc);
788930

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);
790936
}
791937

792938
static int acpi_nfit_add(struct acpi_device *adev)

drivers/nvdimm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ libnvdimm-y := core.o
44
libnvdimm-y += bus.o
55
libnvdimm-y += dimm_devs.o
66
libnvdimm-y += dimm.o
7+
libnvdimm-y += region_devs.o

drivers/nvdimm/nd-core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,8 @@ void nvdimm_bus_exit(void);
4040
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
4141
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
4242
void nd_synchronize(void);
43+
int nvdimm_bus_register_dimms(struct nvdimm_bus *nvdimm_bus);
44+
int nvdimm_bus_register_regions(struct nvdimm_bus *nvdimm_bus);
45+
int nd_match_dimm(struct device *dev, void *data);
4346
bool is_nvdimm(struct device *dev);
4447
#endif /* __ND_CORE_H__ */

drivers/nvdimm/nd.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
#ifndef __ND_H__
1414
#define __ND_H__
15+
#include <linux/libnvdimm.h>
1516
#include <linux/device.h>
1617
#include <linux/mutex.h>
1718
#include <linux/ndctl.h>
@@ -22,6 +23,16 @@ struct nvdimm_drvdata {
2223
void *data;
2324
};
2425

26+
struct nd_region {
27+
struct device dev;
28+
u16 ndr_mappings;
29+
u64 ndr_size;
30+
u64 ndr_start;
31+
int id;
32+
void *provider_data;
33+
struct nd_mapping mapping[0];
34+
};
35+
2536
enum nd_async_mode {
2637
ND_SYNC,
2738
ND_ASYNC,

0 commit comments

Comments
 (0)