PageRenderTime 28ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/powerpc/platforms/pseries/papr_scm.c

https://gitlab.com/kush/linux
C | 370 lines | 275 code | 79 blank | 16 comment | 33 complexity | 694fa8a208647f190687beef47b8749b MD5 | raw file
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define pr_fmt(fmt) "papr-scm: " fmt
  3. #include <linux/of.h>
  4. #include <linux/kernel.h>
  5. #include <linux/module.h>
  6. #include <linux/ioport.h>
  7. #include <linux/slab.h>
  8. #include <linux/ndctl.h>
  9. #include <linux/sched.h>
  10. #include <linux/libnvdimm.h>
  11. #include <linux/platform_device.h>
  12. #include <asm/plpar_wrappers.h>
  13. #define BIND_ANY_ADDR (~0ul)
  14. #define PAPR_SCM_DIMM_CMD_MASK \
  15. ((1ul << ND_CMD_GET_CONFIG_SIZE) | \
  16. (1ul << ND_CMD_GET_CONFIG_DATA) | \
  17. (1ul << ND_CMD_SET_CONFIG_DATA))
  18. struct papr_scm_priv {
  19. struct platform_device *pdev;
  20. struct device_node *dn;
  21. uint32_t drc_index;
  22. uint64_t blocks;
  23. uint64_t block_size;
  24. int metadata_size;
  25. uint64_t bound_addr;
  26. struct nvdimm_bus_descriptor bus_desc;
  27. struct nvdimm_bus *bus;
  28. struct nvdimm *nvdimm;
  29. struct resource res;
  30. struct nd_region *region;
  31. struct nd_interleave_set nd_set;
  32. };
  33. static int drc_pmem_bind(struct papr_scm_priv *p)
  34. {
  35. unsigned long ret[PLPAR_HCALL_BUFSIZE];
  36. uint64_t rc, token;
  37. uint64_t saved = 0;
  38. /*
  39. * When the hypervisor cannot map all the requested memory in a single
  40. * hcall it returns H_BUSY and we call again with the token until
  41. * we get H_SUCCESS. Aborting the retry loop before getting H_SUCCESS
  42. * leave the system in an undefined state, so we wait.
  43. */
  44. token = 0;
  45. do {
  46. rc = plpar_hcall(H_SCM_BIND_MEM, ret, p->drc_index, 0,
  47. p->blocks, BIND_ANY_ADDR, token);
  48. token = ret[0];
  49. if (!saved)
  50. saved = ret[1];
  51. cond_resched();
  52. } while (rc == H_BUSY);
  53. if (rc) {
  54. dev_err(&p->pdev->dev, "bind err: %lld\n", rc);
  55. return -ENXIO;
  56. }
  57. p->bound_addr = saved;
  58. dev_dbg(&p->pdev->dev, "bound drc %x to %pR\n", p->drc_index, &p->res);
  59. return 0;
  60. }
  61. static int drc_pmem_unbind(struct papr_scm_priv *p)
  62. {
  63. unsigned long ret[PLPAR_HCALL_BUFSIZE];
  64. uint64_t rc, token;
  65. token = 0;
  66. /* NB: unbind has the same retry requirements mentioned above */
  67. do {
  68. rc = plpar_hcall(H_SCM_UNBIND_MEM, ret, p->drc_index,
  69. p->bound_addr, p->blocks, token);
  70. token = ret[0];
  71. cond_resched();
  72. } while (rc == H_BUSY);
  73. if (rc)
  74. dev_err(&p->pdev->dev, "unbind error: %lld\n", rc);
  75. return !!rc;
  76. }
  77. static int papr_scm_meta_get(struct papr_scm_priv *p,
  78. struct nd_cmd_get_config_data_hdr *hdr)
  79. {
  80. unsigned long data[PLPAR_HCALL_BUFSIZE];
  81. int64_t ret;
  82. if (hdr->in_offset >= p->metadata_size || hdr->in_length != 1)
  83. return -EINVAL;
  84. ret = plpar_hcall(H_SCM_READ_METADATA, data, p->drc_index,
  85. hdr->in_offset, 1);
  86. if (ret == H_PARAMETER) /* bad DRC index */
  87. return -ENODEV;
  88. if (ret)
  89. return -EINVAL; /* other invalid parameter */
  90. hdr->out_buf[0] = data[0] & 0xff;
  91. return 0;
  92. }
  93. static int papr_scm_meta_set(struct papr_scm_priv *p,
  94. struct nd_cmd_set_config_hdr *hdr)
  95. {
  96. int64_t ret;
  97. if (hdr->in_offset >= p->metadata_size || hdr->in_length != 1)
  98. return -EINVAL;
  99. ret = plpar_hcall_norets(H_SCM_WRITE_METADATA,
  100. p->drc_index, hdr->in_offset, hdr->in_buf[0], 1);
  101. if (ret == H_PARAMETER) /* bad DRC index */
  102. return -ENODEV;
  103. if (ret)
  104. return -EINVAL; /* other invalid parameter */
  105. return 0;
  106. }
  107. int papr_scm_ndctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
  108. unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc)
  109. {
  110. struct nd_cmd_get_config_size *get_size_hdr;
  111. struct papr_scm_priv *p;
  112. /* Only dimm-specific calls are supported atm */
  113. if (!nvdimm)
  114. return -EINVAL;
  115. p = nvdimm_provider_data(nvdimm);
  116. switch (cmd) {
  117. case ND_CMD_GET_CONFIG_SIZE:
  118. get_size_hdr = buf;
  119. get_size_hdr->status = 0;
  120. get_size_hdr->max_xfer = 1;
  121. get_size_hdr->config_size = p->metadata_size;
  122. *cmd_rc = 0;
  123. break;
  124. case ND_CMD_GET_CONFIG_DATA:
  125. *cmd_rc = papr_scm_meta_get(p, buf);
  126. break;
  127. case ND_CMD_SET_CONFIG_DATA:
  128. *cmd_rc = papr_scm_meta_set(p, buf);
  129. break;
  130. default:
  131. return -EINVAL;
  132. }
  133. dev_dbg(&p->pdev->dev, "returned with cmd_rc = %d\n", *cmd_rc);
  134. return 0;
  135. }
  136. static const struct attribute_group *region_attr_groups[] = {
  137. &nd_region_attribute_group,
  138. &nd_device_attribute_group,
  139. &nd_mapping_attribute_group,
  140. &nd_numa_attribute_group,
  141. NULL,
  142. };
  143. static const struct attribute_group *bus_attr_groups[] = {
  144. &nvdimm_bus_attribute_group,
  145. NULL,
  146. };
  147. static const struct attribute_group *papr_scm_dimm_groups[] = {
  148. &nvdimm_attribute_group,
  149. &nd_device_attribute_group,
  150. NULL,
  151. };
  152. static int papr_scm_nvdimm_init(struct papr_scm_priv *p)
  153. {
  154. struct device *dev = &p->pdev->dev;
  155. struct nd_mapping_desc mapping;
  156. struct nd_region_desc ndr_desc;
  157. unsigned long dimm_flags;
  158. p->bus_desc.ndctl = papr_scm_ndctl;
  159. p->bus_desc.module = THIS_MODULE;
  160. p->bus_desc.of_node = p->pdev->dev.of_node;
  161. p->bus_desc.attr_groups = bus_attr_groups;
  162. p->bus_desc.provider_name = kstrdup(p->pdev->name, GFP_KERNEL);
  163. if (!p->bus_desc.provider_name)
  164. return -ENOMEM;
  165. p->bus = nvdimm_bus_register(NULL, &p->bus_desc);
  166. if (!p->bus) {
  167. dev_err(dev, "Error creating nvdimm bus %pOF\n", p->dn);
  168. return -ENXIO;
  169. }
  170. dimm_flags = 0;
  171. set_bit(NDD_ALIASING, &dimm_flags);
  172. p->nvdimm = nvdimm_create(p->bus, p, papr_scm_dimm_groups,
  173. dimm_flags, PAPR_SCM_DIMM_CMD_MASK, 0, NULL);
  174. if (!p->nvdimm) {
  175. dev_err(dev, "Error creating DIMM object for %pOF\n", p->dn);
  176. goto err;
  177. }
  178. if (nvdimm_bus_check_dimm_count(p->bus, 1))
  179. goto err;
  180. /* now add the region */
  181. memset(&mapping, 0, sizeof(mapping));
  182. mapping.nvdimm = p->nvdimm;
  183. mapping.start = 0;
  184. mapping.size = p->blocks * p->block_size; // XXX: potential overflow?
  185. memset(&ndr_desc, 0, sizeof(ndr_desc));
  186. ndr_desc.attr_groups = region_attr_groups;
  187. ndr_desc.numa_node = dev_to_node(&p->pdev->dev);
  188. ndr_desc.target_node = ndr_desc.numa_node;
  189. ndr_desc.res = &p->res;
  190. ndr_desc.of_node = p->dn;
  191. ndr_desc.provider_data = p;
  192. ndr_desc.mapping = &mapping;
  193. ndr_desc.num_mappings = 1;
  194. ndr_desc.nd_set = &p->nd_set;
  195. set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
  196. p->region = nvdimm_pmem_region_create(p->bus, &ndr_desc);
  197. if (!p->region) {
  198. dev_err(dev, "Error registering region %pR from %pOF\n",
  199. ndr_desc.res, p->dn);
  200. goto err;
  201. }
  202. return 0;
  203. err: nvdimm_bus_unregister(p->bus);
  204. kfree(p->bus_desc.provider_name);
  205. return -ENXIO;
  206. }
  207. static int papr_scm_probe(struct platform_device *pdev)
  208. {
  209. struct device_node *dn = pdev->dev.of_node;
  210. u32 drc_index, metadata_size;
  211. u64 blocks, block_size;
  212. struct papr_scm_priv *p;
  213. const char *uuid_str;
  214. u64 uuid[2];
  215. int rc;
  216. /* check we have all the required DT properties */
  217. if (of_property_read_u32(dn, "ibm,my-drc-index", &drc_index)) {
  218. dev_err(&pdev->dev, "%pOF: missing drc-index!\n", dn);
  219. return -ENODEV;
  220. }
  221. if (of_property_read_u64(dn, "ibm,block-size", &block_size)) {
  222. dev_err(&pdev->dev, "%pOF: missing block-size!\n", dn);
  223. return -ENODEV;
  224. }
  225. if (of_property_read_u64(dn, "ibm,number-of-blocks", &blocks)) {
  226. dev_err(&pdev->dev, "%pOF: missing number-of-blocks!\n", dn);
  227. return -ENODEV;
  228. }
  229. if (of_property_read_string(dn, "ibm,unit-guid", &uuid_str)) {
  230. dev_err(&pdev->dev, "%pOF: missing unit-guid!\n", dn);
  231. return -ENODEV;
  232. }
  233. p = kzalloc(sizeof(*p), GFP_KERNEL);
  234. if (!p)
  235. return -ENOMEM;
  236. /* optional DT properties */
  237. of_property_read_u32(dn, "ibm,metadata-size", &metadata_size);
  238. p->dn = dn;
  239. p->drc_index = drc_index;
  240. p->block_size = block_size;
  241. p->blocks = blocks;
  242. /* We just need to ensure that set cookies are unique across */
  243. uuid_parse(uuid_str, (uuid_t *) uuid);
  244. p->nd_set.cookie1 = uuid[0];
  245. p->nd_set.cookie2 = uuid[1];
  246. /* might be zero */
  247. p->metadata_size = metadata_size;
  248. p->pdev = pdev;
  249. /* request the hypervisor to bind this region to somewhere in memory */
  250. rc = drc_pmem_bind(p);
  251. if (rc)
  252. goto err;
  253. /* setup the resource for the newly bound range */
  254. p->res.start = p->bound_addr;
  255. p->res.end = p->bound_addr + p->blocks * p->block_size - 1;
  256. p->res.name = pdev->name;
  257. p->res.flags = IORESOURCE_MEM;
  258. rc = papr_scm_nvdimm_init(p);
  259. if (rc)
  260. goto err2;
  261. platform_set_drvdata(pdev, p);
  262. return 0;
  263. err2: drc_pmem_unbind(p);
  264. err: kfree(p);
  265. return rc;
  266. }
  267. static int papr_scm_remove(struct platform_device *pdev)
  268. {
  269. struct papr_scm_priv *p = platform_get_drvdata(pdev);
  270. nvdimm_bus_unregister(p->bus);
  271. drc_pmem_unbind(p);
  272. kfree(p);
  273. return 0;
  274. }
  275. static const struct of_device_id papr_scm_match[] = {
  276. { .compatible = "ibm,pmemory" },
  277. { },
  278. };
  279. static struct platform_driver papr_scm_driver = {
  280. .probe = papr_scm_probe,
  281. .remove = papr_scm_remove,
  282. .driver = {
  283. .name = "papr_scm",
  284. .owner = THIS_MODULE,
  285. .of_match_table = papr_scm_match,
  286. },
  287. };
  288. module_platform_driver(papr_scm_driver);
  289. MODULE_DEVICE_TABLE(of, papr_scm_match);
  290. MODULE_LICENSE("GPL");
  291. MODULE_AUTHOR("IBM Corporation");