brintos

brintos / linux-shallow public Read only

0
0
Text · 22.4 KiB · aba5e20 Raw
644 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 6000015#define CXL_HCALL_TIMEOUT_DOWNLOAD 12000016 17#define H_ATTACH_CA_PROCESS    0x34418#define H_CONTROL_CA_FUNCTION  0x34819#define H_DETACH_CA_PROCESS    0x34C20#define H_COLLECT_CA_INT_INFO  0x35021#define H_CONTROL_CA_FAULTS    0x35422#define H_DOWNLOAD_CA_FUNCTION 0x35C23#define H_DOWNLOAD_CA_FACILITY 0x36424#define H_CONTROL_CA_FACILITY  0x36825 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         140#define H_CONTROL_CA_FAULTS_RESPOND_AFU         241 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 coherent172 *                        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 allows202 *                          the partition to manipulate or query203 *                          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 executed254 * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when255 *              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 executed267 * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when268 *              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 coherent280 *                          platform function.281 * R4 contains the error state282 */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 buffer293 * Parameter1 = byte offset into error buffer to retrieve, valid values294 *              are between 0 and (ibm,error-buffer-size - 1)295 * Parameter2 = 4K aligned real address of error buffer, to be filled in296 * Parameter3 = length of error buffer, valid values are 4K or less297 */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 the309 *                    coherent platform function310 * Parameter1 = # of configuration record to retrieve, valid values are311 *              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 in316 * Parameter4 = length of configuration buffer, valid values are 4K or less317 */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 completion329 * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when330 *              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 0343 *              and (ibm,#config-records - 1).344 * Parameter2 = 4K naturally aligned real buffer containing block345 *              list entries346 * Parameter3 = number of block list entries in the block list, valid347 *              values are between 0 and 256348 */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 interrupt360 */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 data370 *                                based on an interrupt371 * Parameter1 = value to write to the function-wide error interrupt register372 */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) of383 *                       an error log384 */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 coherent395 *                          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 platform430 *                        function after a fault occurs.431 *432 * Parameters433 *    control-mask: value to control the faults434 *                  looks like PSL_TFC_An shifted >> 32435 *    reset-mask: mask to control reset of function faults436 *                Set reset_mask = 1 to reset PSL errors437 */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 call475 *                          allows the partition to manipulate or query476 *                          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 block526 *              list entries527 * Parameter2 = number of block list entries in the block list, valid528 *              values are between 0 and 256529 */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_FACILITY541 *                    hypervisor call provide platform support for542 *                    downloading a base adapter image to the coherent543 *                    platform facility, and for validating the entire544 *                    image after the download.545 * Parameters546 *    op: operation to perform to the coherent platform function547 *      Download: operation = 1, the base image in the coherent platform548 *                               facility is first erased, and then549 *                               programmed using the image supplied550 *                               in the scatter/gather list.551 *      Validate: operation = 2, the base image in the coherent platform552 *                               facility is compared with the image553 *                               supplied in the scatter/gather list.554 *    list_address: 4K naturally aligned real buffer containing555 *                  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 coherent621 *                                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 coherent634 *                                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}644