of_pmem.c 2.7 KB

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