hcalls.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright 2015 IBM Corp.
  4. */
  5. #include <linux/compiler.h>
  6. #include <linux/types.h>
  7. #include <linux/delay.h>
  8. #include <asm/byteorder.h>
  9. #include "hcalls.h"
  10. #include "trace.h"
  11. #define CXL_HCALL_TIMEOUT 60000
  12. #define CXL_HCALL_TIMEOUT_DOWNLOAD 120000
  13. #define H_ATTACH_CA_PROCESS 0x344
  14. #define H_CONTROL_CA_FUNCTION 0x348
  15. #define H_DETACH_CA_PROCESS 0x34C
  16. #define H_COLLECT_CA_INT_INFO 0x350
  17. #define H_CONTROL_CA_FAULTS 0x354
  18. #define H_DOWNLOAD_CA_FUNCTION 0x35C
  19. #define H_DOWNLOAD_CA_FACILITY 0x364
  20. #define H_CONTROL_CA_FACILITY 0x368
  21. #define H_CONTROL_CA_FUNCTION_RESET 1 /* perform a reset */
  22. #define H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS 2 /* suspend a process from being executed */
  23. #define H_CONTROL_CA_FUNCTION_RESUME_PROCESS 3 /* resume a process to be executed */
  24. #define H_CONTROL_CA_FUNCTION_READ_ERR_STATE 4 /* read the error state */
  25. #define H_CONTROL_CA_FUNCTION_GET_AFU_ERR 5 /* collect the AFU error buffer */
  26. #define H_CONTROL_CA_FUNCTION_GET_CONFIG 6 /* collect configuration record */
  27. #define H_CONTROL_CA_FUNCTION_GET_DOWNLOAD_STATE 7 /* query to return download status */
  28. #define H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS 8 /* terminate the process before completion */
  29. #define H_CONTROL_CA_FUNCTION_COLLECT_VPD 9 /* collect VPD */
  30. #define H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT 11 /* read the function-wide error data based on an interrupt */
  31. #define H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT 12 /* acknowledge function-wide error data based on an interrupt */
  32. #define H_CONTROL_CA_FUNCTION_GET_ERROR_LOG 13 /* retrieve the Platform Log ID (PLID) of an error log */
  33. #define H_CONTROL_CA_FAULTS_RESPOND_PSL 1
  34. #define H_CONTROL_CA_FAULTS_RESPOND_AFU 2
  35. #define H_CONTROL_CA_FACILITY_RESET 1 /* perform a reset */
  36. #define H_CONTROL_CA_FACILITY_COLLECT_VPD 2 /* collect VPD */
  37. #define H_DOWNLOAD_CA_FACILITY_DOWNLOAD 1 /* download adapter image */
  38. #define H_DOWNLOAD_CA_FACILITY_VALIDATE 2 /* validate adapter image */
  39. #define _CXL_LOOP_HCALL(call, rc, retbuf, fn, ...) \
  40. { \
  41. unsigned int delay, total_delay = 0; \
  42. u64 token = 0; \
  43. \
  44. memset(retbuf, 0, sizeof(retbuf)); \
  45. while (1) { \
  46. rc = call(fn, retbuf, __VA_ARGS__, token); \
  47. token = retbuf[0]; \
  48. if (rc != H_BUSY && !H_IS_LONG_BUSY(rc)) \
  49. break; \
  50. \
  51. if (rc == H_BUSY) \
  52. delay = 10; \
  53. else \
  54. delay = get_longbusy_msecs(rc); \
  55. \
  56. total_delay += delay; \
  57. if (total_delay > CXL_HCALL_TIMEOUT) { \
  58. WARN(1, "Warning: Giving up waiting for CXL hcall " \
  59. "%#x after %u msec\n", fn, total_delay); \
  60. rc = H_BUSY; \
  61. break; \
  62. } \
  63. msleep(delay); \
  64. } \
  65. }
  66. #define CXL_H_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall, __VA_ARGS__)
  67. #define CXL_H9_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall9, __VA_ARGS__)
  68. #define _PRINT_MSG(rc, format, ...) \
  69. { \
  70. if ((rc != H_SUCCESS) && (rc != H_CONTINUE)) \
  71. pr_err(format, __VA_ARGS__); \
  72. else \
  73. pr_devel(format, __VA_ARGS__); \
  74. } \
  75. static char *afu_op_names[] = {
  76. "UNKNOWN_OP", /* 0 undefined */
  77. "RESET", /* 1 */
  78. "SUSPEND_PROCESS", /* 2 */
  79. "RESUME_PROCESS", /* 3 */
  80. "READ_ERR_STATE", /* 4 */
  81. "GET_AFU_ERR", /* 5 */
  82. "GET_CONFIG", /* 6 */
  83. "GET_DOWNLOAD_STATE", /* 7 */
  84. "TERMINATE_PROCESS", /* 8 */
  85. "COLLECT_VPD", /* 9 */
  86. "UNKNOWN_OP", /* 10 undefined */
  87. "GET_FUNCTION_ERR_INT", /* 11 */
  88. "ACK_FUNCTION_ERR_INT", /* 12 */
  89. "GET_ERROR_LOG", /* 13 */
  90. };
  91. static char *control_adapter_op_names[] = {
  92. "UNKNOWN_OP", /* 0 undefined */
  93. "RESET", /* 1 */
  94. "COLLECT_VPD", /* 2 */
  95. };
  96. static char *download_op_names[] = {
  97. "UNKNOWN_OP", /* 0 undefined */
  98. "DOWNLOAD", /* 1 */
  99. "VALIDATE", /* 2 */
  100. };
  101. static char *op_str(unsigned int op, char *name_array[], int array_len)
  102. {
  103. if (op >= array_len)
  104. return "UNKNOWN_OP";
  105. return name_array[op];
  106. }
  107. #define OP_STR(op, name_array) op_str(op, name_array, ARRAY_SIZE(name_array))
  108. #define OP_STR_AFU(op) OP_STR(op, afu_op_names)
  109. #define OP_STR_CONTROL_ADAPTER(op) OP_STR(op, control_adapter_op_names)
  110. #define OP_STR_DOWNLOAD_ADAPTER(op) OP_STR(op, download_op_names)
  111. long cxl_h_attach_process(u64 unit_address,
  112. struct cxl_process_element_hcall *element,
  113. u64 *process_token, u64 *mmio_addr, u64 *mmio_size)
  114. {
  115. unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
  116. long rc;
  117. CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_ATTACH_CA_PROCESS, unit_address, virt_to_phys(element));
  118. _PRINT_MSG(rc, "cxl_h_attach_process(%#.16llx, %#.16lx): %li\n",
  119. unit_address, virt_to_phys(element), rc);
  120. trace_cxl_hcall_attach(unit_address, virt_to_phys(element), retbuf[0], retbuf[1], retbuf[2], rc);
  121. pr_devel("token: 0x%.8lx mmio_addr: 0x%lx mmio_size: 0x%lx\nProcess Element Structure:\n",
  122. retbuf[0], retbuf[1], retbuf[2]);
  123. cxl_dump_debug_buffer(element, sizeof(*element));
  124. switch (rc) {
  125. case H_SUCCESS: /* The process info is attached to the coherent platform function */
  126. *process_token = retbuf[0];
  127. if (mmio_addr)
  128. *mmio_addr = retbuf[1];
  129. if (mmio_size)
  130. *mmio_size = retbuf[2];
  131. return 0;
  132. case H_PARAMETER: /* An incorrect parameter was supplied. */
  133. case H_FUNCTION: /* The function is not supported. */
  134. return -EINVAL;
  135. case H_AUTHORITY: /* The partition does not have authority to perform this hcall */
  136. case H_RESOURCE: /* The coherent platform function does not have enough additional resource to attach the process */
  137. case H_HARDWARE: /* A hardware event prevented the attach operation */
  138. case H_STATE: /* The coherent platform function is not in a valid state */
  139. case H_BUSY:
  140. return -EBUSY;
  141. default:
  142. WARN(1, "Unexpected return code: %lx", rc);
  143. return -EINVAL;
  144. }
  145. }
  146. /*
  147. * cxl_h_detach_process - Detach a process element from a coherent
  148. * platform function.
  149. */
  150. long cxl_h_detach_process(u64 unit_address, u64 process_token)
  151. {
  152. unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
  153. long rc;
  154. CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_DETACH_CA_PROCESS, unit_address, process_token);
  155. _PRINT_MSG(rc, "cxl_h_detach_process(%#.16llx, 0x%.8llx): %li\n", unit_address, process_token, rc);
  156. trace_cxl_hcall_detach(unit_address, process_token, rc);
  157. switch (rc) {
  158. case H_SUCCESS: /* The process was detached from the coherent platform function */
  159. return 0;
  160. case H_PARAMETER: /* An incorrect parameter was supplied. */
  161. return -EINVAL;
  162. case H_AUTHORITY: /* The partition does not have authority to perform this hcall */
  163. case H_RESOURCE: /* The function has page table mappings for MMIO */
  164. case H_HARDWARE: /* A hardware event prevented the detach operation */
  165. case H_STATE: /* The coherent platform function is not in a valid state */
  166. case H_BUSY:
  167. return -EBUSY;
  168. default:
  169. WARN(1, "Unexpected return code: %lx", rc);
  170. return -EINVAL;
  171. }
  172. }
  173. /*
  174. * cxl_h_control_function - This H_CONTROL_CA_FUNCTION hypervisor call allows
  175. * the partition to manipulate or query
  176. * certain coherent platform function behaviors.
  177. */
  178. static long cxl_h_control_function(u64 unit_address, u64 op,
  179. u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
  180. {
  181. unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
  182. long rc;
  183. CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FUNCTION, unit_address, op, p1, p2, p3, p4);
  184. _PRINT_MSG(rc, "cxl_h_control_function(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
  185. unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
  186. trace_cxl_hcall_control_function(unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
  187. switch (rc) {
  188. case H_SUCCESS: /* The operation is completed for the coherent platform function */
  189. if ((op == H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT ||
  190. op == H_CONTROL_CA_FUNCTION_READ_ERR_STATE ||
  191. op == H_CONTROL_CA_FUNCTION_COLLECT_VPD))
  192. *out = retbuf[0];
  193. return 0;
  194. case H_PARAMETER: /* An incorrect parameter was supplied. */
  195. case H_FUNCTION: /* The function is not supported. */
  196. case H_NOT_FOUND: /* The operation supplied was not valid */
  197. case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */
  198. case H_SG_LIST: /* An block list entry was invalid */
  199. return -EINVAL;
  200. case H_AUTHORITY: /* The partition does not have authority to perform this hcall */
  201. case H_RESOURCE: /* The function has page table mappings for MMIO */
  202. case H_HARDWARE: /* A hardware event prevented the attach operation */
  203. case H_STATE: /* The coherent platform function is not in a valid state */
  204. case H_BUSY:
  205. return -EBUSY;
  206. default:
  207. WARN(1, "Unexpected return code: %lx", rc);
  208. return -EINVAL;
  209. }
  210. }
  211. /*
  212. * cxl_h_reset_afu - Perform a reset to the coherent platform function.
  213. */
  214. long cxl_h_reset_afu(u64 unit_address)
  215. {
  216. return cxl_h_control_function(unit_address,
  217. H_CONTROL_CA_FUNCTION_RESET,
  218. 0, 0, 0, 0,
  219. NULL);
  220. }
  221. /*
  222. * cxl_h_suspend_process - Suspend a process from being executed
  223. * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
  224. * process was attached.
  225. */
  226. long cxl_h_suspend_process(u64 unit_address, u64 process_token)
  227. {
  228. return cxl_h_control_function(unit_address,
  229. H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS,
  230. process_token, 0, 0, 0,
  231. NULL);
  232. }
  233. /*
  234. * cxl_h_resume_process - Resume a process to be executed
  235. * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
  236. * process was attached.
  237. */
  238. long cxl_h_resume_process(u64 unit_address, u64 process_token)
  239. {
  240. return cxl_h_control_function(unit_address,
  241. H_CONTROL_CA_FUNCTION_RESUME_PROCESS,
  242. process_token, 0, 0, 0,
  243. NULL);
  244. }
  245. /*
  246. * cxl_h_read_error_state - Checks the error state of the coherent
  247. * platform function.
  248. * R4 contains the error state
  249. */
  250. long cxl_h_read_error_state(u64 unit_address, u64 *state)
  251. {
  252. return cxl_h_control_function(unit_address,
  253. H_CONTROL_CA_FUNCTION_READ_ERR_STATE,
  254. 0, 0, 0, 0,
  255. state);
  256. }
  257. /*
  258. * cxl_h_get_afu_err - collect the AFU error buffer
  259. * Parameter1 = byte offset into error buffer to retrieve, valid values
  260. * are between 0 and (ibm,error-buffer-size - 1)
  261. * Parameter2 = 4K aligned real address of error buffer, to be filled in
  262. * Parameter3 = length of error buffer, valid values are 4K or less
  263. */
  264. long cxl_h_get_afu_err(u64 unit_address, u64 offset,
  265. u64 buf_address, u64 len)
  266. {
  267. return cxl_h_control_function(unit_address,
  268. H_CONTROL_CA_FUNCTION_GET_AFU_ERR,
  269. offset, buf_address, len, 0,
  270. NULL);
  271. }
  272. /*
  273. * cxl_h_get_config - collect configuration record for the
  274. * coherent platform function
  275. * Parameter1 = # of configuration record to retrieve, valid values are
  276. * between 0 and (ibm,#config-records - 1)
  277. * Parameter2 = byte offset into configuration record to retrieve,
  278. * valid values are between 0 and (ibm,config-record-size - 1)
  279. * Parameter3 = 4K aligned real address of configuration record buffer,
  280. * to be filled in
  281. * Parameter4 = length of configuration buffer, valid values are 4K or less
  282. */
  283. long cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset,
  284. u64 buf_address, u64 len)
  285. {
  286. return cxl_h_control_function(unit_address,
  287. H_CONTROL_CA_FUNCTION_GET_CONFIG,
  288. cr_num, offset, buf_address, len,
  289. NULL);
  290. }
  291. /*
  292. * cxl_h_terminate_process - Terminate the process before completion
  293. * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
  294. * process was attached.
  295. */
  296. long cxl_h_terminate_process(u64 unit_address, u64 process_token)
  297. {
  298. return cxl_h_control_function(unit_address,
  299. H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS,
  300. process_token, 0, 0, 0,
  301. NULL);
  302. }
  303. /*
  304. * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
  305. * Parameter1 = # of VPD record to retrieve, valid values are between 0
  306. * and (ibm,#config-records - 1).
  307. * Parameter2 = 4K naturally aligned real buffer containing block
  308. * list entries
  309. * Parameter3 = number of block list entries in the block list, valid
  310. * values are between 0 and 256
  311. */
  312. long cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address,
  313. u64 num, u64 *out)
  314. {
  315. return cxl_h_control_function(unit_address,
  316. H_CONTROL_CA_FUNCTION_COLLECT_VPD,
  317. record, list_address, num, 0,
  318. out);
  319. }
  320. /*
  321. * cxl_h_get_fn_error_interrupt - Read the function-wide error data based on an interrupt
  322. */
  323. long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
  324. {
  325. return cxl_h_control_function(unit_address,
  326. H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT,
  327. 0, 0, 0, 0, reg);
  328. }
  329. /*
  330. * cxl_h_ack_fn_error_interrupt - Acknowledge function-wide error data
  331. * based on an interrupt
  332. * Parameter1 = value to write to the function-wide error interrupt register
  333. */
  334. long cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value)
  335. {
  336. return cxl_h_control_function(unit_address,
  337. H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT,
  338. value, 0, 0, 0,
  339. NULL);
  340. }
  341. /*
  342. * cxl_h_get_error_log - Retrieve the Platform Log ID (PLID) of
  343. * an error log
  344. */
  345. long cxl_h_get_error_log(u64 unit_address, u64 value)
  346. {
  347. return cxl_h_control_function(unit_address,
  348. H_CONTROL_CA_FUNCTION_GET_ERROR_LOG,
  349. 0, 0, 0, 0,
  350. NULL);
  351. }
  352. /*
  353. * cxl_h_collect_int_info - Collect interrupt info about a coherent
  354. * platform function after an interrupt occurred.
  355. */
  356. long cxl_h_collect_int_info(u64 unit_address, u64 process_token,
  357. struct cxl_irq_info *info)
  358. {
  359. long rc;
  360. BUG_ON(sizeof(*info) != sizeof(unsigned long[PLPAR_HCALL9_BUFSIZE]));
  361. rc = plpar_hcall9(H_COLLECT_CA_INT_INFO, (unsigned long *) info,
  362. unit_address, process_token);
  363. _PRINT_MSG(rc, "cxl_h_collect_int_info(%#.16llx, 0x%llx): %li\n",
  364. unit_address, process_token, rc);
  365. trace_cxl_hcall_collect_int_info(unit_address, process_token, rc);
  366. switch (rc) {
  367. case H_SUCCESS: /* The interrupt info is returned in return registers. */
  368. pr_devel("dsisr:%#llx, dar:%#llx, dsr:%#llx, pid_tid:%#llx, afu_err:%#llx, errstat:%#llx\n",
  369. info->dsisr, info->dar, info->dsr, info->reserved,
  370. info->afu_err, info->errstat);
  371. return 0;
  372. case H_PARAMETER: /* An incorrect parameter was supplied. */
  373. return -EINVAL;
  374. case H_AUTHORITY: /* The partition does not have authority to perform this hcall. */
  375. case H_HARDWARE: /* A hardware event prevented the collection of the interrupt info.*/
  376. case H_STATE: /* The coherent platform function is not in a valid state to collect interrupt info. */
  377. return -EBUSY;
  378. default:
  379. WARN(1, "Unexpected return code: %lx", rc);
  380. return -EINVAL;
  381. }
  382. }
  383. /*
  384. * cxl_h_control_faults - Control the operation of a coherent platform
  385. * function after a fault occurs.
  386. *
  387. * Parameters
  388. * control-mask: value to control the faults
  389. * looks like PSL_TFC_An shifted >> 32
  390. * reset-mask: mask to control reset of function faults
  391. * Set reset_mask = 1 to reset PSL errors
  392. */
  393. long cxl_h_control_faults(u64 unit_address, u64 process_token,
  394. u64 control_mask, u64 reset_mask)
  395. {
  396. unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
  397. long rc;
  398. memset(retbuf, 0, sizeof(retbuf));
  399. rc = plpar_hcall(H_CONTROL_CA_FAULTS, retbuf, unit_address,
  400. H_CONTROL_CA_FAULTS_RESPOND_PSL, process_token,
  401. control_mask, reset_mask);
  402. _PRINT_MSG(rc, "cxl_h_control_faults(%#.16llx, 0x%llx, %#llx, %#llx): %li (%#lx)\n",
  403. unit_address, process_token, control_mask, reset_mask,
  404. rc, retbuf[0]);
  405. trace_cxl_hcall_control_faults(unit_address, process_token,
  406. control_mask, reset_mask, retbuf[0], rc);
  407. switch (rc) {
  408. case H_SUCCESS: /* Faults were successfully controlled for the function. */
  409. return 0;
  410. case H_PARAMETER: /* An incorrect parameter was supplied. */
  411. return -EINVAL;
  412. case H_HARDWARE: /* A hardware event prevented the control of faults. */
  413. case H_STATE: /* The function was in an invalid state. */
  414. case H_AUTHORITY: /* The partition does not have authority to perform this hcall; the coherent platform facilities may need to be licensed. */
  415. return -EBUSY;
  416. case H_FUNCTION: /* The function is not supported */
  417. case H_NOT_FOUND: /* The operation supplied was not valid */
  418. return -EINVAL;
  419. default:
  420. WARN(1, "Unexpected return code: %lx", rc);
  421. return -EINVAL;
  422. }
  423. }
  424. /*
  425. * cxl_h_control_facility - This H_CONTROL_CA_FACILITY hypervisor call
  426. * allows the partition to manipulate or query
  427. * certain coherent platform facility behaviors.
  428. */
  429. static long cxl_h_control_facility(u64 unit_address, u64 op,
  430. u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
  431. {
  432. unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
  433. long rc;
  434. CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FACILITY, unit_address, op, p1, p2, p3, p4);
  435. _PRINT_MSG(rc, "cxl_h_control_facility(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
  436. unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
  437. trace_cxl_hcall_control_facility(unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
  438. switch (rc) {
  439. case H_SUCCESS: /* The operation is completed for the coherent platform facility */
  440. if (op == H_CONTROL_CA_FACILITY_COLLECT_VPD)
  441. *out = retbuf[0];
  442. return 0;
  443. case H_PARAMETER: /* An incorrect parameter was supplied. */
  444. case H_FUNCTION: /* The function is not supported. */
  445. case H_NOT_FOUND: /* The operation supplied was not valid */
  446. case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */
  447. case H_SG_LIST: /* An block list entry was invalid */
  448. return -EINVAL;
  449. case H_AUTHORITY: /* The partition does not have authority to perform this hcall */
  450. case H_RESOURCE: /* The function has page table mappings for MMIO */
  451. case H_HARDWARE: /* A hardware event prevented the attach operation */
  452. case H_STATE: /* The coherent platform facility is not in a valid state */
  453. case H_BUSY:
  454. return -EBUSY;
  455. default:
  456. WARN(1, "Unexpected return code: %lx", rc);
  457. return -EINVAL;
  458. }
  459. }
  460. /*
  461. * cxl_h_reset_adapter - Perform a reset to the coherent platform facility.
  462. */
  463. long cxl_h_reset_adapter(u64 unit_address)
  464. {
  465. return cxl_h_control_facility(unit_address,
  466. H_CONTROL_CA_FACILITY_RESET,
  467. 0, 0, 0, 0,
  468. NULL);
  469. }
  470. /*
  471. * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
  472. * Parameter1 = 4K naturally aligned real buffer containing block
  473. * list entries
  474. * Parameter2 = number of block list entries in the block list, valid
  475. * values are between 0 and 256
  476. */
  477. long cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address,
  478. u64 num, u64 *out)
  479. {
  480. return cxl_h_control_facility(unit_address,
  481. H_CONTROL_CA_FACILITY_COLLECT_VPD,
  482. list_address, num, 0, 0,
  483. out);
  484. }
  485. /*
  486. * cxl_h_download_facility - This H_DOWNLOAD_CA_FACILITY
  487. * hypervisor call provide platform support for
  488. * downloading a base adapter image to the coherent
  489. * platform facility, and for validating the entire
  490. * image after the download.
  491. * Parameters
  492. * op: operation to perform to the coherent platform function
  493. * Download: operation = 1, the base image in the coherent platform
  494. * facility is first erased, and then
  495. * programmed using the image supplied
  496. * in the scatter/gather list.
  497. * Validate: operation = 2, the base image in the coherent platform
  498. * facility is compared with the image
  499. * supplied in the scatter/gather list.
  500. * list_address: 4K naturally aligned real buffer containing
  501. * scatter/gather list entries.
  502. * num: number of block list entries in the scatter/gather list.
  503. */
  504. static long cxl_h_download_facility(u64 unit_address, u64 op,
  505. u64 list_address, u64 num,
  506. u64 *out)
  507. {
  508. unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
  509. unsigned int delay, total_delay = 0;
  510. u64 token = 0;
  511. long rc;
  512. if (*out != 0)
  513. token = *out;
  514. memset(retbuf, 0, sizeof(retbuf));
  515. while (1) {
  516. rc = plpar_hcall(H_DOWNLOAD_CA_FACILITY, retbuf,
  517. unit_address, op, list_address, num,
  518. token);
  519. token = retbuf[0];
  520. if (rc != H_BUSY && !H_IS_LONG_BUSY(rc))
  521. break;
  522. if (rc != H_BUSY) {
  523. delay = get_longbusy_msecs(rc);
  524. total_delay += delay;
  525. if (total_delay > CXL_HCALL_TIMEOUT_DOWNLOAD) {
  526. WARN(1, "Warning: Giving up waiting for CXL hcall "
  527. "%#x after %u msec\n",
  528. H_DOWNLOAD_CA_FACILITY, total_delay);
  529. rc = H_BUSY;
  530. break;
  531. }
  532. msleep(delay);
  533. }
  534. }
  535. _PRINT_MSG(rc, "cxl_h_download_facility(%#.16llx, %s(%#llx, %#llx), %#lx): %li\n",
  536. unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
  537. trace_cxl_hcall_download_facility(unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
  538. switch (rc) {
  539. case H_SUCCESS: /* The operation is completed for the coherent platform facility */
  540. return 0;
  541. case H_PARAMETER: /* An incorrect parameter was supplied */
  542. case H_FUNCTION: /* The function is not supported. */
  543. case H_SG_LIST: /* An block list entry was invalid */
  544. case H_BAD_DATA: /* Image verification failed */
  545. return -EINVAL;
  546. case H_AUTHORITY: /* The partition does not have authority to perform this hcall */
  547. case H_RESOURCE: /* The function has page table mappings for MMIO */
  548. case H_HARDWARE: /* A hardware event prevented the attach operation */
  549. case H_STATE: /* The coherent platform facility is not in a valid state */
  550. case H_BUSY:
  551. return -EBUSY;
  552. case H_CONTINUE:
  553. *out = retbuf[0];
  554. return 1; /* More data is needed for the complete image */
  555. default:
  556. WARN(1, "Unexpected return code: %lx", rc);
  557. return -EINVAL;
  558. }
  559. }
  560. /*
  561. * cxl_h_download_adapter_image - Download the base image to the coherent
  562. * platform facility.
  563. */
  564. long cxl_h_download_adapter_image(u64 unit_address,
  565. u64 list_address, u64 num,
  566. u64 *out)
  567. {
  568. return cxl_h_download_facility(unit_address,
  569. H_DOWNLOAD_CA_FACILITY_DOWNLOAD,
  570. list_address, num, out);
  571. }
  572. /*
  573. * cxl_h_validate_adapter_image - Validate the base image in the coherent
  574. * platform facility.
  575. */
  576. long cxl_h_validate_adapter_image(u64 unit_address,
  577. u64 list_address, u64 num,
  578. u64 *out)
  579. {
  580. return cxl_h_download_facility(unit_address,
  581. H_DOWNLOAD_CA_FACILITY_VALIDATE,
  582. list_address, num, out);
  583. }