mcdi_functions.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
  4. */
  5. #include <linux/module.h>
  6. #include "mcdi.h"
  7. #include "mcdi_functions.h"
  8. int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx)
  9. {
  10. MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN);
  11. size_t outlen;
  12. int ret;
  13. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_BUSES, NULL, 0,
  14. outbuf, sizeof(outbuf), &outlen);
  15. if (ret)
  16. return ret;
  17. if (outlen != MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN)
  18. return -EIO;
  19. return MCDI_DWORD(outbuf, CDX_BUS_ENUM_BUSES_OUT_BUS_COUNT);
  20. }
  21. int cdx_mcdi_get_num_devs(struct cdx_mcdi *cdx, int bus_num)
  22. {
  23. MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN);
  24. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_IN_LEN);
  25. size_t outlen;
  26. int ret;
  27. MCDI_SET_DWORD(inbuf, CDX_BUS_ENUM_DEVICES_IN_BUS, bus_num);
  28. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_DEVICES, inbuf, sizeof(inbuf),
  29. outbuf, sizeof(outbuf), &outlen);
  30. if (ret)
  31. return ret;
  32. if (outlen != MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN)
  33. return -EIO;
  34. return MCDI_DWORD(outbuf, CDX_BUS_ENUM_DEVICES_OUT_DEVICE_COUNT);
  35. }
  36. int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
  37. u8 bus_num, u8 dev_num,
  38. struct cdx_dev_params *dev_params)
  39. {
  40. MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN);
  41. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN);
  42. struct resource *res = &dev_params->res[0];
  43. size_t outlen;
  44. u32 req_id;
  45. int ret;
  46. MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_BUS, bus_num);
  47. MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_DEVICE, dev_num);
  48. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG, inbuf, sizeof(inbuf),
  49. outbuf, sizeof(outbuf), &outlen);
  50. if (ret)
  51. return ret;
  52. if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN)
  53. return -EIO;
  54. dev_params->bus_num = bus_num;
  55. dev_params->dev_num = dev_num;
  56. req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID);
  57. dev_params->req_id = req_id;
  58. dev_params->msi_dev_id = MCDI_DWORD(outbuf,
  59. CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID);
  60. dev_params->res_count = 0;
  61. if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) {
  62. res[dev_params->res_count].start =
  63. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE);
  64. res[dev_params->res_count].end =
  65. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE) +
  66. MCDI_QWORD(outbuf,
  67. CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) - 1;
  68. res[dev_params->res_count].flags = IORESOURCE_MEM;
  69. dev_params->res_count++;
  70. }
  71. if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) != 0) {
  72. res[dev_params->res_count].start =
  73. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE);
  74. res[dev_params->res_count].end =
  75. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE) +
  76. MCDI_QWORD(outbuf,
  77. CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) - 1;
  78. res[dev_params->res_count].flags = IORESOURCE_MEM;
  79. dev_params->res_count++;
  80. }
  81. if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) != 0) {
  82. res[dev_params->res_count].start =
  83. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE);
  84. res[dev_params->res_count].end =
  85. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE) +
  86. MCDI_QWORD(outbuf,
  87. CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) - 1;
  88. res[dev_params->res_count].flags = IORESOURCE_MEM;
  89. dev_params->res_count++;
  90. }
  91. if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) != 0) {
  92. res[dev_params->res_count].start =
  93. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE);
  94. res[dev_params->res_count].end =
  95. MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE) +
  96. MCDI_QWORD(outbuf,
  97. CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) - 1;
  98. res[dev_params->res_count].flags = IORESOURCE_MEM;
  99. dev_params->res_count++;
  100. }
  101. dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID);
  102. dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID);
  103. dev_params->subsys_vendor = MCDI_WORD(outbuf,
  104. CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID);
  105. dev_params->subsys_device = MCDI_WORD(outbuf,
  106. CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID);
  107. dev_params->class = MCDI_DWORD(outbuf,
  108. CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF;
  109. dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION);
  110. dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT);
  111. return 0;
  112. }
  113. int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num)
  114. {
  115. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_UP_IN_LEN);
  116. int ret;
  117. MCDI_SET_DWORD(inbuf, CDX_BUS_UP_IN_BUS, bus_num);
  118. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_UP, inbuf, sizeof(inbuf),
  119. NULL, 0, NULL);
  120. return ret;
  121. }
  122. int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num)
  123. {
  124. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_DOWN_IN_LEN);
  125. int ret;
  126. MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num);
  127. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf),
  128. NULL, 0, NULL);
  129. return ret;
  130. }
  131. int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num,
  132. u32 msi_vector, u64 msi_address, u32 msi_data)
  133. {
  134. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN);
  135. int ret;
  136. MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num);
  137. MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num);
  138. MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector);
  139. MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address);
  140. MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data);
  141. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, inbuf, sizeof(inbuf),
  142. NULL, 0, NULL);
  143. return ret;
  144. }
  145. int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num)
  146. {
  147. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN);
  148. int ret;
  149. MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_BUS, bus_num);
  150. MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_DEVICE, dev_num);
  151. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_RESET, inbuf, sizeof(inbuf),
  152. NULL, 0, NULL);
  153. return ret;
  154. }
  155. static int cdx_mcdi_ctrl_flag_get(struct cdx_mcdi *cdx, u8 bus_num,
  156. u8 dev_num, u32 *flags)
  157. {
  158. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_IN_LEN);
  159. MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN);
  160. size_t outlen;
  161. int ret;
  162. MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_BUS, bus_num);
  163. MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_DEVICE, dev_num);
  164. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_GET, inbuf,
  165. sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
  166. if (ret)
  167. return ret;
  168. if (outlen != MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN)
  169. return -EIO;
  170. *flags = MCDI_DWORD(outbuf, CDX_DEVICE_CONTROL_GET_OUT_FLAGS);
  171. return 0;
  172. }
  173. static int cdx_mcdi_ctrl_flag_set(struct cdx_mcdi *cdx, u8 bus_num,
  174. u8 dev_num, bool enable, int bit_pos)
  175. {
  176. MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_SET_IN_LEN);
  177. u32 flags;
  178. int ret;
  179. /*
  180. * Get flags and then set/reset bit at bit_pos according to
  181. * the input params.
  182. */
  183. ret = cdx_mcdi_ctrl_flag_get(cdx, bus_num, dev_num, &flags);
  184. if (ret)
  185. return ret;
  186. flags = flags & (u32)(~(BIT(bit_pos)));
  187. if (enable)
  188. flags |= (1 << bit_pos);
  189. MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_BUS, bus_num);
  190. MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_DEVICE, dev_num);
  191. MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_FLAGS, flags);
  192. ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_SET, inbuf,
  193. sizeof(inbuf), NULL, 0, NULL);
  194. return ret;
  195. }
  196. int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num,
  197. u8 dev_num, bool enable)
  198. {
  199. return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable,
  200. MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN);
  201. }
  202. int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num,
  203. u8 dev_num, bool enable)
  204. {
  205. return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable,
  206. MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN);
  207. }