^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #define pr_fmt(fmt) "of_pmem: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/libnvdimm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct of_pmem_private {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct nvdimm_bus_descriptor bus_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct nvdimm_bus *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) static int of_pmem_region_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct of_pmem_private *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct nvdimm_bus *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) bool is_volatile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) np = dev_of_node(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) priv = kzalloc(sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) priv->bus_desc.provider_name = kstrdup(pdev->name, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) priv->bus_desc.module = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) priv->bus_desc.of_node = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) priv->bus = bus = nvdimm_bus_register(&pdev->dev, &priv->bus_desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!bus) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) kfree(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) platform_set_drvdata(pdev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) is_volatile = !!of_find_property(np, "volatile", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) dev_dbg(&pdev->dev, "Registering %s regions from %pOF\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) is_volatile ? "volatile" : "non-volatile", np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) for (i = 0; i < pdev->num_resources; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct nd_region_desc ndr_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct nd_region *region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * NB: libnvdimm copies the data from ndr_desc into it's own
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * structures so passing a stack pointer is fine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) memset(&ndr_desc, 0, sizeof(ndr_desc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ndr_desc.numa_node = dev_to_node(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ndr_desc.target_node = ndr_desc.numa_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ndr_desc.res = &pdev->resource[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ndr_desc.of_node = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (is_volatile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) region = nvdimm_volatile_region_create(bus, &ndr_desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) region = nvdimm_pmem_region_create(bus, &ndr_desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (!region)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) dev_warn(&pdev->dev, "Unable to register region %pR from %pOF\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) ndr_desc.res, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) dev_dbg(&pdev->dev, "Registered region %pR from %pOF\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ndr_desc.res, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int of_pmem_region_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct of_pmem_private *priv = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) nvdimm_bus_unregister(priv->bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) kfree(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static const struct of_device_id of_pmem_region_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) { .compatible = "pmem-region" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) { .compatible = "pmem-region-v2" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static struct platform_driver of_pmem_region_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .probe = of_pmem_region_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .remove = of_pmem_region_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .name = "of_pmem",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .of_match_table = of_pmem_region_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) module_platform_driver(of_pmem_region_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) MODULE_DEVICE_TABLE(of, of_pmem_region_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) MODULE_AUTHOR("IBM Corporation");