Linux Audio

Check our new training course

Loading...
v6.13.7
  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
 88static 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
105static char *control_adapter_op_names[] = {
106	"UNKNOWN_OP",		/* 0 undefined */
107	"RESET",		/* 1 */
108	"COLLECT_VPD",		/* 2 */
109};
110
111static char *download_op_names[] = {
112	"UNKNOWN_OP",		/* 0 undefined */
113	"DOWNLOAD",		/* 1 */
114	"VALIDATE",		/* 2 */
115};
116
117static 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
131long 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 */
174long 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 */
205static 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 */
244long 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 */
257long 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 */
270long 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 */
283long 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 */
298long 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 */
318long 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 */
332long 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 */
349long 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 */
361long 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 */
373long 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 */
385long 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 */
397long 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 */
438long 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 */
478static 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 */
515long 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 */
530long 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 */
558static 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 */
623long 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 */
636long 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}
v4.17
 
  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
 92static 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
109static char *control_adapter_op_names[] = {
110	"UNKNOWN_OP",		/* 0 undefined */
111	"RESET",		/* 1 */
112	"COLLECT_VPD",		/* 2 */
113};
114
115static char *download_op_names[] = {
116	"UNKNOWN_OP",		/* 0 undefined */
117	"DOWNLOAD",		/* 1 */
118	"VALIDATE",		/* 2 */
119};
120
121static 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
135long 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 */
178long 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 */
209static 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 */
248long 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 */
261long 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 */
274long 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 */
287long 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 */
302long 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 */
322long 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 */
336long 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 */
353long 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 */
365long 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 */
377long 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 */
389long 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 */
401long 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 */
442long 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 */
482static 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 */
519long 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 */
534long 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 */
562static 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 */
627long 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 */
640long 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}