162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2015 IBM Corp. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/compiler.h> 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <asm/byteorder.h> 1162306a36Sopenharmony_ci#include "hcalls.h" 1262306a36Sopenharmony_ci#include "trace.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define CXL_HCALL_TIMEOUT 60000 1562306a36Sopenharmony_ci#define CXL_HCALL_TIMEOUT_DOWNLOAD 120000 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define H_ATTACH_CA_PROCESS 0x344 1862306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION 0x348 1962306a36Sopenharmony_ci#define H_DETACH_CA_PROCESS 0x34C 2062306a36Sopenharmony_ci#define H_COLLECT_CA_INT_INFO 0x350 2162306a36Sopenharmony_ci#define H_CONTROL_CA_FAULTS 0x354 2262306a36Sopenharmony_ci#define H_DOWNLOAD_CA_FUNCTION 0x35C 2362306a36Sopenharmony_ci#define H_DOWNLOAD_CA_FACILITY 0x364 2462306a36Sopenharmony_ci#define H_CONTROL_CA_FACILITY 0x368 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_RESET 1 /* perform a reset */ 2762306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS 2 /* suspend a process from being executed */ 2862306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_RESUME_PROCESS 3 /* resume a process to be executed */ 2962306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_READ_ERR_STATE 4 /* read the error state */ 3062306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_GET_AFU_ERR 5 /* collect the AFU error buffer */ 3162306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_GET_CONFIG 6 /* collect configuration record */ 3262306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_GET_DOWNLOAD_STATE 7 /* query to return download status */ 3362306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS 8 /* terminate the process before completion */ 3462306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_COLLECT_VPD 9 /* collect VPD */ 3562306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT 11 /* read the function-wide error data based on an interrupt */ 3662306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT 12 /* acknowledge function-wide error data based on an interrupt */ 3762306a36Sopenharmony_ci#define H_CONTROL_CA_FUNCTION_GET_ERROR_LOG 13 /* retrieve the Platform Log ID (PLID) of an error log */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define H_CONTROL_CA_FAULTS_RESPOND_PSL 1 4062306a36Sopenharmony_ci#define H_CONTROL_CA_FAULTS_RESPOND_AFU 2 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define H_CONTROL_CA_FACILITY_RESET 1 /* perform a reset */ 4362306a36Sopenharmony_ci#define H_CONTROL_CA_FACILITY_COLLECT_VPD 2 /* collect VPD */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define H_DOWNLOAD_CA_FACILITY_DOWNLOAD 1 /* download adapter image */ 4662306a36Sopenharmony_ci#define H_DOWNLOAD_CA_FACILITY_VALIDATE 2 /* validate adapter image */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define _CXL_LOOP_HCALL(call, rc, retbuf, fn, ...) \ 5062306a36Sopenharmony_ci { \ 5162306a36Sopenharmony_ci unsigned int delay, total_delay = 0; \ 5262306a36Sopenharmony_ci u64 token = 0; \ 5362306a36Sopenharmony_ci \ 5462306a36Sopenharmony_ci memset(retbuf, 0, sizeof(retbuf)); \ 5562306a36Sopenharmony_ci while (1) { \ 5662306a36Sopenharmony_ci rc = call(fn, retbuf, __VA_ARGS__, token); \ 5762306a36Sopenharmony_ci token = retbuf[0]; \ 5862306a36Sopenharmony_ci if (rc != H_BUSY && !H_IS_LONG_BUSY(rc)) \ 5962306a36Sopenharmony_ci break; \ 6062306a36Sopenharmony_ci \ 6162306a36Sopenharmony_ci if (rc == H_BUSY) \ 6262306a36Sopenharmony_ci delay = 10; \ 6362306a36Sopenharmony_ci else \ 6462306a36Sopenharmony_ci delay = get_longbusy_msecs(rc); \ 6562306a36Sopenharmony_ci \ 6662306a36Sopenharmony_ci total_delay += delay; \ 6762306a36Sopenharmony_ci if (total_delay > CXL_HCALL_TIMEOUT) { \ 6862306a36Sopenharmony_ci WARN(1, "Warning: Giving up waiting for CXL hcall " \ 6962306a36Sopenharmony_ci "%#x after %u msec\n", fn, total_delay); \ 7062306a36Sopenharmony_ci rc = H_BUSY; \ 7162306a36Sopenharmony_ci break; \ 7262306a36Sopenharmony_ci } \ 7362306a36Sopenharmony_ci msleep(delay); \ 7462306a36Sopenharmony_ci } \ 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci#define CXL_H_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall, __VA_ARGS__) 7762306a36Sopenharmony_ci#define CXL_H9_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall9, __VA_ARGS__) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define _PRINT_MSG(rc, format, ...) \ 8062306a36Sopenharmony_ci { \ 8162306a36Sopenharmony_ci if ((rc != H_SUCCESS) && (rc != H_CONTINUE)) \ 8262306a36Sopenharmony_ci pr_err(format, __VA_ARGS__); \ 8362306a36Sopenharmony_ci else \ 8462306a36Sopenharmony_ci pr_devel(format, __VA_ARGS__); \ 8562306a36Sopenharmony_ci } \ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic char *afu_op_names[] = { 8962306a36Sopenharmony_ci "UNKNOWN_OP", /* 0 undefined */ 9062306a36Sopenharmony_ci "RESET", /* 1 */ 9162306a36Sopenharmony_ci "SUSPEND_PROCESS", /* 2 */ 9262306a36Sopenharmony_ci "RESUME_PROCESS", /* 3 */ 9362306a36Sopenharmony_ci "READ_ERR_STATE", /* 4 */ 9462306a36Sopenharmony_ci "GET_AFU_ERR", /* 5 */ 9562306a36Sopenharmony_ci "GET_CONFIG", /* 6 */ 9662306a36Sopenharmony_ci "GET_DOWNLOAD_STATE", /* 7 */ 9762306a36Sopenharmony_ci "TERMINATE_PROCESS", /* 8 */ 9862306a36Sopenharmony_ci "COLLECT_VPD", /* 9 */ 9962306a36Sopenharmony_ci "UNKNOWN_OP", /* 10 undefined */ 10062306a36Sopenharmony_ci "GET_FUNCTION_ERR_INT", /* 11 */ 10162306a36Sopenharmony_ci "ACK_FUNCTION_ERR_INT", /* 12 */ 10262306a36Sopenharmony_ci "GET_ERROR_LOG", /* 13 */ 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic char *control_adapter_op_names[] = { 10662306a36Sopenharmony_ci "UNKNOWN_OP", /* 0 undefined */ 10762306a36Sopenharmony_ci "RESET", /* 1 */ 10862306a36Sopenharmony_ci "COLLECT_VPD", /* 2 */ 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic char *download_op_names[] = { 11262306a36Sopenharmony_ci "UNKNOWN_OP", /* 0 undefined */ 11362306a36Sopenharmony_ci "DOWNLOAD", /* 1 */ 11462306a36Sopenharmony_ci "VALIDATE", /* 2 */ 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic char *op_str(unsigned int op, char *name_array[], int array_len) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci if (op >= array_len) 12062306a36Sopenharmony_ci return "UNKNOWN_OP"; 12162306a36Sopenharmony_ci return name_array[op]; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define OP_STR(op, name_array) op_str(op, name_array, ARRAY_SIZE(name_array)) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#define OP_STR_AFU(op) OP_STR(op, afu_op_names) 12762306a36Sopenharmony_ci#define OP_STR_CONTROL_ADAPTER(op) OP_STR(op, control_adapter_op_names) 12862306a36Sopenharmony_ci#define OP_STR_DOWNLOAD_ADAPTER(op) OP_STR(op, download_op_names) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cilong cxl_h_attach_process(u64 unit_address, 13262306a36Sopenharmony_ci struct cxl_process_element_hcall *element, 13362306a36Sopenharmony_ci u64 *process_token, u64 *mmio_addr, u64 *mmio_size) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 13662306a36Sopenharmony_ci long rc; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_ATTACH_CA_PROCESS, unit_address, virt_to_phys(element)); 13962306a36Sopenharmony_ci _PRINT_MSG(rc, "cxl_h_attach_process(%#.16llx, %#.16lx): %li\n", 14062306a36Sopenharmony_ci unit_address, virt_to_phys(element), rc); 14162306a36Sopenharmony_ci trace_cxl_hcall_attach(unit_address, virt_to_phys(element), retbuf[0], retbuf[1], retbuf[2], rc); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci pr_devel("token: 0x%.8lx mmio_addr: 0x%lx mmio_size: 0x%lx\nProcess Element Structure:\n", 14462306a36Sopenharmony_ci retbuf[0], retbuf[1], retbuf[2]); 14562306a36Sopenharmony_ci cxl_dump_debug_buffer(element, sizeof(*element)); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci switch (rc) { 14862306a36Sopenharmony_ci case H_SUCCESS: /* The process info is attached to the coherent platform function */ 14962306a36Sopenharmony_ci *process_token = retbuf[0]; 15062306a36Sopenharmony_ci if (mmio_addr) 15162306a36Sopenharmony_ci *mmio_addr = retbuf[1]; 15262306a36Sopenharmony_ci if (mmio_size) 15362306a36Sopenharmony_ci *mmio_size = retbuf[2]; 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci case H_PARAMETER: /* An incorrect parameter was supplied. */ 15662306a36Sopenharmony_ci case H_FUNCTION: /* The function is not supported. */ 15762306a36Sopenharmony_ci return -EINVAL; 15862306a36Sopenharmony_ci case H_AUTHORITY: /* The partition does not have authority to perform this hcall */ 15962306a36Sopenharmony_ci case H_RESOURCE: /* The coherent platform function does not have enough additional resource to attach the process */ 16062306a36Sopenharmony_ci case H_HARDWARE: /* A hardware event prevented the attach operation */ 16162306a36Sopenharmony_ci case H_STATE: /* The coherent platform function is not in a valid state */ 16262306a36Sopenharmony_ci case H_BUSY: 16362306a36Sopenharmony_ci return -EBUSY; 16462306a36Sopenharmony_ci default: 16562306a36Sopenharmony_ci WARN(1, "Unexpected return code: %lx", rc); 16662306a36Sopenharmony_ci return -EINVAL; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * cxl_h_detach_process - Detach a process element from a coherent 17262306a36Sopenharmony_ci * platform function. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cilong cxl_h_detach_process(u64 unit_address, u64 process_token) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 17762306a36Sopenharmony_ci long rc; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_DETACH_CA_PROCESS, unit_address, process_token); 18062306a36Sopenharmony_ci _PRINT_MSG(rc, "cxl_h_detach_process(%#.16llx, 0x%.8llx): %li\n", unit_address, process_token, rc); 18162306a36Sopenharmony_ci trace_cxl_hcall_detach(unit_address, process_token, rc); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci switch (rc) { 18462306a36Sopenharmony_ci case H_SUCCESS: /* The process was detached from the coherent platform function */ 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci case H_PARAMETER: /* An incorrect parameter was supplied. */ 18762306a36Sopenharmony_ci return -EINVAL; 18862306a36Sopenharmony_ci case H_AUTHORITY: /* The partition does not have authority to perform this hcall */ 18962306a36Sopenharmony_ci case H_RESOURCE: /* The function has page table mappings for MMIO */ 19062306a36Sopenharmony_ci case H_HARDWARE: /* A hardware event prevented the detach operation */ 19162306a36Sopenharmony_ci case H_STATE: /* The coherent platform function is not in a valid state */ 19262306a36Sopenharmony_ci case H_BUSY: 19362306a36Sopenharmony_ci return -EBUSY; 19462306a36Sopenharmony_ci default: 19562306a36Sopenharmony_ci WARN(1, "Unexpected return code: %lx", rc); 19662306a36Sopenharmony_ci return -EINVAL; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* 20162306a36Sopenharmony_ci * cxl_h_control_function - This H_CONTROL_CA_FUNCTION hypervisor call allows 20262306a36Sopenharmony_ci * the partition to manipulate or query 20362306a36Sopenharmony_ci * certain coherent platform function behaviors. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_cistatic long cxl_h_control_function(u64 unit_address, u64 op, 20662306a36Sopenharmony_ci u64 p1, u64 p2, u64 p3, u64 p4, u64 *out) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; 20962306a36Sopenharmony_ci long rc; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FUNCTION, unit_address, op, p1, p2, p3, p4); 21262306a36Sopenharmony_ci _PRINT_MSG(rc, "cxl_h_control_function(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n", 21362306a36Sopenharmony_ci unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc); 21462306a36Sopenharmony_ci trace_cxl_hcall_control_function(unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci switch (rc) { 21762306a36Sopenharmony_ci case H_SUCCESS: /* The operation is completed for the coherent platform function */ 21862306a36Sopenharmony_ci if ((op == H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT || 21962306a36Sopenharmony_ci op == H_CONTROL_CA_FUNCTION_READ_ERR_STATE || 22062306a36Sopenharmony_ci op == H_CONTROL_CA_FUNCTION_COLLECT_VPD)) 22162306a36Sopenharmony_ci *out = retbuf[0]; 22262306a36Sopenharmony_ci return 0; 22362306a36Sopenharmony_ci case H_PARAMETER: /* An incorrect parameter was supplied. */ 22462306a36Sopenharmony_ci case H_FUNCTION: /* The function is not supported. */ 22562306a36Sopenharmony_ci case H_NOT_FOUND: /* The operation supplied was not valid */ 22662306a36Sopenharmony_ci case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */ 22762306a36Sopenharmony_ci case H_SG_LIST: /* An block list entry was invalid */ 22862306a36Sopenharmony_ci return -EINVAL; 22962306a36Sopenharmony_ci case H_AUTHORITY: /* The partition does not have authority to perform this hcall */ 23062306a36Sopenharmony_ci case H_RESOURCE: /* The function has page table mappings for MMIO */ 23162306a36Sopenharmony_ci case H_HARDWARE: /* A hardware event prevented the attach operation */ 23262306a36Sopenharmony_ci case H_STATE: /* The coherent platform function is not in a valid state */ 23362306a36Sopenharmony_ci case H_BUSY: 23462306a36Sopenharmony_ci return -EBUSY; 23562306a36Sopenharmony_ci default: 23662306a36Sopenharmony_ci WARN(1, "Unexpected return code: %lx", rc); 23762306a36Sopenharmony_ci return -EINVAL; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* 24262306a36Sopenharmony_ci * cxl_h_reset_afu - Perform a reset to the coherent platform function. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_cilong cxl_h_reset_afu(u64 unit_address) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 24762306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_RESET, 24862306a36Sopenharmony_ci 0, 0, 0, 0, 24962306a36Sopenharmony_ci NULL); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* 25362306a36Sopenharmony_ci * cxl_h_suspend_process - Suspend a process from being executed 25462306a36Sopenharmony_ci * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when 25562306a36Sopenharmony_ci * process was attached. 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_cilong cxl_h_suspend_process(u64 unit_address, u64 process_token) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 26062306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS, 26162306a36Sopenharmony_ci process_token, 0, 0, 0, 26262306a36Sopenharmony_ci NULL); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* 26662306a36Sopenharmony_ci * cxl_h_resume_process - Resume a process to be executed 26762306a36Sopenharmony_ci * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when 26862306a36Sopenharmony_ci * process was attached. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_cilong cxl_h_resume_process(u64 unit_address, u64 process_token) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 27362306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_RESUME_PROCESS, 27462306a36Sopenharmony_ci process_token, 0, 0, 0, 27562306a36Sopenharmony_ci NULL); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * cxl_h_read_error_state - Checks the error state of the coherent 28062306a36Sopenharmony_ci * platform function. 28162306a36Sopenharmony_ci * R4 contains the error state 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_cilong cxl_h_read_error_state(u64 unit_address, u64 *state) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 28662306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_READ_ERR_STATE, 28762306a36Sopenharmony_ci 0, 0, 0, 0, 28862306a36Sopenharmony_ci state); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* 29262306a36Sopenharmony_ci * cxl_h_get_afu_err - collect the AFU error buffer 29362306a36Sopenharmony_ci * Parameter1 = byte offset into error buffer to retrieve, valid values 29462306a36Sopenharmony_ci * are between 0 and (ibm,error-buffer-size - 1) 29562306a36Sopenharmony_ci * Parameter2 = 4K aligned real address of error buffer, to be filled in 29662306a36Sopenharmony_ci * Parameter3 = length of error buffer, valid values are 4K or less 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_cilong cxl_h_get_afu_err(u64 unit_address, u64 offset, 29962306a36Sopenharmony_ci u64 buf_address, u64 len) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 30262306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_GET_AFU_ERR, 30362306a36Sopenharmony_ci offset, buf_address, len, 0, 30462306a36Sopenharmony_ci NULL); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/* 30862306a36Sopenharmony_ci * cxl_h_get_config - collect configuration record for the 30962306a36Sopenharmony_ci * coherent platform function 31062306a36Sopenharmony_ci * Parameter1 = # of configuration record to retrieve, valid values are 31162306a36Sopenharmony_ci * between 0 and (ibm,#config-records - 1) 31262306a36Sopenharmony_ci * Parameter2 = byte offset into configuration record to retrieve, 31362306a36Sopenharmony_ci * valid values are between 0 and (ibm,config-record-size - 1) 31462306a36Sopenharmony_ci * Parameter3 = 4K aligned real address of configuration record buffer, 31562306a36Sopenharmony_ci * to be filled in 31662306a36Sopenharmony_ci * Parameter4 = length of configuration buffer, valid values are 4K or less 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cilong cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset, 31962306a36Sopenharmony_ci u64 buf_address, u64 len) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 32262306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_GET_CONFIG, 32362306a36Sopenharmony_ci cr_num, offset, buf_address, len, 32462306a36Sopenharmony_ci NULL); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/* 32862306a36Sopenharmony_ci * cxl_h_terminate_process - Terminate the process before completion 32962306a36Sopenharmony_ci * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when 33062306a36Sopenharmony_ci * process was attached. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_cilong cxl_h_terminate_process(u64 unit_address, u64 process_token) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 33562306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS, 33662306a36Sopenharmony_ci process_token, 0, 0, 0, 33762306a36Sopenharmony_ci NULL); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* 34162306a36Sopenharmony_ci * cxl_h_collect_vpd - Collect VPD for the coherent platform function. 34262306a36Sopenharmony_ci * Parameter1 = # of VPD record to retrieve, valid values are between 0 34362306a36Sopenharmony_ci * and (ibm,#config-records - 1). 34462306a36Sopenharmony_ci * Parameter2 = 4K naturally aligned real buffer containing block 34562306a36Sopenharmony_ci * list entries 34662306a36Sopenharmony_ci * Parameter3 = number of block list entries in the block list, valid 34762306a36Sopenharmony_ci * values are between 0 and 256 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_cilong cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address, 35062306a36Sopenharmony_ci u64 num, u64 *out) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 35362306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_COLLECT_VPD, 35462306a36Sopenharmony_ci record, list_address, num, 0, 35562306a36Sopenharmony_ci out); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/* 35962306a36Sopenharmony_ci * cxl_h_get_fn_error_interrupt - Read the function-wide error data based on an interrupt 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_cilong cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 36462306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT, 36562306a36Sopenharmony_ci 0, 0, 0, 0, reg); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/* 36962306a36Sopenharmony_ci * cxl_h_ack_fn_error_interrupt - Acknowledge function-wide error data 37062306a36Sopenharmony_ci * based on an interrupt 37162306a36Sopenharmony_ci * Parameter1 = value to write to the function-wide error interrupt register 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_cilong cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 37662306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT, 37762306a36Sopenharmony_ci value, 0, 0, 0, 37862306a36Sopenharmony_ci NULL); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* 38262306a36Sopenharmony_ci * cxl_h_get_error_log - Retrieve the Platform Log ID (PLID) of 38362306a36Sopenharmony_ci * an error log 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_cilong cxl_h_get_error_log(u64 unit_address, u64 value) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci return cxl_h_control_function(unit_address, 38862306a36Sopenharmony_ci H_CONTROL_CA_FUNCTION_GET_ERROR_LOG, 38962306a36Sopenharmony_ci 0, 0, 0, 0, 39062306a36Sopenharmony_ci NULL); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/* 39462306a36Sopenharmony_ci * cxl_h_collect_int_info - Collect interrupt info about a coherent 39562306a36Sopenharmony_ci * platform function after an interrupt occurred. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_cilong cxl_h_collect_int_info(u64 unit_address, u64 process_token, 39862306a36Sopenharmony_ci struct cxl_irq_info *info) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci long rc; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci BUG_ON(sizeof(*info) != sizeof(unsigned long[PLPAR_HCALL9_BUFSIZE])); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci rc = plpar_hcall9(H_COLLECT_CA_INT_INFO, (unsigned long *) info, 40562306a36Sopenharmony_ci unit_address, process_token); 40662306a36Sopenharmony_ci _PRINT_MSG(rc, "cxl_h_collect_int_info(%#.16llx, 0x%llx): %li\n", 40762306a36Sopenharmony_ci unit_address, process_token, rc); 40862306a36Sopenharmony_ci trace_cxl_hcall_collect_int_info(unit_address, process_token, rc); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci switch (rc) { 41162306a36Sopenharmony_ci case H_SUCCESS: /* The interrupt info is returned in return registers. */ 41262306a36Sopenharmony_ci pr_devel("dsisr:%#llx, dar:%#llx, dsr:%#llx, pid_tid:%#llx, afu_err:%#llx, errstat:%#llx\n", 41362306a36Sopenharmony_ci info->dsisr, info->dar, info->dsr, info->reserved, 41462306a36Sopenharmony_ci info->afu_err, info->errstat); 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci case H_PARAMETER: /* An incorrect parameter was supplied. */ 41762306a36Sopenharmony_ci return -EINVAL; 41862306a36Sopenharmony_ci case H_AUTHORITY: /* The partition does not have authority to perform this hcall. */ 41962306a36Sopenharmony_ci case H_HARDWARE: /* A hardware event prevented the collection of the interrupt info.*/ 42062306a36Sopenharmony_ci case H_STATE: /* The coherent platform function is not in a valid state to collect interrupt info. */ 42162306a36Sopenharmony_ci return -EBUSY; 42262306a36Sopenharmony_ci default: 42362306a36Sopenharmony_ci WARN(1, "Unexpected return code: %lx", rc); 42462306a36Sopenharmony_ci return -EINVAL; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* 42962306a36Sopenharmony_ci * cxl_h_control_faults - Control the operation of a coherent platform 43062306a36Sopenharmony_ci * function after a fault occurs. 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * Parameters 43362306a36Sopenharmony_ci * control-mask: value to control the faults 43462306a36Sopenharmony_ci * looks like PSL_TFC_An shifted >> 32 43562306a36Sopenharmony_ci * reset-mask: mask to control reset of function faults 43662306a36Sopenharmony_ci * Set reset_mask = 1 to reset PSL errors 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_cilong cxl_h_control_faults(u64 unit_address, u64 process_token, 43962306a36Sopenharmony_ci u64 control_mask, u64 reset_mask) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 44262306a36Sopenharmony_ci long rc; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci memset(retbuf, 0, sizeof(retbuf)); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci rc = plpar_hcall(H_CONTROL_CA_FAULTS, retbuf, unit_address, 44762306a36Sopenharmony_ci H_CONTROL_CA_FAULTS_RESPOND_PSL, process_token, 44862306a36Sopenharmony_ci control_mask, reset_mask); 44962306a36Sopenharmony_ci _PRINT_MSG(rc, "cxl_h_control_faults(%#.16llx, 0x%llx, %#llx, %#llx): %li (%#lx)\n", 45062306a36Sopenharmony_ci unit_address, process_token, control_mask, reset_mask, 45162306a36Sopenharmony_ci rc, retbuf[0]); 45262306a36Sopenharmony_ci trace_cxl_hcall_control_faults(unit_address, process_token, 45362306a36Sopenharmony_ci control_mask, reset_mask, retbuf[0], rc); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci switch (rc) { 45662306a36Sopenharmony_ci case H_SUCCESS: /* Faults were successfully controlled for the function. */ 45762306a36Sopenharmony_ci return 0; 45862306a36Sopenharmony_ci case H_PARAMETER: /* An incorrect parameter was supplied. */ 45962306a36Sopenharmony_ci return -EINVAL; 46062306a36Sopenharmony_ci case H_HARDWARE: /* A hardware event prevented the control of faults. */ 46162306a36Sopenharmony_ci case H_STATE: /* The function was in an invalid state. */ 46262306a36Sopenharmony_ci case H_AUTHORITY: /* The partition does not have authority to perform this hcall; the coherent platform facilities may need to be licensed. */ 46362306a36Sopenharmony_ci return -EBUSY; 46462306a36Sopenharmony_ci case H_FUNCTION: /* The function is not supported */ 46562306a36Sopenharmony_ci case H_NOT_FOUND: /* The operation supplied was not valid */ 46662306a36Sopenharmony_ci return -EINVAL; 46762306a36Sopenharmony_ci default: 46862306a36Sopenharmony_ci WARN(1, "Unexpected return code: %lx", rc); 46962306a36Sopenharmony_ci return -EINVAL; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* 47462306a36Sopenharmony_ci * cxl_h_control_facility - This H_CONTROL_CA_FACILITY hypervisor call 47562306a36Sopenharmony_ci * allows the partition to manipulate or query 47662306a36Sopenharmony_ci * certain coherent platform facility behaviors. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic long cxl_h_control_facility(u64 unit_address, u64 op, 47962306a36Sopenharmony_ci u64 p1, u64 p2, u64 p3, u64 p4, u64 *out) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; 48262306a36Sopenharmony_ci long rc; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FACILITY, unit_address, op, p1, p2, p3, p4); 48562306a36Sopenharmony_ci _PRINT_MSG(rc, "cxl_h_control_facility(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n", 48662306a36Sopenharmony_ci unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc); 48762306a36Sopenharmony_ci trace_cxl_hcall_control_facility(unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci switch (rc) { 49062306a36Sopenharmony_ci case H_SUCCESS: /* The operation is completed for the coherent platform facility */ 49162306a36Sopenharmony_ci if (op == H_CONTROL_CA_FACILITY_COLLECT_VPD) 49262306a36Sopenharmony_ci *out = retbuf[0]; 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci case H_PARAMETER: /* An incorrect parameter was supplied. */ 49562306a36Sopenharmony_ci case H_FUNCTION: /* The function is not supported. */ 49662306a36Sopenharmony_ci case H_NOT_FOUND: /* The operation supplied was not valid */ 49762306a36Sopenharmony_ci case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */ 49862306a36Sopenharmony_ci case H_SG_LIST: /* An block list entry was invalid */ 49962306a36Sopenharmony_ci return -EINVAL; 50062306a36Sopenharmony_ci case H_AUTHORITY: /* The partition does not have authority to perform this hcall */ 50162306a36Sopenharmony_ci case H_RESOURCE: /* The function has page table mappings for MMIO */ 50262306a36Sopenharmony_ci case H_HARDWARE: /* A hardware event prevented the attach operation */ 50362306a36Sopenharmony_ci case H_STATE: /* The coherent platform facility is not in a valid state */ 50462306a36Sopenharmony_ci case H_BUSY: 50562306a36Sopenharmony_ci return -EBUSY; 50662306a36Sopenharmony_ci default: 50762306a36Sopenharmony_ci WARN(1, "Unexpected return code: %lx", rc); 50862306a36Sopenharmony_ci return -EINVAL; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/* 51362306a36Sopenharmony_ci * cxl_h_reset_adapter - Perform a reset to the coherent platform facility. 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_cilong cxl_h_reset_adapter(u64 unit_address) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci return cxl_h_control_facility(unit_address, 51862306a36Sopenharmony_ci H_CONTROL_CA_FACILITY_RESET, 51962306a36Sopenharmony_ci 0, 0, 0, 0, 52062306a36Sopenharmony_ci NULL); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* 52462306a36Sopenharmony_ci * cxl_h_collect_vpd - Collect VPD for the coherent platform function. 52562306a36Sopenharmony_ci * Parameter1 = 4K naturally aligned real buffer containing block 52662306a36Sopenharmony_ci * list entries 52762306a36Sopenharmony_ci * Parameter2 = number of block list entries in the block list, valid 52862306a36Sopenharmony_ci * values are between 0 and 256 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_cilong cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address, 53162306a36Sopenharmony_ci u64 num, u64 *out) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci return cxl_h_control_facility(unit_address, 53462306a36Sopenharmony_ci H_CONTROL_CA_FACILITY_COLLECT_VPD, 53562306a36Sopenharmony_ci list_address, num, 0, 0, 53662306a36Sopenharmony_ci out); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/* 54062306a36Sopenharmony_ci * cxl_h_download_facility - This H_DOWNLOAD_CA_FACILITY 54162306a36Sopenharmony_ci * hypervisor call provide platform support for 54262306a36Sopenharmony_ci * downloading a base adapter image to the coherent 54362306a36Sopenharmony_ci * platform facility, and for validating the entire 54462306a36Sopenharmony_ci * image after the download. 54562306a36Sopenharmony_ci * Parameters 54662306a36Sopenharmony_ci * op: operation to perform to the coherent platform function 54762306a36Sopenharmony_ci * Download: operation = 1, the base image in the coherent platform 54862306a36Sopenharmony_ci * facility is first erased, and then 54962306a36Sopenharmony_ci * programmed using the image supplied 55062306a36Sopenharmony_ci * in the scatter/gather list. 55162306a36Sopenharmony_ci * Validate: operation = 2, the base image in the coherent platform 55262306a36Sopenharmony_ci * facility is compared with the image 55362306a36Sopenharmony_ci * supplied in the scatter/gather list. 55462306a36Sopenharmony_ci * list_address: 4K naturally aligned real buffer containing 55562306a36Sopenharmony_ci * scatter/gather list entries. 55662306a36Sopenharmony_ci * num: number of block list entries in the scatter/gather list. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_cistatic long cxl_h_download_facility(u64 unit_address, u64 op, 55962306a36Sopenharmony_ci u64 list_address, u64 num, 56062306a36Sopenharmony_ci u64 *out) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 56362306a36Sopenharmony_ci unsigned int delay, total_delay = 0; 56462306a36Sopenharmony_ci u64 token = 0; 56562306a36Sopenharmony_ci long rc; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (*out != 0) 56862306a36Sopenharmony_ci token = *out; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci memset(retbuf, 0, sizeof(retbuf)); 57162306a36Sopenharmony_ci while (1) { 57262306a36Sopenharmony_ci rc = plpar_hcall(H_DOWNLOAD_CA_FACILITY, retbuf, 57362306a36Sopenharmony_ci unit_address, op, list_address, num, 57462306a36Sopenharmony_ci token); 57562306a36Sopenharmony_ci token = retbuf[0]; 57662306a36Sopenharmony_ci if (rc != H_BUSY && !H_IS_LONG_BUSY(rc)) 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (rc != H_BUSY) { 58062306a36Sopenharmony_ci delay = get_longbusy_msecs(rc); 58162306a36Sopenharmony_ci total_delay += delay; 58262306a36Sopenharmony_ci if (total_delay > CXL_HCALL_TIMEOUT_DOWNLOAD) { 58362306a36Sopenharmony_ci WARN(1, "Warning: Giving up waiting for CXL hcall " 58462306a36Sopenharmony_ci "%#x after %u msec\n", 58562306a36Sopenharmony_ci H_DOWNLOAD_CA_FACILITY, total_delay); 58662306a36Sopenharmony_ci rc = H_BUSY; 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci msleep(delay); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci _PRINT_MSG(rc, "cxl_h_download_facility(%#.16llx, %s(%#llx, %#llx), %#lx): %li\n", 59362306a36Sopenharmony_ci unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc); 59462306a36Sopenharmony_ci trace_cxl_hcall_download_facility(unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci switch (rc) { 59762306a36Sopenharmony_ci case H_SUCCESS: /* The operation is completed for the coherent platform facility */ 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci case H_PARAMETER: /* An incorrect parameter was supplied */ 60062306a36Sopenharmony_ci case H_FUNCTION: /* The function is not supported. */ 60162306a36Sopenharmony_ci case H_SG_LIST: /* An block list entry was invalid */ 60262306a36Sopenharmony_ci case H_BAD_DATA: /* Image verification failed */ 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci case H_AUTHORITY: /* The partition does not have authority to perform this hcall */ 60562306a36Sopenharmony_ci case H_RESOURCE: /* The function has page table mappings for MMIO */ 60662306a36Sopenharmony_ci case H_HARDWARE: /* A hardware event prevented the attach operation */ 60762306a36Sopenharmony_ci case H_STATE: /* The coherent platform facility is not in a valid state */ 60862306a36Sopenharmony_ci case H_BUSY: 60962306a36Sopenharmony_ci return -EBUSY; 61062306a36Sopenharmony_ci case H_CONTINUE: 61162306a36Sopenharmony_ci *out = retbuf[0]; 61262306a36Sopenharmony_ci return 1; /* More data is needed for the complete image */ 61362306a36Sopenharmony_ci default: 61462306a36Sopenharmony_ci WARN(1, "Unexpected return code: %lx", rc); 61562306a36Sopenharmony_ci return -EINVAL; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci/* 62062306a36Sopenharmony_ci * cxl_h_download_adapter_image - Download the base image to the coherent 62162306a36Sopenharmony_ci * platform facility. 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_cilong cxl_h_download_adapter_image(u64 unit_address, 62462306a36Sopenharmony_ci u64 list_address, u64 num, 62562306a36Sopenharmony_ci u64 *out) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci return cxl_h_download_facility(unit_address, 62862306a36Sopenharmony_ci H_DOWNLOAD_CA_FACILITY_DOWNLOAD, 62962306a36Sopenharmony_ci list_address, num, out); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci/* 63362306a36Sopenharmony_ci * cxl_h_validate_adapter_image - Validate the base image in the coherent 63462306a36Sopenharmony_ci * platform facility. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_cilong cxl_h_validate_adapter_image(u64 unit_address, 63762306a36Sopenharmony_ci u64 list_address, u64 num, 63862306a36Sopenharmony_ci u64 *out) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci return cxl_h_download_facility(unit_address, 64162306a36Sopenharmony_ci H_DOWNLOAD_CA_FACILITY_VALIDATE, 64262306a36Sopenharmony_ci list_address, num, out); 64362306a36Sopenharmony_ci} 644