162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only OR MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Apple RTKit IPC library 462306a36Sopenharmony_ci * Copyright (C) The Asahi Linux Contributors 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "rtkit-internal.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_cienum { 1062306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */ 1162306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */ 1262306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */ 1362306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */ 1462306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */ 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cienum { 1862306a36Sopenharmony_ci APPLE_RTKIT_EP_MGMT = 0, 1962306a36Sopenharmony_ci APPLE_RTKIT_EP_CRASHLOG = 1, 2062306a36Sopenharmony_ci APPLE_RTKIT_EP_SYSLOG = 2, 2162306a36Sopenharmony_ci APPLE_RTKIT_EP_DEBUG = 3, 2262306a36Sopenharmony_ci APPLE_RTKIT_EP_IOREPORT = 4, 2362306a36Sopenharmony_ci APPLE_RTKIT_EP_OSLOG = 8, 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_TYPE GENMASK_ULL(59, 52) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cienum { 2962306a36Sopenharmony_ci APPLE_RTKIT_MGMT_HELLO = 1, 3062306a36Sopenharmony_ci APPLE_RTKIT_MGMT_HELLO_REPLY = 2, 3162306a36Sopenharmony_ci APPLE_RTKIT_MGMT_STARTEP = 5, 3262306a36Sopenharmony_ci APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE = 6, 3362306a36Sopenharmony_ci APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK = 7, 3462306a36Sopenharmony_ci APPLE_RTKIT_MGMT_EPMAP = 8, 3562306a36Sopenharmony_ci APPLE_RTKIT_MGMT_EPMAP_REPLY = 8, 3662306a36Sopenharmony_ci APPLE_RTKIT_MGMT_SET_AP_PWR_STATE = 0xb, 3762306a36Sopenharmony_ci APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK = 0xb, 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK_ULL(15, 0) 4162306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK_ULL(31, 16) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT_ULL(51) 4462306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK_ULL(34, 32) 4562306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK_ULL(31, 0) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT_ULL(0) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK_ULL(39, 32) 5062306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT_ULL(1) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define APPLE_RTKIT_MGMT_PWR_STATE GENMASK_ULL(15, 0) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define APPLE_RTKIT_CRASHLOG_CRASH 1 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define APPLE_RTKIT_BUFFER_REQUEST 1 5762306a36Sopenharmony_ci#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44) 5862306a36Sopenharmony_ci#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define APPLE_RTKIT_SYSLOG_LOG 5 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define APPLE_RTKIT_SYSLOG_INIT 8 6562306a36Sopenharmony_ci#define APPLE_RTKIT_SYSLOG_N_ENTRIES GENMASK_ULL(7, 0) 6662306a36Sopenharmony_ci#define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56) 6962306a36Sopenharmony_ci#define APPLE_RTKIT_OSLOG_INIT 1 7062306a36Sopenharmony_ci#define APPLE_RTKIT_OSLOG_ACK 3 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 7362306a36Sopenharmony_ci#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistruct apple_rtkit_msg { 7662306a36Sopenharmony_ci struct completion *completion; 7762306a36Sopenharmony_ci struct apple_mbox_msg mbox_msg; 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct apple_rtkit_rx_work { 8162306a36Sopenharmony_ci struct apple_rtkit *rtk; 8262306a36Sopenharmony_ci u8 ep; 8362306a36Sopenharmony_ci u64 msg; 8462306a36Sopenharmony_ci struct work_struct work; 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cibool apple_rtkit_is_running(struct apple_rtkit *rtk) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci if (rtk->crashed) 9062306a36Sopenharmony_ci return false; 9162306a36Sopenharmony_ci if ((rtk->iop_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) 9262306a36Sopenharmony_ci return false; 9362306a36Sopenharmony_ci if ((rtk->ap_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) 9462306a36Sopenharmony_ci return false; 9562306a36Sopenharmony_ci return true; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_is_running); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cibool apple_rtkit_is_crashed(struct apple_rtkit *rtk) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return rtk->crashed; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_is_crashed); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void apple_rtkit_management_send(struct apple_rtkit *rtk, u8 type, 10662306a36Sopenharmony_ci u64 msg) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci msg &= ~APPLE_RTKIT_MGMT_TYPE; 10962306a36Sopenharmony_ci msg |= FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, type); 11062306a36Sopenharmony_ci apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_MGMT, msg, NULL, false); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci u64 reply; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci int min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg); 11862306a36Sopenharmony_ci int max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg); 11962306a36Sopenharmony_ci int want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: Min ver %d, max ver %d\n", min_ver, max_ver); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) { 12462306a36Sopenharmony_ci dev_err(rtk->dev, "RTKit: Firmware min version %d is too new\n", 12562306a36Sopenharmony_ci min_ver); 12662306a36Sopenharmony_ci goto abort_boot; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) { 13062306a36Sopenharmony_ci dev_err(rtk->dev, "RTKit: Firmware max version %d is too old\n", 13162306a36Sopenharmony_ci max_ver); 13262306a36Sopenharmony_ci goto abort_boot; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci dev_info(rtk->dev, "RTKit: Initializing (protocol version %d)\n", 13662306a36Sopenharmony_ci want_ver); 13762306a36Sopenharmony_ci rtk->version = want_ver; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci reply = FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver); 14062306a36Sopenharmony_ci reply |= FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver); 14162306a36Sopenharmony_ci apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_HELLO_REPLY, reply); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ciabort_boot: 14662306a36Sopenharmony_ci rtk->boot_result = -EINVAL; 14762306a36Sopenharmony_ci complete_all(&rtk->epmap_completion); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void apple_rtkit_management_rx_epmap(struct apple_rtkit *rtk, u64 msg) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci int i, ep; 15362306a36Sopenharmony_ci u64 reply; 15462306a36Sopenharmony_ci unsigned long bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg); 15562306a36Sopenharmony_ci u32 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci dev_dbg(rtk->dev, 15862306a36Sopenharmony_ci "RTKit: received endpoint bitmap 0x%lx with base 0x%x\n", 15962306a36Sopenharmony_ci bitmap, base); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci for_each_set_bit(i, &bitmap, 32) { 16262306a36Sopenharmony_ci ep = 32 * base + i; 16362306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: Discovered endpoint 0x%02x\n", ep); 16462306a36Sopenharmony_ci set_bit(ep, rtk->endpoints); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci reply = FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base); 16862306a36Sopenharmony_ci if (msg & APPLE_RTKIT_MGMT_EPMAP_LAST) 16962306a36Sopenharmony_ci reply |= APPLE_RTKIT_MGMT_EPMAP_LAST; 17062306a36Sopenharmony_ci else 17162306a36Sopenharmony_ci reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_EPMAP_REPLY, reply); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!(msg & APPLE_RTKIT_MGMT_EPMAP_LAST)) 17662306a36Sopenharmony_ci return; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci for_each_set_bit(ep, rtk->endpoints, APPLE_RTKIT_APP_ENDPOINT_START) { 17962306a36Sopenharmony_ci switch (ep) { 18062306a36Sopenharmony_ci /* the management endpoint is started by default */ 18162306a36Sopenharmony_ci case APPLE_RTKIT_EP_MGMT: 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* without starting these RTKit refuses to boot */ 18562306a36Sopenharmony_ci case APPLE_RTKIT_EP_SYSLOG: 18662306a36Sopenharmony_ci case APPLE_RTKIT_EP_CRASHLOG: 18762306a36Sopenharmony_ci case APPLE_RTKIT_EP_DEBUG: 18862306a36Sopenharmony_ci case APPLE_RTKIT_EP_IOREPORT: 18962306a36Sopenharmony_ci case APPLE_RTKIT_EP_OSLOG: 19062306a36Sopenharmony_ci dev_dbg(rtk->dev, 19162306a36Sopenharmony_ci "RTKit: Starting system endpoint 0x%02x\n", ep); 19262306a36Sopenharmony_ci apple_rtkit_start_ep(rtk, ep); 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci default: 19662306a36Sopenharmony_ci dev_warn(rtk->dev, 19762306a36Sopenharmony_ci "RTKit: Unknown system endpoint: 0x%02x\n", 19862306a36Sopenharmony_ci ep); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci rtk->boot_result = 0; 20362306a36Sopenharmony_ci complete_all(&rtk->epmap_completion); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void apple_rtkit_management_rx_iop_pwr_ack(struct apple_rtkit *rtk, 20762306a36Sopenharmony_ci u64 msg) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: IOP power state transition: 0x%x -> 0x%x\n", 21262306a36Sopenharmony_ci rtk->iop_power_state, new_state); 21362306a36Sopenharmony_ci rtk->iop_power_state = new_state; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci complete_all(&rtk->iop_pwr_ack_completion); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void apple_rtkit_management_rx_ap_pwr_ack(struct apple_rtkit *rtk, 21962306a36Sopenharmony_ci u64 msg) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: AP power state transition: 0x%x -> 0x%x\n", 22462306a36Sopenharmony_ci rtk->ap_power_state, new_state); 22562306a36Sopenharmony_ci rtk->ap_power_state = new_state; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci complete_all(&rtk->ap_pwr_ack_completion); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic void apple_rtkit_management_rx(struct apple_rtkit *rtk, u64 msg) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci u8 type = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci switch (type) { 23562306a36Sopenharmony_ci case APPLE_RTKIT_MGMT_HELLO: 23662306a36Sopenharmony_ci apple_rtkit_management_rx_hello(rtk, msg); 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci case APPLE_RTKIT_MGMT_EPMAP: 23962306a36Sopenharmony_ci apple_rtkit_management_rx_epmap(rtk, msg); 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK: 24262306a36Sopenharmony_ci apple_rtkit_management_rx_iop_pwr_ack(rtk, msg); 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK: 24562306a36Sopenharmony_ci apple_rtkit_management_rx_ap_pwr_ack(rtk, msg); 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci default: 24862306a36Sopenharmony_ci dev_warn( 24962306a36Sopenharmony_ci rtk->dev, 25062306a36Sopenharmony_ci "RTKit: unknown management message: 0x%llx (type: 0x%02x)\n", 25162306a36Sopenharmony_ci msg, type); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, 25662306a36Sopenharmony_ci struct apple_rtkit_shmem *buffer, 25762306a36Sopenharmony_ci u8 ep, u64 msg) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci size_t n_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg); 26062306a36Sopenharmony_ci u64 reply; 26162306a36Sopenharmony_ci int err; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci buffer->buffer = NULL; 26462306a36Sopenharmony_ci buffer->iomem = NULL; 26562306a36Sopenharmony_ci buffer->is_mapped = false; 26662306a36Sopenharmony_ci buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); 26762306a36Sopenharmony_ci buffer->size = n_4kpages << 12; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n", 27062306a36Sopenharmony_ci buffer->size, &buffer->iova); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (buffer->iova && 27362306a36Sopenharmony_ci (!rtk->ops->shmem_setup || !rtk->ops->shmem_destroy)) { 27462306a36Sopenharmony_ci err = -EINVAL; 27562306a36Sopenharmony_ci goto error; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (rtk->ops->shmem_setup) { 27962306a36Sopenharmony_ci err = rtk->ops->shmem_setup(rtk->cookie, buffer); 28062306a36Sopenharmony_ci if (err) 28162306a36Sopenharmony_ci goto error; 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci buffer->buffer = dma_alloc_coherent(rtk->dev, buffer->size, 28462306a36Sopenharmony_ci &buffer->iova, GFP_KERNEL); 28562306a36Sopenharmony_ci if (!buffer->buffer) { 28662306a36Sopenharmony_ci err = -ENOMEM; 28762306a36Sopenharmony_ci goto error; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (!buffer->is_mapped) { 29262306a36Sopenharmony_ci reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, 29362306a36Sopenharmony_ci APPLE_RTKIT_BUFFER_REQUEST); 29462306a36Sopenharmony_ci reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, n_4kpages); 29562306a36Sopenharmony_ci reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, 29662306a36Sopenharmony_ci buffer->iova); 29762306a36Sopenharmony_ci apple_rtkit_send_message(rtk, ep, reply, NULL, false); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cierror: 30362306a36Sopenharmony_ci buffer->buffer = NULL; 30462306a36Sopenharmony_ci buffer->iomem = NULL; 30562306a36Sopenharmony_ci buffer->iova = 0; 30662306a36Sopenharmony_ci buffer->size = 0; 30762306a36Sopenharmony_ci buffer->is_mapped = false; 30862306a36Sopenharmony_ci return err; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void apple_rtkit_free_buffer(struct apple_rtkit *rtk, 31262306a36Sopenharmony_ci struct apple_rtkit_shmem *bfr) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci if (bfr->size == 0) 31562306a36Sopenharmony_ci return; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (rtk->ops->shmem_destroy) 31862306a36Sopenharmony_ci rtk->ops->shmem_destroy(rtk->cookie, bfr); 31962306a36Sopenharmony_ci else if (bfr->buffer) 32062306a36Sopenharmony_ci dma_free_coherent(rtk->dev, bfr->size, bfr->buffer, bfr->iova); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci bfr->buffer = NULL; 32362306a36Sopenharmony_ci bfr->iomem = NULL; 32462306a36Sopenharmony_ci bfr->iova = 0; 32562306a36Sopenharmony_ci bfr->size = 0; 32662306a36Sopenharmony_ci bfr->is_mapped = false; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void apple_rtkit_memcpy(struct apple_rtkit *rtk, void *dst, 33062306a36Sopenharmony_ci struct apple_rtkit_shmem *bfr, size_t offset, 33162306a36Sopenharmony_ci size_t len) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci if (bfr->iomem) 33462306a36Sopenharmony_ci memcpy_fromio(dst, bfr->iomem + offset, len); 33562306a36Sopenharmony_ci else 33662306a36Sopenharmony_ci memcpy(dst, bfr->buffer + offset, len); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void apple_rtkit_crashlog_rx(struct apple_rtkit *rtk, u64 msg) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); 34262306a36Sopenharmony_ci u8 *bfr; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (type != APPLE_RTKIT_CRASHLOG_CRASH) { 34562306a36Sopenharmony_ci dev_warn(rtk->dev, "RTKit: Unknown crashlog message: %llx\n", 34662306a36Sopenharmony_ci msg); 34762306a36Sopenharmony_ci return; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (!rtk->crashlog_buffer.size) { 35162306a36Sopenharmony_ci apple_rtkit_common_rx_get_buffer(rtk, &rtk->crashlog_buffer, 35262306a36Sopenharmony_ci APPLE_RTKIT_EP_CRASHLOG, msg); 35362306a36Sopenharmony_ci return; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci dev_err(rtk->dev, "RTKit: co-processor has crashed\n"); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * create a shadow copy here to make sure the co-processor isn't able 36062306a36Sopenharmony_ci * to change the log while we're dumping it. this also ensures 36162306a36Sopenharmony_ci * the buffer is in normal memory and not iomem for e.g. the SMC 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci bfr = kzalloc(rtk->crashlog_buffer.size, GFP_KERNEL); 36462306a36Sopenharmony_ci if (bfr) { 36562306a36Sopenharmony_ci apple_rtkit_memcpy(rtk, bfr, &rtk->crashlog_buffer, 0, 36662306a36Sopenharmony_ci rtk->crashlog_buffer.size); 36762306a36Sopenharmony_ci apple_rtkit_crashlog_dump(rtk, bfr, rtk->crashlog_buffer.size); 36862306a36Sopenharmony_ci kfree(bfr); 36962306a36Sopenharmony_ci } else { 37062306a36Sopenharmony_ci dev_err(rtk->dev, 37162306a36Sopenharmony_ci "RTKit: Couldn't allocate crashlog shadow buffer\n"); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci rtk->crashed = true; 37562306a36Sopenharmony_ci if (rtk->ops->crashed) 37662306a36Sopenharmony_ci rtk->ops->crashed(rtk->cookie); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic void apple_rtkit_ioreport_rx(struct apple_rtkit *rtk, u64 msg) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci switch (type) { 38462306a36Sopenharmony_ci case APPLE_RTKIT_BUFFER_REQUEST: 38562306a36Sopenharmony_ci apple_rtkit_common_rx_get_buffer(rtk, &rtk->ioreport_buffer, 38662306a36Sopenharmony_ci APPLE_RTKIT_EP_IOREPORT, msg); 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci /* unknown, must be ACKed or the co-processor will hang */ 38962306a36Sopenharmony_ci case 0x8: 39062306a36Sopenharmony_ci case 0xc: 39162306a36Sopenharmony_ci apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_IOREPORT, msg, 39262306a36Sopenharmony_ci NULL, false); 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci default: 39562306a36Sopenharmony_ci dev_warn(rtk->dev, "RTKit: Unknown ioreport message: %llx\n", 39662306a36Sopenharmony_ci msg); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci rtk->syslog_n_entries = FIELD_GET(APPLE_RTKIT_SYSLOG_N_ENTRIES, msg); 40362306a36Sopenharmony_ci rtk->syslog_msg_size = FIELD_GET(APPLE_RTKIT_SYSLOG_MSG_SIZE, msg); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci rtk->syslog_msg_buffer = kzalloc(rtk->syslog_msg_size, GFP_KERNEL); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci dev_dbg(rtk->dev, 40862306a36Sopenharmony_ci "RTKit: syslog initialized: entries: %zd, msg_size: %zd\n", 40962306a36Sopenharmony_ci rtk->syslog_n_entries, rtk->syslog_msg_size); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic bool should_crop_syslog_char(char c) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci return c == '\n' || c == '\r' || c == ' ' || c == '\0'; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci u8 idx = msg & 0xff; 42062306a36Sopenharmony_ci char log_context[24]; 42162306a36Sopenharmony_ci size_t entry_size = 0x20 + rtk->syslog_msg_size; 42262306a36Sopenharmony_ci int msglen; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (!rtk->syslog_msg_buffer) { 42562306a36Sopenharmony_ci dev_warn( 42662306a36Sopenharmony_ci rtk->dev, 42762306a36Sopenharmony_ci "RTKit: received syslog message but no syslog_msg_buffer\n"); 42862306a36Sopenharmony_ci goto done; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci if (!rtk->syslog_buffer.size) { 43162306a36Sopenharmony_ci dev_warn( 43262306a36Sopenharmony_ci rtk->dev, 43362306a36Sopenharmony_ci "RTKit: received syslog message but syslog_buffer.size is zero\n"); 43462306a36Sopenharmony_ci goto done; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci if (!rtk->syslog_buffer.buffer && !rtk->syslog_buffer.iomem) { 43762306a36Sopenharmony_ci dev_warn( 43862306a36Sopenharmony_ci rtk->dev, 43962306a36Sopenharmony_ci "RTKit: received syslog message but no syslog_buffer.buffer or syslog_buffer.iomem\n"); 44062306a36Sopenharmony_ci goto done; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci if (idx > rtk->syslog_n_entries) { 44362306a36Sopenharmony_ci dev_warn(rtk->dev, "RTKit: syslog index %d out of range\n", 44462306a36Sopenharmony_ci idx); 44562306a36Sopenharmony_ci goto done; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci apple_rtkit_memcpy(rtk, log_context, &rtk->syslog_buffer, 44962306a36Sopenharmony_ci idx * entry_size + 8, sizeof(log_context)); 45062306a36Sopenharmony_ci apple_rtkit_memcpy(rtk, rtk->syslog_msg_buffer, &rtk->syslog_buffer, 45162306a36Sopenharmony_ci idx * entry_size + 8 + sizeof(log_context), 45262306a36Sopenharmony_ci rtk->syslog_msg_size); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci log_context[sizeof(log_context) - 1] = 0; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci msglen = rtk->syslog_msg_size - 1; 45762306a36Sopenharmony_ci while (msglen > 0 && 45862306a36Sopenharmony_ci should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1])) 45962306a36Sopenharmony_ci msglen--; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci rtk->syslog_msg_buffer[msglen] = 0; 46262306a36Sopenharmony_ci dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context, 46362306a36Sopenharmony_ci rtk->syslog_msg_buffer); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cidone: 46662306a36Sopenharmony_ci apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_SYSLOG, msg, NULL, false); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci switch (type) { 47462306a36Sopenharmony_ci case APPLE_RTKIT_BUFFER_REQUEST: 47562306a36Sopenharmony_ci apple_rtkit_common_rx_get_buffer(rtk, &rtk->syslog_buffer, 47662306a36Sopenharmony_ci APPLE_RTKIT_EP_SYSLOG, msg); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case APPLE_RTKIT_SYSLOG_INIT: 47962306a36Sopenharmony_ci apple_rtkit_syslog_rx_init(rtk, msg); 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci case APPLE_RTKIT_SYSLOG_LOG: 48262306a36Sopenharmony_ci apple_rtkit_syslog_rx_log(rtk, msg); 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci default: 48562306a36Sopenharmony_ci dev_warn(rtk->dev, "RTKit: Unknown syslog message: %llx\n", 48662306a36Sopenharmony_ci msg); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic void apple_rtkit_oslog_rx_init(struct apple_rtkit *rtk, u64 msg) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci u64 ack; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: oslog init: msg: 0x%llx\n", msg); 49562306a36Sopenharmony_ci ack = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_ACK); 49662306a36Sopenharmony_ci apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_OSLOG, ack, NULL, false); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void apple_rtkit_oslog_rx(struct apple_rtkit *rtk, u64 msg) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci u8 type = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci switch (type) { 50462306a36Sopenharmony_ci case APPLE_RTKIT_OSLOG_INIT: 50562306a36Sopenharmony_ci apple_rtkit_oslog_rx_init(rtk, msg); 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci default: 50862306a36Sopenharmony_ci dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", msg); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic void apple_rtkit_rx_work(struct work_struct *work) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct apple_rtkit_rx_work *rtk_work = 51562306a36Sopenharmony_ci container_of(work, struct apple_rtkit_rx_work, work); 51662306a36Sopenharmony_ci struct apple_rtkit *rtk = rtk_work->rtk; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci switch (rtk_work->ep) { 51962306a36Sopenharmony_ci case APPLE_RTKIT_EP_MGMT: 52062306a36Sopenharmony_ci apple_rtkit_management_rx(rtk, rtk_work->msg); 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci case APPLE_RTKIT_EP_CRASHLOG: 52362306a36Sopenharmony_ci apple_rtkit_crashlog_rx(rtk, rtk_work->msg); 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci case APPLE_RTKIT_EP_SYSLOG: 52662306a36Sopenharmony_ci apple_rtkit_syslog_rx(rtk, rtk_work->msg); 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci case APPLE_RTKIT_EP_IOREPORT: 52962306a36Sopenharmony_ci apple_rtkit_ioreport_rx(rtk, rtk_work->msg); 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci case APPLE_RTKIT_EP_OSLOG: 53262306a36Sopenharmony_ci apple_rtkit_oslog_rx(rtk, rtk_work->msg); 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci case APPLE_RTKIT_APP_ENDPOINT_START ... 0xff: 53562306a36Sopenharmony_ci if (rtk->ops->recv_message) 53662306a36Sopenharmony_ci rtk->ops->recv_message(rtk->cookie, rtk_work->ep, 53762306a36Sopenharmony_ci rtk_work->msg); 53862306a36Sopenharmony_ci else 53962306a36Sopenharmony_ci dev_warn( 54062306a36Sopenharmony_ci rtk->dev, 54162306a36Sopenharmony_ci "Received unexpected message to EP%02d: %llx\n", 54262306a36Sopenharmony_ci rtk_work->ep, rtk_work->msg); 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci default: 54562306a36Sopenharmony_ci dev_warn(rtk->dev, 54662306a36Sopenharmony_ci "RTKit: message to unknown endpoint %02x: %llx\n", 54762306a36Sopenharmony_ci rtk_work->ep, rtk_work->msg); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci kfree(rtk_work); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic void apple_rtkit_rx(struct mbox_client *cl, void *mssg) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct apple_rtkit *rtk = container_of(cl, struct apple_rtkit, mbox_cl); 55662306a36Sopenharmony_ci struct apple_mbox_msg *msg = mssg; 55762306a36Sopenharmony_ci struct apple_rtkit_rx_work *work; 55862306a36Sopenharmony_ci u8 ep = msg->msg1; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* 56162306a36Sopenharmony_ci * The message was read from a MMIO FIFO and we have to make 56262306a36Sopenharmony_ci * sure all reads from buffers sent with that message happen 56362306a36Sopenharmony_ci * afterwards. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci dma_rmb(); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (!test_bit(ep, rtk->endpoints)) 56862306a36Sopenharmony_ci dev_warn(rtk->dev, 56962306a36Sopenharmony_ci "RTKit: Message to undiscovered endpoint 0x%02x\n", 57062306a36Sopenharmony_ci ep); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (ep >= APPLE_RTKIT_APP_ENDPOINT_START && 57362306a36Sopenharmony_ci rtk->ops->recv_message_early && 57462306a36Sopenharmony_ci rtk->ops->recv_message_early(rtk->cookie, ep, msg->msg0)) 57562306a36Sopenharmony_ci return; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_ATOMIC); 57862306a36Sopenharmony_ci if (!work) 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci work->rtk = rtk; 58262306a36Sopenharmony_ci work->ep = ep; 58362306a36Sopenharmony_ci work->msg = msg->msg0; 58462306a36Sopenharmony_ci INIT_WORK(&work->work, apple_rtkit_rx_work); 58562306a36Sopenharmony_ci queue_work(rtk->wq, &work->work); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic void apple_rtkit_tx_done(struct mbox_client *cl, void *mssg, int r) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct apple_rtkit_msg *msg = 59162306a36Sopenharmony_ci container_of(mssg, struct apple_rtkit_msg, mbox_msg); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (r == -ETIME) 59462306a36Sopenharmony_ci return; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (msg->completion) 59762306a36Sopenharmony_ci complete(msg->completion); 59862306a36Sopenharmony_ci kfree(msg); 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciint apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, 60262306a36Sopenharmony_ci struct completion *completion, bool atomic) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct apple_rtkit_msg *msg; 60562306a36Sopenharmony_ci int ret; 60662306a36Sopenharmony_ci gfp_t flags; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (rtk->crashed) 60962306a36Sopenharmony_ci return -EINVAL; 61062306a36Sopenharmony_ci if (ep >= APPLE_RTKIT_APP_ENDPOINT_START && 61162306a36Sopenharmony_ci !apple_rtkit_is_running(rtk)) 61262306a36Sopenharmony_ci return -EINVAL; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (atomic) 61562306a36Sopenharmony_ci flags = GFP_ATOMIC; 61662306a36Sopenharmony_ci else 61762306a36Sopenharmony_ci flags = GFP_KERNEL; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci msg = kzalloc(sizeof(*msg), flags); 62062306a36Sopenharmony_ci if (!msg) 62162306a36Sopenharmony_ci return -ENOMEM; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci msg->mbox_msg.msg0 = message; 62462306a36Sopenharmony_ci msg->mbox_msg.msg1 = ep; 62562306a36Sopenharmony_ci msg->completion = completion; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* 62862306a36Sopenharmony_ci * The message will be sent with a MMIO write. We need the barrier 62962306a36Sopenharmony_ci * here to ensure any previous writes to buffers are visible to the 63062306a36Sopenharmony_ci * device before that MMIO write happens. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci dma_wmb(); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci ret = mbox_send_message(rtk->mbox_chan, &msg->mbox_msg); 63562306a36Sopenharmony_ci if (ret < 0) { 63662306a36Sopenharmony_ci kfree(msg); 63762306a36Sopenharmony_ci return ret; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_send_message); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciint apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, 64562306a36Sopenharmony_ci unsigned long timeout, bool atomic) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(completion); 64862306a36Sopenharmony_ci int ret; 64962306a36Sopenharmony_ci long t; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ret = apple_rtkit_send_message(rtk, ep, message, &completion, atomic); 65262306a36Sopenharmony_ci if (ret < 0) 65362306a36Sopenharmony_ci return ret; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (atomic) { 65662306a36Sopenharmony_ci ret = mbox_flush(rtk->mbox_chan, timeout); 65762306a36Sopenharmony_ci if (ret < 0) 65862306a36Sopenharmony_ci return ret; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (try_wait_for_completion(&completion)) 66162306a36Sopenharmony_ci return 0; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci return -ETIME; 66462306a36Sopenharmony_ci } else { 66562306a36Sopenharmony_ci t = wait_for_completion_interruptible_timeout( 66662306a36Sopenharmony_ci &completion, msecs_to_jiffies(timeout)); 66762306a36Sopenharmony_ci if (t < 0) 66862306a36Sopenharmony_ci return t; 66962306a36Sopenharmony_ci else if (t == 0) 67062306a36Sopenharmony_ci return -ETIME; 67162306a36Sopenharmony_ci return 0; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ciint apple_rtkit_poll(struct apple_rtkit *rtk) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci return mbox_client_peek_data(rtk->mbox_chan); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_poll); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ciint apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci u64 msg; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (!test_bit(endpoint, rtk->endpoints)) 68762306a36Sopenharmony_ci return -EINVAL; 68862306a36Sopenharmony_ci if (endpoint >= APPLE_RTKIT_APP_ENDPOINT_START && 68962306a36Sopenharmony_ci !apple_rtkit_is_running(rtk)) 69062306a36Sopenharmony_ci return -EINVAL; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci msg = FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoint); 69362306a36Sopenharmony_ci msg |= APPLE_RTKIT_MGMT_STARTEP_FLAG; 69462306a36Sopenharmony_ci apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_STARTEP, msg); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_start_ep); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic int apple_rtkit_request_mbox_chan(struct apple_rtkit *rtk) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci if (rtk->mbox_name) 70362306a36Sopenharmony_ci rtk->mbox_chan = mbox_request_channel_byname(&rtk->mbox_cl, 70462306a36Sopenharmony_ci rtk->mbox_name); 70562306a36Sopenharmony_ci else 70662306a36Sopenharmony_ci rtk->mbox_chan = 70762306a36Sopenharmony_ci mbox_request_channel(&rtk->mbox_cl, rtk->mbox_idx); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (IS_ERR(rtk->mbox_chan)) 71062306a36Sopenharmony_ci return PTR_ERR(rtk->mbox_chan); 71162306a36Sopenharmony_ci return 0; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistruct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, 71562306a36Sopenharmony_ci const char *mbox_name, int mbox_idx, 71662306a36Sopenharmony_ci const struct apple_rtkit_ops *ops) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct apple_rtkit *rtk; 71962306a36Sopenharmony_ci int ret; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (!ops) 72262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci rtk = kzalloc(sizeof(*rtk), GFP_KERNEL); 72562306a36Sopenharmony_ci if (!rtk) 72662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci rtk->dev = dev; 72962306a36Sopenharmony_ci rtk->cookie = cookie; 73062306a36Sopenharmony_ci rtk->ops = ops; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci init_completion(&rtk->epmap_completion); 73362306a36Sopenharmony_ci init_completion(&rtk->iop_pwr_ack_completion); 73462306a36Sopenharmony_ci init_completion(&rtk->ap_pwr_ack_completion); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS); 73762306a36Sopenharmony_ci set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci rtk->mbox_name = mbox_name; 74062306a36Sopenharmony_ci rtk->mbox_idx = mbox_idx; 74162306a36Sopenharmony_ci rtk->mbox_cl.dev = dev; 74262306a36Sopenharmony_ci rtk->mbox_cl.tx_block = false; 74362306a36Sopenharmony_ci rtk->mbox_cl.knows_txdone = false; 74462306a36Sopenharmony_ci rtk->mbox_cl.rx_callback = &apple_rtkit_rx; 74562306a36Sopenharmony_ci rtk->mbox_cl.tx_done = &apple_rtkit_tx_done; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM, 74862306a36Sopenharmony_ci dev_name(rtk->dev)); 74962306a36Sopenharmony_ci if (!rtk->wq) { 75062306a36Sopenharmony_ci ret = -ENOMEM; 75162306a36Sopenharmony_ci goto free_rtk; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = apple_rtkit_request_mbox_chan(rtk); 75562306a36Sopenharmony_ci if (ret) 75662306a36Sopenharmony_ci goto destroy_wq; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci return rtk; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cidestroy_wq: 76162306a36Sopenharmony_ci destroy_workqueue(rtk->wq); 76262306a36Sopenharmony_cifree_rtk: 76362306a36Sopenharmony_ci kfree(rtk); 76462306a36Sopenharmony_ci return ERR_PTR(ret); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_init); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic int apple_rtkit_wait_for_completion(struct completion *c) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci long t; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci t = wait_for_completion_interruptible_timeout(c, 77362306a36Sopenharmony_ci msecs_to_jiffies(1000)); 77462306a36Sopenharmony_ci if (t < 0) 77562306a36Sopenharmony_ci return t; 77662306a36Sopenharmony_ci else if (t == 0) 77762306a36Sopenharmony_ci return -ETIME; 77862306a36Sopenharmony_ci else 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ciint apple_rtkit_reinit(struct apple_rtkit *rtk) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci /* make sure we don't handle any messages while reinitializing */ 78562306a36Sopenharmony_ci mbox_free_channel(rtk->mbox_chan); 78662306a36Sopenharmony_ci flush_workqueue(rtk->wq); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); 78962306a36Sopenharmony_ci apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); 79062306a36Sopenharmony_ci apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci kfree(rtk->syslog_msg_buffer); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci rtk->syslog_msg_buffer = NULL; 79562306a36Sopenharmony_ci rtk->syslog_n_entries = 0; 79662306a36Sopenharmony_ci rtk->syslog_msg_size = 0; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS); 79962306a36Sopenharmony_ci set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci reinit_completion(&rtk->epmap_completion); 80262306a36Sopenharmony_ci reinit_completion(&rtk->iop_pwr_ack_completion); 80362306a36Sopenharmony_ci reinit_completion(&rtk->ap_pwr_ack_completion); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci rtk->crashed = false; 80662306a36Sopenharmony_ci rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_OFF; 80762306a36Sopenharmony_ci rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_OFF; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci return apple_rtkit_request_mbox_chan(rtk); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_reinit); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic int apple_rtkit_set_ap_power_state(struct apple_rtkit *rtk, 81462306a36Sopenharmony_ci unsigned int state) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci u64 msg; 81762306a36Sopenharmony_ci int ret; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci reinit_completion(&rtk->ap_pwr_ack_completion); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state); 82262306a36Sopenharmony_ci apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE, 82362306a36Sopenharmony_ci msg); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci ret = apple_rtkit_wait_for_completion(&rtk->ap_pwr_ack_completion); 82662306a36Sopenharmony_ci if (ret) 82762306a36Sopenharmony_ci return ret; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (rtk->ap_power_state != state) 83062306a36Sopenharmony_ci return -EINVAL; 83162306a36Sopenharmony_ci return 0; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic int apple_rtkit_set_iop_power_state(struct apple_rtkit *rtk, 83562306a36Sopenharmony_ci unsigned int state) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci u64 msg; 83862306a36Sopenharmony_ci int ret; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci reinit_completion(&rtk->iop_pwr_ack_completion); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state); 84362306a36Sopenharmony_ci apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE, 84462306a36Sopenharmony_ci msg); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci ret = apple_rtkit_wait_for_completion(&rtk->iop_pwr_ack_completion); 84762306a36Sopenharmony_ci if (ret) 84862306a36Sopenharmony_ci return ret; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (rtk->iop_power_state != state) 85162306a36Sopenharmony_ci return -EINVAL; 85262306a36Sopenharmony_ci return 0; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ciint apple_rtkit_boot(struct apple_rtkit *rtk) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci int ret; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (apple_rtkit_is_running(rtk)) 86062306a36Sopenharmony_ci return 0; 86162306a36Sopenharmony_ci if (rtk->crashed) 86262306a36Sopenharmony_ci return -EINVAL; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: waiting for boot to finish\n"); 86562306a36Sopenharmony_ci ret = apple_rtkit_wait_for_completion(&rtk->epmap_completion); 86662306a36Sopenharmony_ci if (ret) 86762306a36Sopenharmony_ci return ret; 86862306a36Sopenharmony_ci if (rtk->boot_result) 86962306a36Sopenharmony_ci return rtk->boot_result; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci dev_dbg(rtk->dev, "RTKit: waiting for IOP power state ACK\n"); 87262306a36Sopenharmony_ci ret = apple_rtkit_wait_for_completion(&rtk->iop_pwr_ack_completion); 87362306a36Sopenharmony_ci if (ret) 87462306a36Sopenharmony_ci return ret; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return apple_rtkit_set_ap_power_state(rtk, APPLE_RTKIT_PWR_STATE_ON); 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_boot); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ciint apple_rtkit_shutdown(struct apple_rtkit *rtk) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci int ret; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* if OFF is used here the co-processor will not wake up again */ 88562306a36Sopenharmony_ci ret = apple_rtkit_set_ap_power_state(rtk, 88662306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_QUIESCED); 88762306a36Sopenharmony_ci if (ret) 88862306a36Sopenharmony_ci return ret; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_SLEEP); 89162306a36Sopenharmony_ci if (ret) 89262306a36Sopenharmony_ci return ret; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci return apple_rtkit_reinit(rtk); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_shutdown); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ciint apple_rtkit_idle(struct apple_rtkit *rtk) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci int ret; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* if OFF is used here the co-processor will not wake up again */ 90362306a36Sopenharmony_ci ret = apple_rtkit_set_ap_power_state(rtk, 90462306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_IDLE); 90562306a36Sopenharmony_ci if (ret) 90662306a36Sopenharmony_ci return ret; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_IDLE); 90962306a36Sopenharmony_ci if (ret) 91062306a36Sopenharmony_ci return ret; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_IDLE; 91362306a36Sopenharmony_ci rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_IDLE; 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_idle); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ciint apple_rtkit_quiesce(struct apple_rtkit *rtk) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci int ret; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci ret = apple_rtkit_set_ap_power_state(rtk, 92362306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_QUIESCED); 92462306a36Sopenharmony_ci if (ret) 92562306a36Sopenharmony_ci return ret; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci ret = apple_rtkit_set_iop_power_state(rtk, 92862306a36Sopenharmony_ci APPLE_RTKIT_PWR_STATE_QUIESCED); 92962306a36Sopenharmony_ci if (ret) 93062306a36Sopenharmony_ci return ret; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci ret = apple_rtkit_reinit(rtk); 93362306a36Sopenharmony_ci if (ret) 93462306a36Sopenharmony_ci return ret; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED; 93762306a36Sopenharmony_ci rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED; 93862306a36Sopenharmony_ci return 0; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_quiesce); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ciint apple_rtkit_wake(struct apple_rtkit *rtk) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci u64 msg; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (apple_rtkit_is_running(rtk)) 94762306a36Sopenharmony_ci return -EINVAL; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci reinit_completion(&rtk->iop_pwr_ack_completion); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* 95262306a36Sopenharmony_ci * Use open-coded apple_rtkit_set_iop_power_state since apple_rtkit_boot 95362306a36Sopenharmony_ci * will wait for the completion anyway. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON); 95662306a36Sopenharmony_ci apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE, 95762306a36Sopenharmony_ci msg); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci return apple_rtkit_boot(rtk); 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_wake); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_civoid apple_rtkit_free(struct apple_rtkit *rtk) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci mbox_free_channel(rtk->mbox_chan); 96662306a36Sopenharmony_ci destroy_workqueue(rtk->wq); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); 96962306a36Sopenharmony_ci apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); 97062306a36Sopenharmony_ci apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci kfree(rtk->syslog_msg_buffer); 97362306a36Sopenharmony_ci kfree(rtk); 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(apple_rtkit_free); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic void apple_rtkit_free_wrapper(void *data) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci apple_rtkit_free(data); 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistruct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie, 98362306a36Sopenharmony_ci const char *mbox_name, int mbox_idx, 98462306a36Sopenharmony_ci const struct apple_rtkit_ops *ops) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci struct apple_rtkit *rtk; 98762306a36Sopenharmony_ci int ret; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci rtk = apple_rtkit_init(dev, cookie, mbox_name, mbox_idx, ops); 99062306a36Sopenharmony_ci if (IS_ERR(rtk)) 99162306a36Sopenharmony_ci return rtk; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, apple_rtkit_free_wrapper, rtk); 99462306a36Sopenharmony_ci if (ret) 99562306a36Sopenharmony_ci return ERR_PTR(ret); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci return rtk; 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_apple_rtkit_init); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL"); 100262306a36Sopenharmony_ciMODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); 100362306a36Sopenharmony_ciMODULE_DESCRIPTION("Apple RTKit driver"); 1004