Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / misc / cxl / hcalls.c
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
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
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }