hcalls.c 23 KB

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