2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2016-03-04 14:26:34 +03:00
/*
* Copyright 2015 IBM Corp .
*/
# include <linux/compiler.h>
# include <linux/types.h>
# include <linux/delay.h>
# include <asm/byteorder.h>
# include "hcalls.h"
2016-03-04 14:26:42 +03:00
# include "trace.h"
2016-03-04 14:26:34 +03:00
# define CXL_HCALL_TIMEOUT 60000
# define CXL_HCALL_TIMEOUT_DOWNLOAD 120000
# define H_ATTACH_CA_PROCESS 0x344
# define H_CONTROL_CA_FUNCTION 0x348
# define H_DETACH_CA_PROCESS 0x34C
# define H_COLLECT_CA_INT_INFO 0x350
# define H_CONTROL_CA_FAULTS 0x354
# define H_DOWNLOAD_CA_FUNCTION 0x35C
# define H_DOWNLOAD_CA_FACILITY 0x364
# define H_CONTROL_CA_FACILITY 0x368
# define H_CONTROL_CA_FUNCTION_RESET 1 /* perform a reset */
# define H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS 2 /* suspend a process from being executed */
# define H_CONTROL_CA_FUNCTION_RESUME_PROCESS 3 /* resume a process to be executed */
# define H_CONTROL_CA_FUNCTION_READ_ERR_STATE 4 /* read the error state */
# define H_CONTROL_CA_FUNCTION_GET_AFU_ERR 5 /* collect the AFU error buffer */
# define H_CONTROL_CA_FUNCTION_GET_CONFIG 6 /* collect configuration record */
# define H_CONTROL_CA_FUNCTION_GET_DOWNLOAD_STATE 7 /* query to return download status */
# define H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS 8 /* terminate the process before completion */
# define H_CONTROL_CA_FUNCTION_COLLECT_VPD 9 /* collect VPD */
# define H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT 11 /* read the function-wide error data based on an interrupt */
# define H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT 12 /* acknowledge function-wide error data based on an interrupt */
# define H_CONTROL_CA_FUNCTION_GET_ERROR_LOG 13 /* retrieve the Platform Log ID (PLID) of an error log */
# define H_CONTROL_CA_FAULTS_RESPOND_PSL 1
# define H_CONTROL_CA_FAULTS_RESPOND_AFU 2
# define H_CONTROL_CA_FACILITY_RESET 1 /* perform a reset */
# define H_CONTROL_CA_FACILITY_COLLECT_VPD 2 /* collect VPD */
# define H_DOWNLOAD_CA_FACILITY_DOWNLOAD 1 /* download adapter image */
# define H_DOWNLOAD_CA_FACILITY_VALIDATE 2 /* validate adapter image */
# define _CXL_LOOP_HCALL(call, rc, retbuf, fn, ...) \
{ \
unsigned int delay , total_delay = 0 ; \
u64 token = 0 ; \
\
memset ( retbuf , 0 , sizeof ( retbuf ) ) ; \
while ( 1 ) { \
rc = call ( fn , retbuf , __VA_ARGS__ , token ) ; \
token = retbuf [ 0 ] ; \
if ( rc ! = H_BUSY & & ! H_IS_LONG_BUSY ( rc ) ) \
break ; \
\
if ( rc = = H_BUSY ) \
delay = 10 ; \
else \
delay = get_longbusy_msecs ( rc ) ; \
\
total_delay + = delay ; \
if ( total_delay > CXL_HCALL_TIMEOUT ) { \
WARN ( 1 , " Warning: Giving up waiting for CXL hcall " \
" %#x after %u msec \n " , fn , total_delay ) ; \
rc = H_BUSY ; \
break ; \
} \
msleep ( delay ) ; \
} \
}
# define CXL_H_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall, __VA_ARGS__)
# define CXL_H9_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall9, __VA_ARGS__)
# define _PRINT_MSG(rc, format, ...) \
{ \
if ( ( rc ! = H_SUCCESS ) & & ( rc ! = H_CONTINUE ) ) \
pr_err ( format , __VA_ARGS__ ) ; \
else \
pr_devel ( format , __VA_ARGS__ ) ; \
} \
static char * afu_op_names [ ] = {
" UNKNOWN_OP " , /* 0 undefined */
" RESET " , /* 1 */
" SUSPEND_PROCESS " , /* 2 */
" RESUME_PROCESS " , /* 3 */
" READ_ERR_STATE " , /* 4 */
" GET_AFU_ERR " , /* 5 */
" GET_CONFIG " , /* 6 */
" GET_DOWNLOAD_STATE " , /* 7 */
" TERMINATE_PROCESS " , /* 8 */
" COLLECT_VPD " , /* 9 */
" UNKNOWN_OP " , /* 10 undefined */
" GET_FUNCTION_ERR_INT " , /* 11 */
" ACK_FUNCTION_ERR_INT " , /* 12 */
" GET_ERROR_LOG " , /* 13 */
} ;
static char * control_adapter_op_names [ ] = {
" UNKNOWN_OP " , /* 0 undefined */
" RESET " , /* 1 */
" COLLECT_VPD " , /* 2 */
} ;
static char * download_op_names [ ] = {
" UNKNOWN_OP " , /* 0 undefined */
" DOWNLOAD " , /* 1 */
" VALIDATE " , /* 2 */
} ;
static char * op_str ( unsigned int op , char * name_array [ ] , int array_len )
{
if ( op > = array_len )
return " UNKNOWN_OP " ;
return name_array [ op ] ;
}
# define OP_STR(op, name_array) op_str(op, name_array, ARRAY_SIZE(name_array))
# define OP_STR_AFU(op) OP_STR(op, afu_op_names)
# define OP_STR_CONTROL_ADAPTER(op) OP_STR(op, control_adapter_op_names)
# define OP_STR_DOWNLOAD_ADAPTER(op) OP_STR(op, download_op_names)
long cxl_h_attach_process ( u64 unit_address ,
struct cxl_process_element_hcall * element ,
u64 * process_token , u64 * mmio_addr , u64 * mmio_size )
{
unsigned long retbuf [ PLPAR_HCALL_BUFSIZE ] ;
long rc ;
CXL_H_WAIT_UNTIL_DONE ( rc , retbuf , H_ATTACH_CA_PROCESS , unit_address , virt_to_phys ( element ) ) ;
_PRINT_MSG ( rc , " cxl_h_attach_process(%#.16llx, %#.16lx): %li \n " ,
unit_address , virt_to_phys ( element ) , rc ) ;
2016-03-04 14:26:42 +03:00
trace_cxl_hcall_attach ( unit_address , virt_to_phys ( element ) , retbuf [ 0 ] , retbuf [ 1 ] , retbuf [ 2 ] , rc ) ;
2016-03-04 14:26:34 +03:00
pr_devel ( " token: 0x%.8lx mmio_addr: 0x%lx mmio_size: 0x%lx \n Process Element Structure: \n " ,
retbuf [ 0 ] , retbuf [ 1 ] , retbuf [ 2 ] ) ;
cxl_dump_debug_buffer ( element , sizeof ( * element ) ) ;
switch ( rc ) {
case H_SUCCESS : /* The process info is attached to the coherent platform function */
* process_token = retbuf [ 0 ] ;
if ( mmio_addr )
* mmio_addr = retbuf [ 1 ] ;
if ( mmio_size )
* mmio_size = retbuf [ 2 ] ;
return 0 ;
case H_PARAMETER : /* An incorrect parameter was supplied. */
case H_FUNCTION : /* The function is not supported. */
return - EINVAL ;
case H_AUTHORITY : /* The partition does not have authority to perform this hcall */
case H_RESOURCE : /* The coherent platform function does not have enough additional resource to attach the process */
case H_HARDWARE : /* A hardware event prevented the attach operation */
case H_STATE : /* The coherent platform function is not in a valid state */
case H_BUSY :
return - EBUSY ;
default :
WARN ( 1 , " Unexpected return code: %lx " , rc ) ;
return - EINVAL ;
}
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_detach_process - Detach a process element from a coherent
* platform function .
*/
long cxl_h_detach_process ( u64 unit_address , u64 process_token )
{
unsigned long retbuf [ PLPAR_HCALL_BUFSIZE ] ;
long rc ;
CXL_H_WAIT_UNTIL_DONE ( rc , retbuf , H_DETACH_CA_PROCESS , unit_address , process_token ) ;
_PRINT_MSG ( rc , " cxl_h_detach_process(%#.16llx, 0x%.8llx): %li \n " , unit_address , process_token , rc ) ;
2016-03-04 14:26:42 +03:00
trace_cxl_hcall_detach ( unit_address , process_token , rc ) ;
2016-03-04 14:26:34 +03:00
switch ( rc ) {
case H_SUCCESS : /* The process was detached from the coherent platform function */
return 0 ;
case H_PARAMETER : /* An incorrect parameter was supplied. */
return - EINVAL ;
case H_AUTHORITY : /* The partition does not have authority to perform this hcall */
case H_RESOURCE : /* The function has page table mappings for MMIO */
case H_HARDWARE : /* A hardware event prevented the detach operation */
case H_STATE : /* The coherent platform function is not in a valid state */
case H_BUSY :
return - EBUSY ;
default :
WARN ( 1 , " Unexpected return code: %lx " , rc ) ;
return - EINVAL ;
}
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_control_function - This H_CONTROL_CA_FUNCTION hypervisor call allows
* the partition to manipulate or query
* certain coherent platform function behaviors .
*/
static long cxl_h_control_function ( u64 unit_address , u64 op ,
u64 p1 , u64 p2 , u64 p3 , u64 p4 , u64 * out )
{
unsigned long retbuf [ PLPAR_HCALL9_BUFSIZE ] ;
long rc ;
CXL_H9_WAIT_UNTIL_DONE ( rc , retbuf , H_CONTROL_CA_FUNCTION , unit_address , op , p1 , p2 , p3 , p4 ) ;
_PRINT_MSG ( rc , " cxl_h_control_function(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li \n " ,
unit_address , OP_STR_AFU ( op ) , p1 , p2 , p3 , p4 , retbuf [ 0 ] , rc ) ;
2016-03-04 14:26:42 +03:00
trace_cxl_hcall_control_function ( unit_address , OP_STR_AFU ( op ) , p1 , p2 , p3 , p4 , retbuf [ 0 ] , rc ) ;
2016-03-04 14:26:34 +03:00
switch ( rc ) {
case H_SUCCESS : /* The operation is completed for the coherent platform function */
if ( ( op = = H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT | |
op = = H_CONTROL_CA_FUNCTION_READ_ERR_STATE | |
op = = H_CONTROL_CA_FUNCTION_COLLECT_VPD ) )
* out = retbuf [ 0 ] ;
return 0 ;
case H_PARAMETER : /* An incorrect parameter was supplied. */
case H_FUNCTION : /* The function is not supported. */
case H_NOT_FOUND : /* The operation supplied was not valid */
case H_NOT_AVAILABLE : /* The operation cannot be performed because the AFU has not been downloaded */
case H_SG_LIST : /* An block list entry was invalid */
return - EINVAL ;
case H_AUTHORITY : /* The partition does not have authority to perform this hcall */
case H_RESOURCE : /* The function has page table mappings for MMIO */
case H_HARDWARE : /* A hardware event prevented the attach operation */
case H_STATE : /* The coherent platform function is not in a valid state */
case H_BUSY :
return - EBUSY ;
default :
WARN ( 1 , " Unexpected return code: %lx " , rc ) ;
return - EINVAL ;
}
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_reset_afu - Perform a reset to the coherent platform function .
*/
long cxl_h_reset_afu ( u64 unit_address )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_RESET ,
0 , 0 , 0 , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_suspend_process - Suspend a process from being executed
* Parameter1 = process - token as returned from H_ATTACH_CA_PROCESS when
* process was attached .
*/
long cxl_h_suspend_process ( u64 unit_address , u64 process_token )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS ,
process_token , 0 , 0 , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_resume_process - Resume a process to be executed
* Parameter1 = process - token as returned from H_ATTACH_CA_PROCESS when
* process was attached .
*/
long cxl_h_resume_process ( u64 unit_address , u64 process_token )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_RESUME_PROCESS ,
process_token , 0 , 0 , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_read_error_state - Checks the error state of the coherent
* platform function .
* R4 contains the error state
*/
long cxl_h_read_error_state ( u64 unit_address , u64 * state )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_READ_ERR_STATE ,
0 , 0 , 0 , 0 ,
state ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_get_afu_err - collect the AFU error buffer
* Parameter1 = byte offset into error buffer to retrieve , valid values
* are between 0 and ( ibm , error - buffer - size - 1 )
* Parameter2 = 4 K aligned real address of error buffer , to be filled in
* Parameter3 = length of error buffer , valid values are 4 K or less
*/
long cxl_h_get_afu_err ( u64 unit_address , u64 offset ,
u64 buf_address , u64 len )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_GET_AFU_ERR ,
offset , buf_address , len , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_get_config - collect configuration record for the
* coherent platform function
* Parameter1 = # of configuration record to retrieve , valid values are
* between 0 and ( ibm , # config - records - 1 )
* Parameter2 = byte offset into configuration record to retrieve ,
* valid values are between 0 and ( ibm , config - record - size - 1 )
* Parameter3 = 4 K aligned real address of configuration record buffer ,
* to be filled in
* Parameter4 = length of configuration buffer , valid values are 4 K or less
*/
long cxl_h_get_config ( u64 unit_address , u64 cr_num , u64 offset ,
u64 buf_address , u64 len )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_GET_CONFIG ,
cr_num , offset , buf_address , len ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_terminate_process - Terminate the process before completion
* Parameter1 = process - token as returned from H_ATTACH_CA_PROCESS when
* process was attached .
*/
long cxl_h_terminate_process ( u64 unit_address , u64 process_token )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS ,
process_token , 0 , 0 , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_collect_vpd - Collect VPD for the coherent platform function .
* Parameter1 = # of VPD record to retrieve , valid values are between 0
* and ( ibm , # config - records - 1 ) .
* Parameter2 = 4 K naturally aligned real buffer containing block
* list entries
* Parameter3 = number of block list entries in the block list , valid
* values are between 0 and 256
*/
long cxl_h_collect_vpd ( u64 unit_address , u64 record , u64 list_address ,
u64 num , u64 * out )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_COLLECT_VPD ,
record , list_address , num , 0 ,
out ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_get_fn_error_interrupt - Read the function - wide error data based on an interrupt
*/
long cxl_h_get_fn_error_interrupt ( u64 unit_address , u64 * reg )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT ,
0 , 0 , 0 , 0 , reg ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_ack_fn_error_interrupt - Acknowledge function - wide error data
* based on an interrupt
* Parameter1 = value to write to the function - wide error interrupt register
*/
long cxl_h_ack_fn_error_interrupt ( u64 unit_address , u64 value )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT ,
value , 0 , 0 , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_get_error_log - Retrieve the Platform Log ID ( PLID ) of
* an error log
*/
long cxl_h_get_error_log ( u64 unit_address , u64 value )
{
return cxl_h_control_function ( unit_address ,
H_CONTROL_CA_FUNCTION_GET_ERROR_LOG ,
0 , 0 , 0 , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_collect_int_info - Collect interrupt info about a coherent
* platform function after an interrupt occurred .
*/
long cxl_h_collect_int_info ( u64 unit_address , u64 process_token ,
struct cxl_irq_info * info )
{
long rc ;
BUG_ON ( sizeof ( * info ) ! = sizeof ( unsigned long [ PLPAR_HCALL9_BUFSIZE ] ) ) ;
rc = plpar_hcall9 ( H_COLLECT_CA_INT_INFO , ( unsigned long * ) info ,
unit_address , process_token ) ;
_PRINT_MSG ( rc , " cxl_h_collect_int_info(%#.16llx, 0x%llx): %li \n " ,
unit_address , process_token , rc ) ;
2016-03-04 14:26:42 +03:00
trace_cxl_hcall_collect_int_info ( unit_address , process_token , rc ) ;
2016-03-04 14:26:34 +03:00
switch ( rc ) {
case H_SUCCESS : /* The interrupt info is returned in return registers. */
2017-04-07 17:11:54 +03:00
pr_devel ( " dsisr:%#llx, dar:%#llx, dsr:%#llx, pid_tid:%#llx, afu_err:%#llx, errstat:%#llx \n " ,
info - > dsisr , info - > dar , info - > dsr , info - > reserved ,
info - > afu_err , info - > errstat ) ;
2016-03-04 14:26:34 +03:00
return 0 ;
case H_PARAMETER : /* An incorrect parameter was supplied. */
return - EINVAL ;
case H_AUTHORITY : /* The partition does not have authority to perform this hcall. */
case H_HARDWARE : /* A hardware event prevented the collection of the interrupt info.*/
case H_STATE : /* The coherent platform function is not in a valid state to collect interrupt info. */
return - EBUSY ;
default :
WARN ( 1 , " Unexpected return code: %lx " , rc ) ;
return - EINVAL ;
}
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_control_faults - Control the operation of a coherent platform
* function after a fault occurs .
*
* Parameters
* control - mask : value to control the faults
* looks like PSL_TFC_An shifted > > 32
* reset - mask : mask to control reset of function faults
* Set reset_mask = 1 to reset PSL errors
*/
long cxl_h_control_faults ( u64 unit_address , u64 process_token ,
u64 control_mask , u64 reset_mask )
{
unsigned long retbuf [ PLPAR_HCALL_BUFSIZE ] ;
long rc ;
memset ( retbuf , 0 , sizeof ( retbuf ) ) ;
rc = plpar_hcall ( H_CONTROL_CA_FAULTS , retbuf , unit_address ,
H_CONTROL_CA_FAULTS_RESPOND_PSL , process_token ,
control_mask , reset_mask ) ;
_PRINT_MSG ( rc , " cxl_h_control_faults(%#.16llx, 0x%llx, %#llx, %#llx): %li (%#lx) \n " ,
unit_address , process_token , control_mask , reset_mask ,
rc , retbuf [ 0 ] ) ;
2016-03-04 14:26:42 +03:00
trace_cxl_hcall_control_faults ( unit_address , process_token ,
control_mask , reset_mask , retbuf [ 0 ] , rc ) ;
2016-03-04 14:26:34 +03:00
switch ( rc ) {
case H_SUCCESS : /* Faults were successfully controlled for the function. */
return 0 ;
case H_PARAMETER : /* An incorrect parameter was supplied. */
return - EINVAL ;
case H_HARDWARE : /* A hardware event prevented the control of faults. */
case H_STATE : /* The function was in an invalid state. */
case H_AUTHORITY : /* The partition does not have authority to perform this hcall; the coherent platform facilities may need to be licensed. */
return - EBUSY ;
case H_FUNCTION : /* The function is not supported */
case H_NOT_FOUND : /* The operation supplied was not valid */
return - EINVAL ;
default :
WARN ( 1 , " Unexpected return code: %lx " , rc ) ;
return - EINVAL ;
}
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_control_facility - This H_CONTROL_CA_FACILITY hypervisor call
* allows the partition to manipulate or query
* certain coherent platform facility behaviors .
*/
static long cxl_h_control_facility ( u64 unit_address , u64 op ,
u64 p1 , u64 p2 , u64 p3 , u64 p4 , u64 * out )
{
unsigned long retbuf [ PLPAR_HCALL9_BUFSIZE ] ;
long rc ;
CXL_H9_WAIT_UNTIL_DONE ( rc , retbuf , H_CONTROL_CA_FACILITY , unit_address , op , p1 , p2 , p3 , p4 ) ;
_PRINT_MSG ( rc , " cxl_h_control_facility(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li \n " ,
unit_address , OP_STR_CONTROL_ADAPTER ( op ) , p1 , p2 , p3 , p4 , retbuf [ 0 ] , rc ) ;
2016-03-04 14:26:42 +03:00
trace_cxl_hcall_control_facility ( unit_address , OP_STR_CONTROL_ADAPTER ( op ) , p1 , p2 , p3 , p4 , retbuf [ 0 ] , rc ) ;
2016-03-04 14:26:34 +03:00
switch ( rc ) {
case H_SUCCESS : /* The operation is completed for the coherent platform facility */
if ( op = = H_CONTROL_CA_FACILITY_COLLECT_VPD )
* out = retbuf [ 0 ] ;
return 0 ;
case H_PARAMETER : /* An incorrect parameter was supplied. */
case H_FUNCTION : /* The function is not supported. */
case H_NOT_FOUND : /* The operation supplied was not valid */
case H_NOT_AVAILABLE : /* The operation cannot be performed because the AFU has not been downloaded */
case H_SG_LIST : /* An block list entry was invalid */
return - EINVAL ;
case H_AUTHORITY : /* The partition does not have authority to perform this hcall */
case H_RESOURCE : /* The function has page table mappings for MMIO */
case H_HARDWARE : /* A hardware event prevented the attach operation */
case H_STATE : /* The coherent platform facility is not in a valid state */
case H_BUSY :
return - EBUSY ;
default :
WARN ( 1 , " Unexpected return code: %lx " , rc ) ;
return - EINVAL ;
}
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_reset_adapter - Perform a reset to the coherent platform facility .
*/
long cxl_h_reset_adapter ( u64 unit_address )
{
return cxl_h_control_facility ( unit_address ,
H_CONTROL_CA_FACILITY_RESET ,
0 , 0 , 0 , 0 ,
NULL ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_collect_vpd - Collect VPD for the coherent platform function .
* Parameter1 = 4 K naturally aligned real buffer containing block
* list entries
* Parameter2 = number of block list entries in the block list , valid
* values are between 0 and 256
*/
long cxl_h_collect_vpd_adapter ( u64 unit_address , u64 list_address ,
u64 num , u64 * out )
{
return cxl_h_control_facility ( unit_address ,
H_CONTROL_CA_FACILITY_COLLECT_VPD ,
list_address , num , 0 , 0 ,
out ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_download_facility - This H_DOWNLOAD_CA_FACILITY
* hypervisor call provide platform support for
* downloading a base adapter image to the coherent
* platform facility , and for validating the entire
* image after the download .
* Parameters
* op : operation to perform to the coherent platform function
* Download : operation = 1 , the base image in the coherent platform
* facility is first erased , and then
* programmed using the image supplied
* in the scatter / gather list .
* Validate : operation = 2 , the base image in the coherent platform
* facility is compared with the image
* supplied in the scatter / gather list .
* list_address : 4 K naturally aligned real buffer containing
* scatter / gather list entries .
* num : number of block list entries in the scatter / gather list .
*/
static long cxl_h_download_facility ( u64 unit_address , u64 op ,
u64 list_address , u64 num ,
u64 * out )
{
unsigned long retbuf [ PLPAR_HCALL_BUFSIZE ] ;
unsigned int delay , total_delay = 0 ;
u64 token = 0 ;
long rc ;
if ( * out ! = 0 )
token = * out ;
memset ( retbuf , 0 , sizeof ( retbuf ) ) ;
while ( 1 ) {
rc = plpar_hcall ( H_DOWNLOAD_CA_FACILITY , retbuf ,
unit_address , op , list_address , num ,
token ) ;
token = retbuf [ 0 ] ;
if ( rc ! = H_BUSY & & ! H_IS_LONG_BUSY ( rc ) )
break ;
if ( rc ! = H_BUSY ) {
delay = get_longbusy_msecs ( rc ) ;
total_delay + = delay ;
if ( total_delay > CXL_HCALL_TIMEOUT_DOWNLOAD ) {
WARN ( 1 , " Warning: Giving up waiting for CXL hcall "
" %#x after %u msec \n " ,
H_DOWNLOAD_CA_FACILITY , total_delay ) ;
rc = H_BUSY ;
break ;
}
msleep ( delay ) ;
}
}
_PRINT_MSG ( rc , " cxl_h_download_facility(%#.16llx, %s(%#llx, %#llx), %#lx): %li \n " ,
unit_address , OP_STR_DOWNLOAD_ADAPTER ( op ) , list_address , num , retbuf [ 0 ] , rc ) ;
2016-03-04 14:26:42 +03:00
trace_cxl_hcall_download_facility ( unit_address , OP_STR_DOWNLOAD_ADAPTER ( op ) , list_address , num , retbuf [ 0 ] , rc ) ;
2016-03-04 14:26:34 +03:00
switch ( rc ) {
case H_SUCCESS : /* The operation is completed for the coherent platform facility */
return 0 ;
case H_PARAMETER : /* An incorrect parameter was supplied */
case H_FUNCTION : /* The function is not supported. */
case H_SG_LIST : /* An block list entry was invalid */
case H_BAD_DATA : /* Image verification failed */
return - EINVAL ;
case H_AUTHORITY : /* The partition does not have authority to perform this hcall */
case H_RESOURCE : /* The function has page table mappings for MMIO */
case H_HARDWARE : /* A hardware event prevented the attach operation */
case H_STATE : /* The coherent platform facility is not in a valid state */
case H_BUSY :
return - EBUSY ;
case H_CONTINUE :
* out = retbuf [ 0 ] ;
return 1 ; /* More data is needed for the complete image */
default :
WARN ( 1 , " Unexpected return code: %lx " , rc ) ;
return - EINVAL ;
}
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_download_adapter_image - Download the base image to the coherent
* platform facility .
*/
long cxl_h_download_adapter_image ( u64 unit_address ,
u64 list_address , u64 num ,
u64 * out )
{
return cxl_h_download_facility ( unit_address ,
H_DOWNLOAD_CA_FACILITY_DOWNLOAD ,
list_address , num , out ) ;
}
2020-07-01 11:31:15 +03:00
/*
2016-03-04 14:26:34 +03:00
* cxl_h_validate_adapter_image - Validate the base image in the coherent
* platform facility .
*/
long cxl_h_validate_adapter_image ( u64 unit_address ,
u64 list_address , u64 num ,
u64 * out )
{
return cxl_h_download_facility ( unit_address ,
H_DOWNLOAD_CA_FACILITY_VALIDATE ,
list_address , num , out ) ;
}