// 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 */
APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */
APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */
APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */
APPLE_RTKIT_PWR_STATE_INIT = 0x220, /* init after starting the coproc */
};
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;
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);
}
}
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);
} 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, bfr, rtk->crashlog_buffer.size);
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);
}
}
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;
}
if (rtk->crashed) {
dev_warn(rtk->dev, "RTKit: Device is crashed, cannot send message\n"); return -EINVAL;
}
if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
!apple_rtkit_is_running(rtk)) {
dev_warn(rtk->dev, "RTKit: Endpoint 0x%02x is not running, cannot send message\n", ep); return -EINVAL;
}
/* * 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();
staticint 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; elseif (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 */
apple_mbox_stop(rtk->mbox);
flush_workqueue(rtk->wq);
msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state);
ret = apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
msg); if (ret) return ret;
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;
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;
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;
int apple_rtkit_wake(struct apple_rtkit *rtk)
{
u64 msg; int ret;
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_INIT);
ret = apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
msg); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.