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