hcalls.c (22903B)
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}