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