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