static __init int register_e820_pmem(void) { static struct nvdimm_bus_descriptor nd_desc; struct device *dev = &e820_pmem.dev; struct nvdimm_bus *nvdimm_bus; int rc, i; rc = platform_device_register(&e820_pmem); if (rc) return rc; nd_desc.attr_groups = e820_pmem_attribute_groups; nd_desc.provider_name = "e820"; nvdimm_bus = nvdimm_bus_register(dev, &nd_desc); if (!nvdimm_bus) goto err; dev->platform_data = nvdimm_bus; for (i = 0; i < e820.nr_map; i++) { struct e820entry *ei = &e820.map[i]; struct resource res = { .flags = IORESOURCE_MEM, .start = ei->addr, .end = ei->addr + ei->size - 1, }; struct nd_region_desc ndr_desc; if (ei->type != E820_PRAM) continue; memset(&ndr_desc, 0, sizeof(ndr_desc)); ndr_desc.res = &res; ndr_desc.attr_groups = e820_pmem_region_attribute_groups; ndr_desc.numa_node = NUMA_NO_NODE; if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) goto err; } return 0; err: dev_err(dev, "failed to register legacy persistent memory ranges\n"); platform_device_unregister(&e820_pmem); return -ENXIO; } device_initcall(register_e820_pmem);
static int e820_pmem_probe(struct platform_device *pdev) { static struct nvdimm_bus_descriptor nd_desc; struct device *dev = &pdev->dev; struct nvdimm_bus *nvdimm_bus; struct resource *p; nd_desc.attr_groups = e820_pmem_attribute_groups; nd_desc.provider_name = "e820"; nd_desc.module = THIS_MODULE; nvdimm_bus = nvdimm_bus_register(dev, &nd_desc); if (!nvdimm_bus) goto err; platform_set_drvdata(pdev, nvdimm_bus); for (p = iomem_resource.child; p ; p = p->sibling) { struct nd_region_desc ndr_desc; if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY) continue; memset(&ndr_desc, 0, sizeof(ndr_desc)); ndr_desc.res = p; ndr_desc.attr_groups = e820_pmem_region_attribute_groups; ndr_desc.numa_node = e820_range_to_nid(p->start); set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) goto err; } return 0; err: nvdimm_bus_unregister(nvdimm_bus); dev_err(dev, "failed to register legacy persistent memory ranges\n"); return -ENXIO; }
static int papr_scm_nvdimm_init(struct papr_scm_priv *p) { struct device *dev = &p->pdev->dev; struct nd_mapping_desc mapping; struct nd_region_desc ndr_desc; unsigned long dimm_flags; p->bus_desc.ndctl = papr_scm_ndctl; p->bus_desc.module = THIS_MODULE; p->bus_desc.of_node = p->pdev->dev.of_node; p->bus_desc.attr_groups = bus_attr_groups; p->bus_desc.provider_name = kstrdup(p->pdev->name, GFP_KERNEL); if (!p->bus_desc.provider_name) return -ENOMEM; p->bus = nvdimm_bus_register(NULL, &p->bus_desc); if (!p->bus) { dev_err(dev, "Error creating nvdimm bus %pOF\n", p->dn); return -ENXIO; } dimm_flags = 0; set_bit(NDD_ALIASING, &dimm_flags); p->nvdimm = nvdimm_create(p->bus, p, papr_scm_dimm_groups, dimm_flags, PAPR_SCM_DIMM_CMD_MASK, 0, NULL); if (!p->nvdimm) { dev_err(dev, "Error creating DIMM object for %pOF\n", p->dn); goto err; } /* now add the region */ memset(&mapping, 0, sizeof(mapping)); mapping.nvdimm = p->nvdimm; mapping.start = 0; mapping.size = p->blocks * p->block_size; // XXX: potential overflow? memset(&ndr_desc, 0, sizeof(ndr_desc)); ndr_desc.attr_groups = region_attr_groups; ndr_desc.numa_node = dev_to_node(&p->pdev->dev); ndr_desc.res = &p->res; ndr_desc.of_node = p->dn; ndr_desc.provider_data = p; ndr_desc.mapping = &mapping; ndr_desc.num_mappings = 1; ndr_desc.nd_set = &p->nd_set; set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); p->region = nvdimm_pmem_region_create(p->bus, &ndr_desc); if (!p->region) { dev_err(dev, "Error registering region %pR from %pOF\n", ndr_desc.res, p->dn); goto err; } return 0; err: nvdimm_bus_unregister(p->bus); kfree(p->bus_desc.provider_name); return -ENXIO; }