cdx_controller.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * CDX host controller driver for AMD versal-net platform.
  4. *
  5. * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
  6. */
  7. #include <linux/mod_devicetable.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/slab.h>
  10. #include <linux/cdx/cdx_bus.h>
  11. #include <linux/irqdomain.h>
  12. #include "cdx_controller.h"
  13. #include "../cdx.h"
  14. #include "mcdi_functions.h"
  15. #include "mcdid.h"
  16. static unsigned int cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd)
  17. {
  18. return MCDI_RPC_TIMEOUT;
  19. }
  20. static void cdx_mcdi_request(struct cdx_mcdi *cdx,
  21. const struct cdx_dword *hdr, size_t hdr_len,
  22. const struct cdx_dword *sdu, size_t sdu_len)
  23. {
  24. if (cdx_rpmsg_send(cdx, hdr, hdr_len, sdu, sdu_len))
  25. dev_err(&cdx->rpdev->dev, "Failed to send rpmsg data\n");
  26. }
  27. static const struct cdx_mcdi_ops mcdi_ops = {
  28. .mcdi_rpc_timeout = cdx_mcdi_rpc_timeout,
  29. .mcdi_request = cdx_mcdi_request,
  30. };
  31. static int cdx_bus_enable(struct cdx_controller *cdx, u8 bus_num)
  32. {
  33. return cdx_mcdi_bus_enable(cdx->priv, bus_num);
  34. }
  35. static int cdx_bus_disable(struct cdx_controller *cdx, u8 bus_num)
  36. {
  37. return cdx_mcdi_bus_disable(cdx->priv, bus_num);
  38. }
  39. void cdx_rpmsg_post_probe(struct cdx_controller *cdx)
  40. {
  41. /* Register CDX controller with CDX bus driver */
  42. if (cdx_register_controller(cdx))
  43. dev_err(cdx->dev, "Failed to register CDX controller\n");
  44. }
  45. void cdx_rpmsg_pre_remove(struct cdx_controller *cdx)
  46. {
  47. cdx_unregister_controller(cdx);
  48. cdx_mcdi_wait_for_quiescence(cdx->priv, MCDI_RPC_TIMEOUT);
  49. }
  50. static int cdx_configure_device(struct cdx_controller *cdx,
  51. u8 bus_num, u8 dev_num,
  52. struct cdx_device_config *dev_config)
  53. {
  54. u16 msi_index;
  55. int ret = 0;
  56. u32 data;
  57. u64 addr;
  58. switch (dev_config->type) {
  59. case CDX_DEV_MSI_CONF:
  60. msi_index = dev_config->msi.msi_index;
  61. data = dev_config->msi.data;
  62. addr = dev_config->msi.addr;
  63. ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data);
  64. break;
  65. case CDX_DEV_RESET_CONF:
  66. ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num);
  67. break;
  68. case CDX_DEV_BUS_MASTER_CONF:
  69. ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num,
  70. dev_config->bus_master_enable);
  71. break;
  72. case CDX_DEV_MSI_ENABLE:
  73. ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable);
  74. break;
  75. default:
  76. ret = -EINVAL;
  77. }
  78. return ret;
  79. }
  80. static int cdx_scan_devices(struct cdx_controller *cdx)
  81. {
  82. struct cdx_mcdi *cdx_mcdi = cdx->priv;
  83. u8 bus_num, dev_num, num_cdx_bus;
  84. int ret;
  85. /* MCDI FW Read: Fetch the number of CDX buses on this controller */
  86. ret = cdx_mcdi_get_num_buses(cdx_mcdi);
  87. if (ret < 0) {
  88. dev_err(cdx->dev,
  89. "Get number of CDX buses failed: %d\n", ret);
  90. return ret;
  91. }
  92. num_cdx_bus = (u8)ret;
  93. for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) {
  94. struct device *bus_dev;
  95. u8 num_cdx_dev;
  96. /* Add the bus on cdx subsystem */
  97. bus_dev = cdx_bus_add(cdx, bus_num);
  98. if (!bus_dev)
  99. continue;
  100. /* MCDI FW Read: Fetch the number of devices present */
  101. ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num);
  102. if (ret < 0) {
  103. dev_err(cdx->dev,
  104. "Get devices on CDX bus %d failed: %d\n", bus_num, ret);
  105. continue;
  106. }
  107. num_cdx_dev = (u8)ret;
  108. for (dev_num = 0; dev_num < num_cdx_dev; dev_num++) {
  109. struct cdx_dev_params dev_params;
  110. /* MCDI FW: Get the device config */
  111. ret = cdx_mcdi_get_dev_config(cdx_mcdi, bus_num,
  112. dev_num, &dev_params);
  113. if (ret) {
  114. dev_err(cdx->dev,
  115. "CDX device config get failed for %d(bus):%d(dev), %d\n",
  116. bus_num, dev_num, ret);
  117. continue;
  118. }
  119. dev_params.cdx = cdx;
  120. dev_params.parent = bus_dev;
  121. /* Add the device to the cdx bus */
  122. ret = cdx_device_add(&dev_params);
  123. if (ret) {
  124. dev_err(cdx->dev, "registering cdx dev: %d failed: %d\n",
  125. dev_num, ret);
  126. continue;
  127. }
  128. dev_dbg(cdx->dev, "CDX dev: %d on cdx bus: %d created\n",
  129. dev_num, bus_num);
  130. }
  131. }
  132. return 0;
  133. }
  134. static struct cdx_ops cdx_ops = {
  135. .bus_enable = cdx_bus_enable,
  136. .bus_disable = cdx_bus_disable,
  137. .scan = cdx_scan_devices,
  138. .dev_configure = cdx_configure_device,
  139. };
  140. static int xlnx_cdx_probe(struct platform_device *pdev)
  141. {
  142. struct cdx_controller *cdx;
  143. struct cdx_mcdi *cdx_mcdi;
  144. int ret;
  145. cdx_mcdi = kzalloc_obj(*cdx_mcdi);
  146. if (!cdx_mcdi)
  147. return -ENOMEM;
  148. /* Store the MCDI ops */
  149. cdx_mcdi->mcdi_ops = &mcdi_ops;
  150. /* MCDI FW: Initialize the FW path */
  151. ret = cdx_mcdi_init(cdx_mcdi);
  152. if (ret) {
  153. dev_err_probe(&pdev->dev, ret, "MCDI Initialization failed\n");
  154. goto mcdi_init_fail;
  155. }
  156. cdx = kzalloc_obj(*cdx);
  157. if (!cdx) {
  158. ret = -ENOMEM;
  159. goto cdx_alloc_fail;
  160. }
  161. platform_set_drvdata(pdev, cdx);
  162. cdx->dev = &pdev->dev;
  163. cdx->priv = cdx_mcdi;
  164. cdx->ops = &cdx_ops;
  165. /* Create MSI domain */
  166. if (IS_ENABLED(CONFIG_GENERIC_MSI_IRQ))
  167. cdx->msi_domain = cdx_msi_domain_init(&pdev->dev);
  168. if (!cdx->msi_domain) {
  169. ret = dev_err_probe(&pdev->dev, -ENODEV, "cdx_msi_domain_init() failed");
  170. goto cdx_msi_fail;
  171. }
  172. ret = cdx_setup_rpmsg(pdev);
  173. if (ret) {
  174. dev_err_probe(&pdev->dev, ret, "Failed to register CDX RPMsg transport\n");
  175. goto cdx_rpmsg_fail;
  176. }
  177. return 0;
  178. cdx_rpmsg_fail:
  179. irq_domain_remove(cdx->msi_domain);
  180. cdx_msi_fail:
  181. kfree(cdx);
  182. cdx_alloc_fail:
  183. cdx_mcdi_finish(cdx_mcdi);
  184. mcdi_init_fail:
  185. kfree(cdx_mcdi);
  186. return ret;
  187. }
  188. static void xlnx_cdx_remove(struct platform_device *pdev)
  189. {
  190. struct cdx_controller *cdx = platform_get_drvdata(pdev);
  191. struct cdx_mcdi *cdx_mcdi = cdx->priv;
  192. cdx_destroy_rpmsg(pdev);
  193. irq_domain_remove(cdx->msi_domain);
  194. kfree(cdx);
  195. cdx_mcdi_finish(cdx_mcdi);
  196. kfree(cdx_mcdi);
  197. }
  198. static const struct of_device_id cdx_match_table[] = {
  199. {.compatible = "xlnx,versal-net-cdx",},
  200. { },
  201. };
  202. MODULE_DEVICE_TABLE(of, cdx_match_table);
  203. static struct platform_driver cdx_pdriver = {
  204. .driver = {
  205. .name = "cdx-controller",
  206. .of_match_table = cdx_match_table,
  207. },
  208. .probe = xlnx_cdx_probe,
  209. .remove = xlnx_cdx_remove,
  210. };
  211. module_platform_driver(cdx_pdriver);
  212. MODULE_AUTHOR("AMD Inc.");
  213. MODULE_DESCRIPTION("CDX controller for AMD devices");
  214. MODULE_LICENSE("GPL");
  215. MODULE_IMPORT_NS("CDX_BUS_CONTROLLER");