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