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