2022-05-01 16:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/*
* Apple RTKit IPC library
* Copyright ( C ) The Asahi Linux Contributors
*/
# include "rtkit-internal.h"
enum {
APPLE_RTKIT_PWR_STATE_OFF = 0x00 , /* power off, cannot be restarted */
APPLE_RTKIT_PWR_STATE_SLEEP = 0x01 , /* sleeping, can be restarted */
2023-01-23 15:53:54 +09:00
APPLE_RTKIT_PWR_STATE_IDLE = 0x201 , /* sleeping, retain state */
2022-05-01 16:55:06 +02:00
APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10 , /* running but no communication */
APPLE_RTKIT_PWR_STATE_ON = 0x20 , /* normal operating state */
} ;
enum {
APPLE_RTKIT_EP_MGMT = 0 ,
APPLE_RTKIT_EP_CRASHLOG = 1 ,
APPLE_RTKIT_EP_SYSLOG = 2 ,
APPLE_RTKIT_EP_DEBUG = 3 ,
APPLE_RTKIT_EP_IOREPORT = 4 ,
APPLE_RTKIT_EP_OSLOG = 8 ,
} ;
# define APPLE_RTKIT_MGMT_TYPE GENMASK_ULL(59, 52)
enum {
APPLE_RTKIT_MGMT_HELLO = 1 ,
APPLE_RTKIT_MGMT_HELLO_REPLY = 2 ,
APPLE_RTKIT_MGMT_STARTEP = 5 ,
APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE = 6 ,
APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK = 7 ,
APPLE_RTKIT_MGMT_EPMAP = 8 ,
APPLE_RTKIT_MGMT_EPMAP_REPLY = 8 ,
APPLE_RTKIT_MGMT_SET_AP_PWR_STATE = 0xb ,
APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK = 0xb ,
} ;
# define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK_ULL(15, 0)
# define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK_ULL(31, 16)
# define APPLE_RTKIT_MGMT_EPMAP_LAST BIT_ULL(51)
# define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK_ULL(34, 32)
# define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK_ULL(31, 0)
# define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT_ULL(0)
# define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK_ULL(39, 32)
# define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT_ULL(1)
# define APPLE_RTKIT_MGMT_PWR_STATE GENMASK_ULL(15, 0)
# define APPLE_RTKIT_CRASHLOG_CRASH 1
# define APPLE_RTKIT_BUFFER_REQUEST 1
# define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44)
2023-02-24 15:49:44 +09:00
# define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0)
2022-05-01 16:55:06 +02:00
# define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52)
# define APPLE_RTKIT_SYSLOG_LOG 5
# define APPLE_RTKIT_SYSLOG_INIT 8
# define APPLE_RTKIT_SYSLOG_N_ENTRIES GENMASK_ULL(7, 0)
# define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24)
# define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56)
# define APPLE_RTKIT_OSLOG_INIT 1
# define APPLE_RTKIT_OSLOG_ACK 3
# define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
# define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
struct apple_rtkit_msg {
struct completion * completion ;
struct apple_mbox_msg mbox_msg ;
} ;
struct apple_rtkit_rx_work {
struct apple_rtkit * rtk ;
u8 ep ;
u64 msg ;
struct work_struct work ;
} ;
bool apple_rtkit_is_running ( struct apple_rtkit * rtk )
{
if ( rtk - > crashed )
return false ;
if ( ( rtk - > iop_power_state & 0xff ) ! = APPLE_RTKIT_PWR_STATE_ON )
return false ;
if ( ( rtk - > ap_power_state & 0xff ) ! = APPLE_RTKIT_PWR_STATE_ON )
return false ;
return true ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_is_running ) ;
bool apple_rtkit_is_crashed ( struct apple_rtkit * rtk )
{
return rtk - > crashed ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_is_crashed ) ;
static void apple_rtkit_management_send ( struct apple_rtkit * rtk , u8 type ,
u64 msg )
{
msg & = ~ APPLE_RTKIT_MGMT_TYPE ;
msg | = FIELD_PREP ( APPLE_RTKIT_MGMT_TYPE , type ) ;
apple_rtkit_send_message ( rtk , APPLE_RTKIT_EP_MGMT , msg , NULL , false ) ;
}
static void apple_rtkit_management_rx_hello ( struct apple_rtkit * rtk , u64 msg )
{
u64 reply ;
int min_ver = FIELD_GET ( APPLE_RTKIT_MGMT_HELLO_MINVER , msg ) ;
int max_ver = FIELD_GET ( APPLE_RTKIT_MGMT_HELLO_MAXVER , msg ) ;
int want_ver = min ( APPLE_RTKIT_MAX_SUPPORTED_VERSION , max_ver ) ;
dev_dbg ( rtk - > dev , " RTKit: Min ver %d, max ver %d \n " , min_ver , max_ver ) ;
if ( min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION ) {
dev_err ( rtk - > dev , " RTKit: Firmware min version %d is too new \n " ,
min_ver ) ;
goto abort_boot ;
}
if ( max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION ) {
dev_err ( rtk - > dev , " RTKit: Firmware max version %d is too old \n " ,
max_ver ) ;
goto abort_boot ;
}
dev_info ( rtk - > dev , " RTKit: Initializing (protocol version %d) \n " ,
want_ver ) ;
rtk - > version = want_ver ;
reply = FIELD_PREP ( APPLE_RTKIT_MGMT_HELLO_MINVER , want_ver ) ;
reply | = FIELD_PREP ( APPLE_RTKIT_MGMT_HELLO_MAXVER , want_ver ) ;
apple_rtkit_management_send ( rtk , APPLE_RTKIT_MGMT_HELLO_REPLY , reply ) ;
return ;
abort_boot :
rtk - > boot_result = - EINVAL ;
complete_all ( & rtk - > epmap_completion ) ;
}
static void apple_rtkit_management_rx_epmap ( struct apple_rtkit * rtk , u64 msg )
{
int i , ep ;
u64 reply ;
unsigned long bitmap = FIELD_GET ( APPLE_RTKIT_MGMT_EPMAP_BITMAP , msg ) ;
u32 base = FIELD_GET ( APPLE_RTKIT_MGMT_EPMAP_BASE , msg ) ;
dev_dbg ( rtk - > dev ,
" RTKit: received endpoint bitmap 0x%lx with base 0x%x \n " ,
bitmap , base ) ;
for_each_set_bit ( i , & bitmap , 32 ) {
ep = 32 * base + i ;
dev_dbg ( rtk - > dev , " RTKit: Discovered endpoint 0x%02x \n " , ep ) ;
set_bit ( ep , rtk - > endpoints ) ;
}
reply = FIELD_PREP ( APPLE_RTKIT_MGMT_EPMAP_BASE , base ) ;
if ( msg & APPLE_RTKIT_MGMT_EPMAP_LAST )
reply | = APPLE_RTKIT_MGMT_EPMAP_LAST ;
else
reply | = APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE ;
apple_rtkit_management_send ( rtk , APPLE_RTKIT_MGMT_EPMAP_REPLY , reply ) ;
if ( ! ( msg & APPLE_RTKIT_MGMT_EPMAP_LAST ) )
return ;
for_each_set_bit ( ep , rtk - > endpoints , APPLE_RTKIT_APP_ENDPOINT_START ) {
switch ( ep ) {
/* the management endpoint is started by default */
case APPLE_RTKIT_EP_MGMT :
break ;
/* without starting these RTKit refuses to boot */
case APPLE_RTKIT_EP_SYSLOG :
case APPLE_RTKIT_EP_CRASHLOG :
case APPLE_RTKIT_EP_DEBUG :
case APPLE_RTKIT_EP_IOREPORT :
case APPLE_RTKIT_EP_OSLOG :
dev_dbg ( rtk - > dev ,
" RTKit: Starting system endpoint 0x%02x \n " , ep ) ;
apple_rtkit_start_ep ( rtk , ep ) ;
break ;
default :
dev_warn ( rtk - > dev ,
" RTKit: Unknown system endpoint: 0x%02x \n " ,
ep ) ;
}
}
rtk - > boot_result = 0 ;
complete_all ( & rtk - > epmap_completion ) ;
}
static void apple_rtkit_management_rx_iop_pwr_ack ( struct apple_rtkit * rtk ,
u64 msg )
{
unsigned int new_state = FIELD_GET ( APPLE_RTKIT_MGMT_PWR_STATE , msg ) ;
dev_dbg ( rtk - > dev , " RTKit: IOP power state transition: 0x%x -> 0x%x \n " ,
rtk - > iop_power_state , new_state ) ;
rtk - > iop_power_state = new_state ;
complete_all ( & rtk - > iop_pwr_ack_completion ) ;
}
static void apple_rtkit_management_rx_ap_pwr_ack ( struct apple_rtkit * rtk ,
u64 msg )
{
unsigned int new_state = FIELD_GET ( APPLE_RTKIT_MGMT_PWR_STATE , msg ) ;
dev_dbg ( rtk - > dev , " RTKit: AP power state transition: 0x%x -> 0x%x \n " ,
rtk - > ap_power_state , new_state ) ;
rtk - > ap_power_state = new_state ;
complete_all ( & rtk - > ap_pwr_ack_completion ) ;
}
static void apple_rtkit_management_rx ( struct apple_rtkit * rtk , u64 msg )
{
u8 type = FIELD_GET ( APPLE_RTKIT_MGMT_TYPE , msg ) ;
switch ( type ) {
case APPLE_RTKIT_MGMT_HELLO :
apple_rtkit_management_rx_hello ( rtk , msg ) ;
break ;
case APPLE_RTKIT_MGMT_EPMAP :
apple_rtkit_management_rx_epmap ( rtk , msg ) ;
break ;
case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK :
apple_rtkit_management_rx_iop_pwr_ack ( rtk , msg ) ;
break ;
case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK :
apple_rtkit_management_rx_ap_pwr_ack ( rtk , msg ) ;
break ;
default :
dev_warn (
rtk - > dev ,
" RTKit: unknown management message: 0x%llx (type: 0x%02x) \n " ,
msg , type ) ;
}
}
static int apple_rtkit_common_rx_get_buffer ( struct apple_rtkit * rtk ,
struct apple_rtkit_shmem * buffer ,
u8 ep , u64 msg )
{
size_t n_4kpages = FIELD_GET ( APPLE_RTKIT_BUFFER_REQUEST_SIZE , msg ) ;
u64 reply ;
int err ;
buffer - > buffer = NULL ;
buffer - > iomem = NULL ;
buffer - > is_mapped = false ;
buffer - > iova = FIELD_GET ( APPLE_RTKIT_BUFFER_REQUEST_IOVA , msg ) ;
buffer - > size = n_4kpages < < 12 ;
dev_dbg ( rtk - > dev , " RTKit: buffer request for 0x%zx bytes at %pad \n " ,
buffer - > size , & buffer - > iova ) ;
if ( buffer - > iova & &
( ! rtk - > ops - > shmem_setup | | ! rtk - > ops - > shmem_destroy ) ) {
err = - EINVAL ;
goto error ;
}
if ( rtk - > ops - > shmem_setup ) {
err = rtk - > ops - > shmem_setup ( rtk - > cookie , buffer ) ;
if ( err )
goto error ;
} else {
buffer - > buffer = dma_alloc_coherent ( rtk - > dev , buffer - > size ,
& buffer - > iova , GFP_KERNEL ) ;
if ( ! buffer - > buffer ) {
err = - ENOMEM ;
goto error ;
}
}
if ( ! buffer - > is_mapped ) {
reply = FIELD_PREP ( APPLE_RTKIT_SYSLOG_TYPE ,
APPLE_RTKIT_BUFFER_REQUEST ) ;
reply | = FIELD_PREP ( APPLE_RTKIT_BUFFER_REQUEST_SIZE , n_4kpages ) ;
reply | = FIELD_PREP ( APPLE_RTKIT_BUFFER_REQUEST_IOVA ,
buffer - > iova ) ;
apple_rtkit_send_message ( rtk , ep , reply , NULL , false ) ;
}
return 0 ;
error :
buffer - > buffer = NULL ;
buffer - > iomem = NULL ;
buffer - > iova = 0 ;
buffer - > size = 0 ;
buffer - > is_mapped = false ;
return err ;
}
static void apple_rtkit_free_buffer ( struct apple_rtkit * rtk ,
struct apple_rtkit_shmem * bfr )
{
if ( bfr - > size = = 0 )
return ;
if ( rtk - > ops - > shmem_destroy )
rtk - > ops - > shmem_destroy ( rtk - > cookie , bfr ) ;
else if ( bfr - > buffer )
dma_free_coherent ( rtk - > dev , bfr - > size , bfr - > buffer , bfr - > iova ) ;
bfr - > buffer = NULL ;
bfr - > iomem = NULL ;
bfr - > iova = 0 ;
bfr - > size = 0 ;
bfr - > is_mapped = false ;
}
static void apple_rtkit_memcpy ( struct apple_rtkit * rtk , void * dst ,
struct apple_rtkit_shmem * bfr , size_t offset ,
size_t len )
{
if ( bfr - > iomem )
memcpy_fromio ( dst , bfr - > iomem + offset , len ) ;
else
memcpy ( dst , bfr - > buffer + offset , len ) ;
}
static void apple_rtkit_crashlog_rx ( struct apple_rtkit * rtk , u64 msg )
{
u8 type = FIELD_GET ( APPLE_RTKIT_SYSLOG_TYPE , msg ) ;
u8 * bfr ;
if ( type ! = APPLE_RTKIT_CRASHLOG_CRASH ) {
dev_warn ( rtk - > dev , " RTKit: Unknown crashlog message: %llx \n " ,
msg ) ;
return ;
}
if ( ! rtk - > crashlog_buffer . size ) {
apple_rtkit_common_rx_get_buffer ( rtk , & rtk - > crashlog_buffer ,
APPLE_RTKIT_EP_CRASHLOG , msg ) ;
return ;
}
dev_err ( rtk - > dev , " RTKit: co-processor has crashed \n " ) ;
/*
* create a shadow copy here to make sure the co - processor isn ' t able
* to change the log while we ' re dumping it . this also ensures
* the buffer is in normal memory and not iomem for e . g . the SMC
*/
bfr = kzalloc ( rtk - > crashlog_buffer . size , GFP_KERNEL ) ;
if ( bfr ) {
apple_rtkit_memcpy ( rtk , bfr , & rtk - > crashlog_buffer , 0 ,
rtk - > crashlog_buffer . size ) ;
apple_rtkit_crashlog_dump ( rtk , bfr , rtk - > crashlog_buffer . size ) ;
kfree ( bfr ) ;
} else {
dev_err ( rtk - > dev ,
" RTKit: Couldn't allocate crashlog shadow buffer \n " ) ;
}
rtk - > crashed = true ;
if ( rtk - > ops - > crashed )
rtk - > ops - > crashed ( rtk - > cookie ) ;
}
static void apple_rtkit_ioreport_rx ( struct apple_rtkit * rtk , u64 msg )
{
u8 type = FIELD_GET ( APPLE_RTKIT_SYSLOG_TYPE , msg ) ;
switch ( type ) {
case APPLE_RTKIT_BUFFER_REQUEST :
apple_rtkit_common_rx_get_buffer ( rtk , & rtk - > ioreport_buffer ,
APPLE_RTKIT_EP_IOREPORT , msg ) ;
break ;
/* unknown, must be ACKed or the co-processor will hang */
case 0x8 :
case 0xc :
apple_rtkit_send_message ( rtk , APPLE_RTKIT_EP_IOREPORT , msg ,
NULL , false ) ;
break ;
default :
dev_warn ( rtk - > dev , " RTKit: Unknown ioreport message: %llx \n " ,
msg ) ;
}
}
static void apple_rtkit_syslog_rx_init ( struct apple_rtkit * rtk , u64 msg )
{
rtk - > syslog_n_entries = FIELD_GET ( APPLE_RTKIT_SYSLOG_N_ENTRIES , msg ) ;
rtk - > syslog_msg_size = FIELD_GET ( APPLE_RTKIT_SYSLOG_MSG_SIZE , msg ) ;
rtk - > syslog_msg_buffer = kzalloc ( rtk - > syslog_msg_size , GFP_KERNEL ) ;
dev_dbg ( rtk - > dev ,
" RTKit: syslog initialized: entries: %zd, msg_size: %zd \n " ,
rtk - > syslog_n_entries , rtk - > syslog_msg_size ) ;
}
2023-02-24 17:21:59 +01:00
static bool should_crop_syslog_char ( char c )
{
return c = = ' \n ' | | c = = ' \r ' | | c = = ' ' | | c = = ' \0 ' ;
}
2022-05-01 16:55:06 +02:00
static void apple_rtkit_syslog_rx_log ( struct apple_rtkit * rtk , u64 msg )
{
u8 idx = msg & 0xff ;
char log_context [ 24 ] ;
size_t entry_size = 0x20 + rtk - > syslog_msg_size ;
2023-02-24 17:21:59 +01:00
int msglen ;
2022-05-01 16:55:06 +02:00
if ( ! rtk - > syslog_msg_buffer ) {
dev_warn (
rtk - > dev ,
" RTKit: received syslog message but no syslog_msg_buffer \n " ) ;
goto done ;
}
if ( ! rtk - > syslog_buffer . size ) {
dev_warn (
rtk - > dev ,
" RTKit: received syslog message but syslog_buffer.size is zero \n " ) ;
goto done ;
}
if ( ! rtk - > syslog_buffer . buffer & & ! rtk - > syslog_buffer . iomem ) {
dev_warn (
rtk - > dev ,
" RTKit: received syslog message but no syslog_buffer.buffer or syslog_buffer.iomem \n " ) ;
goto done ;
}
if ( idx > rtk - > syslog_n_entries ) {
dev_warn ( rtk - > dev , " RTKit: syslog index %d out of range \n " ,
idx ) ;
goto done ;
}
apple_rtkit_memcpy ( rtk , log_context , & rtk - > syslog_buffer ,
idx * entry_size + 8 , sizeof ( log_context ) ) ;
apple_rtkit_memcpy ( rtk , rtk - > syslog_msg_buffer , & rtk - > syslog_buffer ,
idx * entry_size + 8 + sizeof ( log_context ) ,
rtk - > syslog_msg_size ) ;
log_context [ sizeof ( log_context ) - 1 ] = 0 ;
2023-02-24 17:21:59 +01:00
msglen = rtk - > syslog_msg_size - 1 ;
while ( msglen > 0 & &
should_crop_syslog_char ( rtk - > syslog_msg_buffer [ msglen - 1 ] ) )
msglen - - ;
rtk - > syslog_msg_buffer [ msglen ] = 0 ;
2022-05-01 16:55:06 +02:00
dev_info ( rtk - > dev , " RTKit: syslog message: %s: %s \n " , log_context ,
rtk - > syslog_msg_buffer ) ;
done :
apple_rtkit_send_message ( rtk , APPLE_RTKIT_EP_SYSLOG , msg , NULL , false ) ;
}
static void apple_rtkit_syslog_rx ( struct apple_rtkit * rtk , u64 msg )
{
u8 type = FIELD_GET ( APPLE_RTKIT_SYSLOG_TYPE , msg ) ;
switch ( type ) {
case APPLE_RTKIT_BUFFER_REQUEST :
apple_rtkit_common_rx_get_buffer ( rtk , & rtk - > syslog_buffer ,
APPLE_RTKIT_EP_SYSLOG , msg ) ;
break ;
case APPLE_RTKIT_SYSLOG_INIT :
apple_rtkit_syslog_rx_init ( rtk , msg ) ;
break ;
case APPLE_RTKIT_SYSLOG_LOG :
apple_rtkit_syslog_rx_log ( rtk , msg ) ;
break ;
default :
dev_warn ( rtk - > dev , " RTKit: Unknown syslog message: %llx \n " ,
msg ) ;
}
}
static void apple_rtkit_oslog_rx_init ( struct apple_rtkit * rtk , u64 msg )
{
u64 ack ;
dev_dbg ( rtk - > dev , " RTKit: oslog init: msg: 0x%llx \n " , msg ) ;
ack = FIELD_PREP ( APPLE_RTKIT_OSLOG_TYPE , APPLE_RTKIT_OSLOG_ACK ) ;
apple_rtkit_send_message ( rtk , APPLE_RTKIT_EP_OSLOG , ack , NULL , false ) ;
}
static void apple_rtkit_oslog_rx ( struct apple_rtkit * rtk , u64 msg )
{
u8 type = FIELD_GET ( APPLE_RTKIT_OSLOG_TYPE , msg ) ;
switch ( type ) {
case APPLE_RTKIT_OSLOG_INIT :
apple_rtkit_oslog_rx_init ( rtk , msg ) ;
break ;
default :
dev_warn ( rtk - > dev , " RTKit: Unknown oslog message: %llx \n " , msg ) ;
}
}
static void apple_rtkit_rx_work ( struct work_struct * work )
{
struct apple_rtkit_rx_work * rtk_work =
container_of ( work , struct apple_rtkit_rx_work , work ) ;
struct apple_rtkit * rtk = rtk_work - > rtk ;
switch ( rtk_work - > ep ) {
case APPLE_RTKIT_EP_MGMT :
apple_rtkit_management_rx ( rtk , rtk_work - > msg ) ;
break ;
case APPLE_RTKIT_EP_CRASHLOG :
apple_rtkit_crashlog_rx ( rtk , rtk_work - > msg ) ;
break ;
case APPLE_RTKIT_EP_SYSLOG :
apple_rtkit_syslog_rx ( rtk , rtk_work - > msg ) ;
break ;
case APPLE_RTKIT_EP_IOREPORT :
apple_rtkit_ioreport_rx ( rtk , rtk_work - > msg ) ;
break ;
case APPLE_RTKIT_EP_OSLOG :
apple_rtkit_oslog_rx ( rtk , rtk_work - > msg ) ;
break ;
case APPLE_RTKIT_APP_ENDPOINT_START . . . 0xff :
if ( rtk - > ops - > recv_message )
rtk - > ops - > recv_message ( rtk - > cookie , rtk_work - > ep ,
rtk_work - > msg ) ;
else
dev_warn (
rtk - > dev ,
" Received unexpected message to EP%02d: %llx \n " ,
rtk_work - > ep , rtk_work - > msg ) ;
break ;
default :
dev_warn ( rtk - > dev ,
" RTKit: message to unknown endpoint %02x: %llx \n " ,
rtk_work - > ep , rtk_work - > msg ) ;
}
kfree ( rtk_work ) ;
}
static void apple_rtkit_rx ( struct mbox_client * cl , void * mssg )
{
struct apple_rtkit * rtk = container_of ( cl , struct apple_rtkit , mbox_cl ) ;
struct apple_mbox_msg * msg = mssg ;
struct apple_rtkit_rx_work * work ;
u8 ep = msg - > msg1 ;
/*
* The message was read from a MMIO FIFO and we have to make
* sure all reads from buffers sent with that message happen
* afterwards .
*/
dma_rmb ( ) ;
if ( ! test_bit ( ep , rtk - > endpoints ) )
dev_warn ( rtk - > dev ,
" RTKit: Message to undiscovered endpoint 0x%02x \n " ,
ep ) ;
if ( ep > = APPLE_RTKIT_APP_ENDPOINT_START & &
rtk - > ops - > recv_message_early & &
rtk - > ops - > recv_message_early ( rtk - > cookie , ep , msg - > msg0 ) )
return ;
work = kzalloc ( sizeof ( * work ) , GFP_ATOMIC ) ;
if ( ! work )
return ;
work - > rtk = rtk ;
work - > ep = ep ;
work - > msg = msg - > msg0 ;
INIT_WORK ( & work - > work , apple_rtkit_rx_work ) ;
queue_work ( rtk - > wq , & work - > work ) ;
}
static void apple_rtkit_tx_done ( struct mbox_client * cl , void * mssg , int r )
{
struct apple_rtkit_msg * msg =
container_of ( mssg , struct apple_rtkit_msg , mbox_msg ) ;
if ( r = = - ETIME )
return ;
if ( msg - > completion )
complete ( msg - > completion ) ;
kfree ( msg ) ;
}
int apple_rtkit_send_message ( struct apple_rtkit * rtk , u8 ep , u64 message ,
struct completion * completion , bool atomic )
{
struct apple_rtkit_msg * msg ;
int ret ;
gfp_t flags ;
if ( rtk - > crashed )
return - EINVAL ;
if ( ep > = APPLE_RTKIT_APP_ENDPOINT_START & &
! apple_rtkit_is_running ( rtk ) )
return - EINVAL ;
if ( atomic )
flags = GFP_ATOMIC ;
else
flags = GFP_KERNEL ;
msg = kzalloc ( sizeof ( * msg ) , flags ) ;
if ( ! msg )
return - ENOMEM ;
msg - > mbox_msg . msg0 = message ;
msg - > mbox_msg . msg1 = ep ;
msg - > completion = completion ;
/*
* The message will be sent with a MMIO write . We need the barrier
* here to ensure any previous writes to buffers are visible to the
* device before that MMIO write happens .
*/
dma_wmb ( ) ;
ret = mbox_send_message ( rtk - > mbox_chan , & msg - > mbox_msg ) ;
if ( ret < 0 ) {
kfree ( msg ) ;
return ret ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_send_message ) ;
int apple_rtkit_send_message_wait ( struct apple_rtkit * rtk , u8 ep , u64 message ,
unsigned long timeout , bool atomic )
{
DECLARE_COMPLETION_ONSTACK ( completion ) ;
int ret ;
long t ;
ret = apple_rtkit_send_message ( rtk , ep , message , & completion , atomic ) ;
if ( ret < 0 )
return ret ;
if ( atomic ) {
ret = mbox_flush ( rtk - > mbox_chan , timeout ) ;
if ( ret < 0 )
return ret ;
if ( try_wait_for_completion ( & completion ) )
return 0 ;
return - ETIME ;
} else {
t = wait_for_completion_interruptible_timeout (
& completion , msecs_to_jiffies ( timeout ) ) ;
if ( t < 0 )
return t ;
else if ( t = = 0 )
return - ETIME ;
return 0 ;
}
}
EXPORT_SYMBOL_GPL ( apple_rtkit_send_message_wait ) ;
2022-09-14 09:34:31 +01:00
int apple_rtkit_poll ( struct apple_rtkit * rtk )
{
return mbox_client_peek_data ( rtk - > mbox_chan ) ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_poll ) ;
2022-05-01 16:55:06 +02:00
int apple_rtkit_start_ep ( struct apple_rtkit * rtk , u8 endpoint )
{
u64 msg ;
if ( ! test_bit ( endpoint , rtk - > endpoints ) )
return - EINVAL ;
if ( endpoint > = APPLE_RTKIT_APP_ENDPOINT_START & &
! apple_rtkit_is_running ( rtk ) )
return - EINVAL ;
msg = FIELD_PREP ( APPLE_RTKIT_MGMT_STARTEP_EP , endpoint ) ;
msg | = APPLE_RTKIT_MGMT_STARTEP_FLAG ;
apple_rtkit_management_send ( rtk , APPLE_RTKIT_MGMT_STARTEP , msg ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_start_ep ) ;
static int apple_rtkit_request_mbox_chan ( struct apple_rtkit * rtk )
{
if ( rtk - > mbox_name )
rtk - > mbox_chan = mbox_request_channel_byname ( & rtk - > mbox_cl ,
rtk - > mbox_name ) ;
else
rtk - > mbox_chan =
mbox_request_channel ( & rtk - > mbox_cl , rtk - > mbox_idx ) ;
if ( IS_ERR ( rtk - > mbox_chan ) )
return PTR_ERR ( rtk - > mbox_chan ) ;
return 0 ;
}
2023-01-21 16:41:35 +09:00
struct apple_rtkit * apple_rtkit_init ( struct device * dev , void * cookie ,
2022-05-01 16:55:06 +02:00
const char * mbox_name , int mbox_idx ,
const struct apple_rtkit_ops * ops )
{
struct apple_rtkit * rtk ;
int ret ;
if ( ! ops )
return ERR_PTR ( - EINVAL ) ;
rtk = kzalloc ( sizeof ( * rtk ) , GFP_KERNEL ) ;
if ( ! rtk )
return ERR_PTR ( - ENOMEM ) ;
rtk - > dev = dev ;
rtk - > cookie = cookie ;
rtk - > ops = ops ;
init_completion ( & rtk - > epmap_completion ) ;
init_completion ( & rtk - > iop_pwr_ack_completion ) ;
init_completion ( & rtk - > ap_pwr_ack_completion ) ;
bitmap_zero ( rtk - > endpoints , APPLE_RTKIT_MAX_ENDPOINTS ) ;
set_bit ( APPLE_RTKIT_EP_MGMT , rtk - > endpoints ) ;
rtk - > mbox_name = mbox_name ;
rtk - > mbox_idx = mbox_idx ;
rtk - > mbox_cl . dev = dev ;
rtk - > mbox_cl . tx_block = false ;
rtk - > mbox_cl . knows_txdone = false ;
rtk - > mbox_cl . rx_callback = & apple_rtkit_rx ;
rtk - > mbox_cl . tx_done = & apple_rtkit_tx_done ;
rtk - > wq = alloc_ordered_workqueue ( " rtkit-%s " , WQ_MEM_RECLAIM ,
dev_name ( rtk - > dev ) ) ;
if ( ! rtk - > wq ) {
ret = - ENOMEM ;
goto free_rtk ;
}
ret = apple_rtkit_request_mbox_chan ( rtk ) ;
if ( ret )
goto destroy_wq ;
return rtk ;
destroy_wq :
destroy_workqueue ( rtk - > wq ) ;
free_rtk :
kfree ( rtk ) ;
return ERR_PTR ( ret ) ;
}
2023-01-21 16:41:35 +09:00
EXPORT_SYMBOL_GPL ( apple_rtkit_init ) ;
2022-05-01 16:55:06 +02:00
static int apple_rtkit_wait_for_completion ( struct completion * c )
{
long t ;
t = wait_for_completion_interruptible_timeout ( c ,
msecs_to_jiffies ( 1000 ) ) ;
if ( t < 0 )
return t ;
else if ( t = = 0 )
return - ETIME ;
else
return 0 ;
}
int apple_rtkit_reinit ( struct apple_rtkit * rtk )
{
/* make sure we don't handle any messages while reinitializing */
mbox_free_channel ( rtk - > mbox_chan ) ;
flush_workqueue ( rtk - > wq ) ;
apple_rtkit_free_buffer ( rtk , & rtk - > ioreport_buffer ) ;
apple_rtkit_free_buffer ( rtk , & rtk - > crashlog_buffer ) ;
apple_rtkit_free_buffer ( rtk , & rtk - > syslog_buffer ) ;
kfree ( rtk - > syslog_msg_buffer ) ;
rtk - > syslog_msg_buffer = NULL ;
rtk - > syslog_n_entries = 0 ;
rtk - > syslog_msg_size = 0 ;
bitmap_zero ( rtk - > endpoints , APPLE_RTKIT_MAX_ENDPOINTS ) ;
set_bit ( APPLE_RTKIT_EP_MGMT , rtk - > endpoints ) ;
reinit_completion ( & rtk - > epmap_completion ) ;
reinit_completion ( & rtk - > iop_pwr_ack_completion ) ;
reinit_completion ( & rtk - > ap_pwr_ack_completion ) ;
rtk - > crashed = false ;
rtk - > iop_power_state = APPLE_RTKIT_PWR_STATE_OFF ;
rtk - > ap_power_state = APPLE_RTKIT_PWR_STATE_OFF ;
return apple_rtkit_request_mbox_chan ( rtk ) ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_reinit ) ;
static int apple_rtkit_set_ap_power_state ( struct apple_rtkit * rtk ,
unsigned int state )
{
u64 msg ;
int ret ;
reinit_completion ( & rtk - > ap_pwr_ack_completion ) ;
msg = FIELD_PREP ( APPLE_RTKIT_MGMT_PWR_STATE , state ) ;
apple_rtkit_management_send ( rtk , APPLE_RTKIT_MGMT_SET_AP_PWR_STATE ,
msg ) ;
ret = apple_rtkit_wait_for_completion ( & rtk - > ap_pwr_ack_completion ) ;
if ( ret )
return ret ;
if ( rtk - > ap_power_state ! = state )
return - EINVAL ;
return 0 ;
}
static int apple_rtkit_set_iop_power_state ( struct apple_rtkit * rtk ,
unsigned int state )
{
u64 msg ;
int ret ;
reinit_completion ( & rtk - > iop_pwr_ack_completion ) ;
msg = FIELD_PREP ( APPLE_RTKIT_MGMT_PWR_STATE , state ) ;
apple_rtkit_management_send ( rtk , APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE ,
msg ) ;
ret = apple_rtkit_wait_for_completion ( & rtk - > iop_pwr_ack_completion ) ;
if ( ret )
return ret ;
if ( rtk - > iop_power_state ! = state )
return - EINVAL ;
return 0 ;
}
int apple_rtkit_boot ( struct apple_rtkit * rtk )
{
int ret ;
if ( apple_rtkit_is_running ( rtk ) )
return 0 ;
if ( rtk - > crashed )
return - EINVAL ;
dev_dbg ( rtk - > dev , " RTKit: waiting for boot to finish \n " ) ;
ret = apple_rtkit_wait_for_completion ( & rtk - > epmap_completion ) ;
if ( ret )
return ret ;
if ( rtk - > boot_result )
return rtk - > boot_result ;
dev_dbg ( rtk - > dev , " RTKit: waiting for IOP power state ACK \n " ) ;
ret = apple_rtkit_wait_for_completion ( & rtk - > iop_pwr_ack_completion ) ;
if ( ret )
return ret ;
return apple_rtkit_set_ap_power_state ( rtk , APPLE_RTKIT_PWR_STATE_ON ) ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_boot ) ;
int apple_rtkit_shutdown ( struct apple_rtkit * rtk )
{
int ret ;
/* if OFF is used here the co-processor will not wake up again */
ret = apple_rtkit_set_ap_power_state ( rtk ,
APPLE_RTKIT_PWR_STATE_QUIESCED ) ;
if ( ret )
return ret ;
ret = apple_rtkit_set_iop_power_state ( rtk , APPLE_RTKIT_PWR_STATE_SLEEP ) ;
if ( ret )
return ret ;
return apple_rtkit_reinit ( rtk ) ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_shutdown ) ;
2023-01-23 15:53:54 +09:00
int apple_rtkit_idle ( struct apple_rtkit * rtk )
{
int ret ;
/* if OFF is used here the co-processor will not wake up again */
ret = apple_rtkit_set_ap_power_state ( rtk ,
APPLE_RTKIT_PWR_STATE_IDLE ) ;
if ( ret )
return ret ;
ret = apple_rtkit_set_iop_power_state ( rtk , APPLE_RTKIT_PWR_STATE_IDLE ) ;
if ( ret )
return ret ;
rtk - > iop_power_state = APPLE_RTKIT_PWR_STATE_IDLE ;
rtk - > ap_power_state = APPLE_RTKIT_PWR_STATE_IDLE ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_idle ) ;
2022-05-01 16:55:06 +02:00
int apple_rtkit_quiesce ( struct apple_rtkit * rtk )
{
int ret ;
ret = apple_rtkit_set_ap_power_state ( rtk ,
APPLE_RTKIT_PWR_STATE_QUIESCED ) ;
if ( ret )
return ret ;
ret = apple_rtkit_set_iop_power_state ( rtk ,
APPLE_RTKIT_PWR_STATE_QUIESCED ) ;
if ( ret )
return ret ;
ret = apple_rtkit_reinit ( rtk ) ;
if ( ret )
return ret ;
rtk - > iop_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED ;
rtk - > ap_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_quiesce ) ;
int apple_rtkit_wake ( struct apple_rtkit * rtk )
{
u64 msg ;
if ( apple_rtkit_is_running ( rtk ) )
return - EINVAL ;
reinit_completion ( & rtk - > iop_pwr_ack_completion ) ;
/*
* Use open - coded apple_rtkit_set_iop_power_state since apple_rtkit_boot
* will wait for the completion anyway .
*/
msg = FIELD_PREP ( APPLE_RTKIT_MGMT_PWR_STATE , APPLE_RTKIT_PWR_STATE_ON ) ;
apple_rtkit_management_send ( rtk , APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE ,
msg ) ;
return apple_rtkit_boot ( rtk ) ;
}
EXPORT_SYMBOL_GPL ( apple_rtkit_wake ) ;
2023-01-21 16:41:35 +09:00
void apple_rtkit_free ( struct apple_rtkit * rtk )
2022-05-01 16:55:06 +02:00
{
mbox_free_channel ( rtk - > mbox_chan ) ;
destroy_workqueue ( rtk - > wq ) ;
apple_rtkit_free_buffer ( rtk , & rtk - > ioreport_buffer ) ;
apple_rtkit_free_buffer ( rtk , & rtk - > crashlog_buffer ) ;
apple_rtkit_free_buffer ( rtk , & rtk - > syslog_buffer ) ;
kfree ( rtk - > syslog_msg_buffer ) ;
kfree ( rtk ) ;
}
2023-01-21 16:41:35 +09:00
EXPORT_SYMBOL_GPL ( apple_rtkit_free ) ;
static void apple_rtkit_free_wrapper ( void * data )
{
apple_rtkit_free ( data ) ;
}
2022-05-01 16:55:06 +02:00
struct apple_rtkit * devm_apple_rtkit_init ( struct device * dev , void * cookie ,
const char * mbox_name , int mbox_idx ,
const struct apple_rtkit_ops * ops )
{
struct apple_rtkit * rtk ;
int ret ;
rtk = apple_rtkit_init ( dev , cookie , mbox_name , mbox_idx , ops ) ;
if ( IS_ERR ( rtk ) )
return rtk ;
2023-01-21 16:41:35 +09:00
ret = devm_add_action_or_reset ( dev , apple_rtkit_free_wrapper , rtk ) ;
2022-05-01 16:55:06 +02:00
if ( ret )
return ERR_PTR ( ret ) ;
return rtk ;
}
EXPORT_SYMBOL_GPL ( devm_apple_rtkit_init ) ;
MODULE_LICENSE ( " Dual MIT/GPL " ) ;
MODULE_AUTHOR ( " Sven Peter <sven@svenpeter.dev> " ) ;
MODULE_DESCRIPTION ( " Apple RTKit driver " ) ;