19bd1d9a0SSven Peter // SPDX-License-Identifier: GPL-2.0-only OR MIT
29bd1d9a0SSven Peter /*
39bd1d9a0SSven Peter * Apple RTKit IPC library
49bd1d9a0SSven Peter * Copyright (C) The Asahi Linux Contributors
59bd1d9a0SSven Peter */
69bd1d9a0SSven Peter
79bd1d9a0SSven Peter #include "rtkit-internal.h"
89bd1d9a0SSven Peter
99bd1d9a0SSven Peter enum {
109bd1d9a0SSven Peter APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */
119bd1d9a0SSven Peter APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */
1240eaa8c0SHector Martin APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */
139bd1d9a0SSven Peter APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */
149bd1d9a0SSven Peter APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */
159bd1d9a0SSven Peter };
169bd1d9a0SSven Peter
179bd1d9a0SSven Peter enum {
189bd1d9a0SSven Peter APPLE_RTKIT_EP_MGMT = 0,
199bd1d9a0SSven Peter APPLE_RTKIT_EP_CRASHLOG = 1,
209bd1d9a0SSven Peter APPLE_RTKIT_EP_SYSLOG = 2,
219bd1d9a0SSven Peter APPLE_RTKIT_EP_DEBUG = 3,
229bd1d9a0SSven Peter APPLE_RTKIT_EP_IOREPORT = 4,
239bd1d9a0SSven Peter APPLE_RTKIT_EP_OSLOG = 8,
249bd1d9a0SSven Peter };
259bd1d9a0SSven Peter
269bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_TYPE GENMASK_ULL(59, 52)
279bd1d9a0SSven Peter
289bd1d9a0SSven Peter enum {
299bd1d9a0SSven Peter APPLE_RTKIT_MGMT_HELLO = 1,
309bd1d9a0SSven Peter APPLE_RTKIT_MGMT_HELLO_REPLY = 2,
319bd1d9a0SSven Peter APPLE_RTKIT_MGMT_STARTEP = 5,
329bd1d9a0SSven Peter APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE = 6,
339bd1d9a0SSven Peter APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK = 7,
349bd1d9a0SSven Peter APPLE_RTKIT_MGMT_EPMAP = 8,
359bd1d9a0SSven Peter APPLE_RTKIT_MGMT_EPMAP_REPLY = 8,
369bd1d9a0SSven Peter APPLE_RTKIT_MGMT_SET_AP_PWR_STATE = 0xb,
379bd1d9a0SSven Peter APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK = 0xb,
389bd1d9a0SSven Peter };
399bd1d9a0SSven Peter
409bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK_ULL(15, 0)
419bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK_ULL(31, 16)
429bd1d9a0SSven Peter
439bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_EPMAP_LAST BIT_ULL(51)
449bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK_ULL(34, 32)
459bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK_ULL(31, 0)
469bd1d9a0SSven Peter
479bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT_ULL(0)
489bd1d9a0SSven Peter
499bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK_ULL(39, 32)
509bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT_ULL(1)
519bd1d9a0SSven Peter
529bd1d9a0SSven Peter #define APPLE_RTKIT_MGMT_PWR_STATE GENMASK_ULL(15, 0)
539bd1d9a0SSven Peter
549bd1d9a0SSven Peter #define APPLE_RTKIT_CRASHLOG_CRASH 1
559bd1d9a0SSven Peter
569bd1d9a0SSven Peter #define APPLE_RTKIT_BUFFER_REQUEST 1
579bd1d9a0SSven Peter #define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44)
5822344488SAsahi Lina #define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0)
599bd1d9a0SSven Peter
609bd1d9a0SSven Peter #define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52)
619bd1d9a0SSven Peter
629bd1d9a0SSven Peter #define APPLE_RTKIT_SYSLOG_LOG 5
639bd1d9a0SSven Peter
649bd1d9a0SSven Peter #define APPLE_RTKIT_SYSLOG_INIT 8
659bd1d9a0SSven Peter #define APPLE_RTKIT_SYSLOG_N_ENTRIES GENMASK_ULL(7, 0)
669bd1d9a0SSven Peter #define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24)
679bd1d9a0SSven Peter
689bd1d9a0SSven Peter #define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56)
699bd1d9a0SSven Peter #define APPLE_RTKIT_OSLOG_INIT 1
709bd1d9a0SSven Peter #define APPLE_RTKIT_OSLOG_ACK 3
719bd1d9a0SSven Peter
729bd1d9a0SSven Peter #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
739bd1d9a0SSven Peter #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
749bd1d9a0SSven Peter
759bd1d9a0SSven Peter struct apple_rtkit_rx_work {
769bd1d9a0SSven Peter struct apple_rtkit *rtk;
779bd1d9a0SSven Peter u8 ep;
789bd1d9a0SSven Peter u64 msg;
799bd1d9a0SSven Peter struct work_struct work;
809bd1d9a0SSven Peter };
819bd1d9a0SSven Peter
apple_rtkit_is_running(struct apple_rtkit * rtk)829bd1d9a0SSven Peter bool apple_rtkit_is_running(struct apple_rtkit *rtk)
839bd1d9a0SSven Peter {
849bd1d9a0SSven Peter if (rtk->crashed)
859bd1d9a0SSven Peter return false;
869bd1d9a0SSven Peter if ((rtk->iop_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON)
879bd1d9a0SSven Peter return false;
889bd1d9a0SSven Peter if ((rtk->ap_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON)
899bd1d9a0SSven Peter return false;
909bd1d9a0SSven Peter return true;
919bd1d9a0SSven Peter }
929bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_is_running);
939bd1d9a0SSven Peter
apple_rtkit_is_crashed(struct apple_rtkit * rtk)949bd1d9a0SSven Peter bool apple_rtkit_is_crashed(struct apple_rtkit *rtk)
959bd1d9a0SSven Peter {
969bd1d9a0SSven Peter return rtk->crashed;
979bd1d9a0SSven Peter }
989bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_is_crashed);
999bd1d9a0SSven Peter
apple_rtkit_management_send(struct apple_rtkit * rtk,u8 type,u64 msg)1009bd1d9a0SSven Peter static void apple_rtkit_management_send(struct apple_rtkit *rtk, u8 type,
1019bd1d9a0SSven Peter u64 msg)
1029bd1d9a0SSven Peter {
1039bd1d9a0SSven Peter msg &= ~APPLE_RTKIT_MGMT_TYPE;
1049bd1d9a0SSven Peter msg |= FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, type);
1059bd1d9a0SSven Peter apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_MGMT, msg, NULL, false);
1069bd1d9a0SSven Peter }
1079bd1d9a0SSven Peter
apple_rtkit_management_rx_hello(struct apple_rtkit * rtk,u64 msg)1089bd1d9a0SSven Peter static void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg)
1099bd1d9a0SSven Peter {
1109bd1d9a0SSven Peter u64 reply;
1119bd1d9a0SSven Peter
1129bd1d9a0SSven Peter int min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg);
1139bd1d9a0SSven Peter int max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg);
1149bd1d9a0SSven Peter int want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
1159bd1d9a0SSven Peter
1169bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: Min ver %d, max ver %d\n", min_ver, max_ver);
1179bd1d9a0SSven Peter
1189bd1d9a0SSven Peter if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
1199bd1d9a0SSven Peter dev_err(rtk->dev, "RTKit: Firmware min version %d is too new\n",
1209bd1d9a0SSven Peter min_ver);
1219bd1d9a0SSven Peter goto abort_boot;
1229bd1d9a0SSven Peter }
1239bd1d9a0SSven Peter
1249bd1d9a0SSven Peter if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
1259bd1d9a0SSven Peter dev_err(rtk->dev, "RTKit: Firmware max version %d is too old\n",
1269bd1d9a0SSven Peter max_ver);
1279bd1d9a0SSven Peter goto abort_boot;
1289bd1d9a0SSven Peter }
1299bd1d9a0SSven Peter
1309bd1d9a0SSven Peter dev_info(rtk->dev, "RTKit: Initializing (protocol version %d)\n",
1319bd1d9a0SSven Peter want_ver);
1329bd1d9a0SSven Peter rtk->version = want_ver;
1339bd1d9a0SSven Peter
1349bd1d9a0SSven Peter reply = FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver);
1359bd1d9a0SSven Peter reply |= FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
1369bd1d9a0SSven Peter apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_HELLO_REPLY, reply);
1379bd1d9a0SSven Peter
1389bd1d9a0SSven Peter return;
1399bd1d9a0SSven Peter
1409bd1d9a0SSven Peter abort_boot:
1419bd1d9a0SSven Peter rtk->boot_result = -EINVAL;
1429bd1d9a0SSven Peter complete_all(&rtk->epmap_completion);
1439bd1d9a0SSven Peter }
1449bd1d9a0SSven Peter
apple_rtkit_management_rx_epmap(struct apple_rtkit * rtk,u64 msg)1459bd1d9a0SSven Peter static void apple_rtkit_management_rx_epmap(struct apple_rtkit *rtk, u64 msg)
1469bd1d9a0SSven Peter {
1479bd1d9a0SSven Peter int i, ep;
1489bd1d9a0SSven Peter u64 reply;
1499bd1d9a0SSven Peter unsigned long bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg);
1509bd1d9a0SSven Peter u32 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg);
1519bd1d9a0SSven Peter
1529bd1d9a0SSven Peter dev_dbg(rtk->dev,
1539bd1d9a0SSven Peter "RTKit: received endpoint bitmap 0x%lx with base 0x%x\n",
1549bd1d9a0SSven Peter bitmap, base);
1559bd1d9a0SSven Peter
1569bd1d9a0SSven Peter for_each_set_bit(i, &bitmap, 32) {
1579bd1d9a0SSven Peter ep = 32 * base + i;
1589bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: Discovered endpoint 0x%02x\n", ep);
1599bd1d9a0SSven Peter set_bit(ep, rtk->endpoints);
1609bd1d9a0SSven Peter }
1619bd1d9a0SSven Peter
1629bd1d9a0SSven Peter reply = FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
1639bd1d9a0SSven Peter if (msg & APPLE_RTKIT_MGMT_EPMAP_LAST)
1649bd1d9a0SSven Peter reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
1659bd1d9a0SSven Peter else
1669bd1d9a0SSven Peter reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
1679bd1d9a0SSven Peter
1689bd1d9a0SSven Peter apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_EPMAP_REPLY, reply);
1699bd1d9a0SSven Peter
1709bd1d9a0SSven Peter if (!(msg & APPLE_RTKIT_MGMT_EPMAP_LAST))
1719bd1d9a0SSven Peter return;
1729bd1d9a0SSven Peter
1739bd1d9a0SSven Peter for_each_set_bit(ep, rtk->endpoints, APPLE_RTKIT_APP_ENDPOINT_START) {
1749bd1d9a0SSven Peter switch (ep) {
1759bd1d9a0SSven Peter /* the management endpoint is started by default */
1769bd1d9a0SSven Peter case APPLE_RTKIT_EP_MGMT:
1779bd1d9a0SSven Peter break;
1789bd1d9a0SSven Peter
1799bd1d9a0SSven Peter /* without starting these RTKit refuses to boot */
1809bd1d9a0SSven Peter case APPLE_RTKIT_EP_SYSLOG:
1819bd1d9a0SSven Peter case APPLE_RTKIT_EP_CRASHLOG:
1829bd1d9a0SSven Peter case APPLE_RTKIT_EP_DEBUG:
1839bd1d9a0SSven Peter case APPLE_RTKIT_EP_IOREPORT:
1849bd1d9a0SSven Peter case APPLE_RTKIT_EP_OSLOG:
1859bd1d9a0SSven Peter dev_dbg(rtk->dev,
1869bd1d9a0SSven Peter "RTKit: Starting system endpoint 0x%02x\n", ep);
1879bd1d9a0SSven Peter apple_rtkit_start_ep(rtk, ep);
1889bd1d9a0SSven Peter break;
1899bd1d9a0SSven Peter
1909bd1d9a0SSven Peter default:
1919bd1d9a0SSven Peter dev_warn(rtk->dev,
1929bd1d9a0SSven Peter "RTKit: Unknown system endpoint: 0x%02x\n",
1939bd1d9a0SSven Peter ep);
1949bd1d9a0SSven Peter }
1959bd1d9a0SSven Peter }
1969bd1d9a0SSven Peter
1979bd1d9a0SSven Peter rtk->boot_result = 0;
1989bd1d9a0SSven Peter complete_all(&rtk->epmap_completion);
1999bd1d9a0SSven Peter }
2009bd1d9a0SSven Peter
apple_rtkit_management_rx_iop_pwr_ack(struct apple_rtkit * rtk,u64 msg)2019bd1d9a0SSven Peter static void apple_rtkit_management_rx_iop_pwr_ack(struct apple_rtkit *rtk,
2029bd1d9a0SSven Peter u64 msg)
2039bd1d9a0SSven Peter {
2049bd1d9a0SSven Peter unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg);
2059bd1d9a0SSven Peter
2069bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: IOP power state transition: 0x%x -> 0x%x\n",
2079bd1d9a0SSven Peter rtk->iop_power_state, new_state);
2089bd1d9a0SSven Peter rtk->iop_power_state = new_state;
2099bd1d9a0SSven Peter
2109bd1d9a0SSven Peter complete_all(&rtk->iop_pwr_ack_completion);
2119bd1d9a0SSven Peter }
2129bd1d9a0SSven Peter
apple_rtkit_management_rx_ap_pwr_ack(struct apple_rtkit * rtk,u64 msg)2139bd1d9a0SSven Peter static void apple_rtkit_management_rx_ap_pwr_ack(struct apple_rtkit *rtk,
2149bd1d9a0SSven Peter u64 msg)
2159bd1d9a0SSven Peter {
2169bd1d9a0SSven Peter unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg);
2179bd1d9a0SSven Peter
2189bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: AP power state transition: 0x%x -> 0x%x\n",
2199bd1d9a0SSven Peter rtk->ap_power_state, new_state);
2209bd1d9a0SSven Peter rtk->ap_power_state = new_state;
2219bd1d9a0SSven Peter
2229bd1d9a0SSven Peter complete_all(&rtk->ap_pwr_ack_completion);
2239bd1d9a0SSven Peter }
2249bd1d9a0SSven Peter
apple_rtkit_management_rx(struct apple_rtkit * rtk,u64 msg)2259bd1d9a0SSven Peter static void apple_rtkit_management_rx(struct apple_rtkit *rtk, u64 msg)
2269bd1d9a0SSven Peter {
2279bd1d9a0SSven Peter u8 type = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg);
2289bd1d9a0SSven Peter
2299bd1d9a0SSven Peter switch (type) {
2309bd1d9a0SSven Peter case APPLE_RTKIT_MGMT_HELLO:
2319bd1d9a0SSven Peter apple_rtkit_management_rx_hello(rtk, msg);
2329bd1d9a0SSven Peter break;
2339bd1d9a0SSven Peter case APPLE_RTKIT_MGMT_EPMAP:
2349bd1d9a0SSven Peter apple_rtkit_management_rx_epmap(rtk, msg);
2359bd1d9a0SSven Peter break;
2369bd1d9a0SSven Peter case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK:
2379bd1d9a0SSven Peter apple_rtkit_management_rx_iop_pwr_ack(rtk, msg);
2389bd1d9a0SSven Peter break;
2399bd1d9a0SSven Peter case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK:
2409bd1d9a0SSven Peter apple_rtkit_management_rx_ap_pwr_ack(rtk, msg);
2419bd1d9a0SSven Peter break;
2429bd1d9a0SSven Peter default:
2439bd1d9a0SSven Peter dev_warn(
2449bd1d9a0SSven Peter rtk->dev,
2459bd1d9a0SSven Peter "RTKit: unknown management message: 0x%llx (type: 0x%02x)\n",
2469bd1d9a0SSven Peter msg, type);
2479bd1d9a0SSven Peter }
2489bd1d9a0SSven Peter }
2499bd1d9a0SSven Peter
apple_rtkit_common_rx_get_buffer(struct apple_rtkit * rtk,struct apple_rtkit_shmem * buffer,u8 ep,u64 msg)2509bd1d9a0SSven Peter static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk,
2519bd1d9a0SSven Peter struct apple_rtkit_shmem *buffer,
2529bd1d9a0SSven Peter u8 ep, u64 msg)
2539bd1d9a0SSven Peter {
2549bd1d9a0SSven Peter size_t n_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg);
2559bd1d9a0SSven Peter u64 reply;
2569bd1d9a0SSven Peter int err;
2579bd1d9a0SSven Peter
2589bd1d9a0SSven Peter buffer->buffer = NULL;
2599bd1d9a0SSven Peter buffer->iomem = NULL;
2609bd1d9a0SSven Peter buffer->is_mapped = false;
2619bd1d9a0SSven Peter buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg);
2629bd1d9a0SSven Peter buffer->size = n_4kpages << 12;
2639bd1d9a0SSven Peter
2649bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n",
2659bd1d9a0SSven Peter buffer->size, &buffer->iova);
2669bd1d9a0SSven Peter
2679bd1d9a0SSven Peter if (buffer->iova &&
2689bd1d9a0SSven Peter (!rtk->ops->shmem_setup || !rtk->ops->shmem_destroy)) {
2699bd1d9a0SSven Peter err = -EINVAL;
2709bd1d9a0SSven Peter goto error;
2719bd1d9a0SSven Peter }
2729bd1d9a0SSven Peter
2739bd1d9a0SSven Peter if (rtk->ops->shmem_setup) {
2749bd1d9a0SSven Peter err = rtk->ops->shmem_setup(rtk->cookie, buffer);
2759bd1d9a0SSven Peter if (err)
2769bd1d9a0SSven Peter goto error;
2779bd1d9a0SSven Peter } else {
2789bd1d9a0SSven Peter buffer->buffer = dma_alloc_coherent(rtk->dev, buffer->size,
2799bd1d9a0SSven Peter &buffer->iova, GFP_KERNEL);
2809bd1d9a0SSven Peter if (!buffer->buffer) {
2819bd1d9a0SSven Peter err = -ENOMEM;
2829bd1d9a0SSven Peter goto error;
2839bd1d9a0SSven Peter }
2849bd1d9a0SSven Peter }
2859bd1d9a0SSven Peter
2869bd1d9a0SSven Peter if (!buffer->is_mapped) {
2879bd1d9a0SSven Peter reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE,
2889bd1d9a0SSven Peter APPLE_RTKIT_BUFFER_REQUEST);
2899bd1d9a0SSven Peter reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, n_4kpages);
2909bd1d9a0SSven Peter reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA,
2919bd1d9a0SSven Peter buffer->iova);
2929bd1d9a0SSven Peter apple_rtkit_send_message(rtk, ep, reply, NULL, false);
2939bd1d9a0SSven Peter }
2949bd1d9a0SSven Peter
2959bd1d9a0SSven Peter return 0;
2969bd1d9a0SSven Peter
2979bd1d9a0SSven Peter error:
2989bd1d9a0SSven Peter buffer->buffer = NULL;
2999bd1d9a0SSven Peter buffer->iomem = NULL;
3009bd1d9a0SSven Peter buffer->iova = 0;
3019bd1d9a0SSven Peter buffer->size = 0;
3029bd1d9a0SSven Peter buffer->is_mapped = false;
3039bd1d9a0SSven Peter return err;
3049bd1d9a0SSven Peter }
3059bd1d9a0SSven Peter
apple_rtkit_free_buffer(struct apple_rtkit * rtk,struct apple_rtkit_shmem * bfr)3069bd1d9a0SSven Peter static void apple_rtkit_free_buffer(struct apple_rtkit *rtk,
3079bd1d9a0SSven Peter struct apple_rtkit_shmem *bfr)
3089bd1d9a0SSven Peter {
3099bd1d9a0SSven Peter if (bfr->size == 0)
3109bd1d9a0SSven Peter return;
3119bd1d9a0SSven Peter
3129bd1d9a0SSven Peter if (rtk->ops->shmem_destroy)
3139bd1d9a0SSven Peter rtk->ops->shmem_destroy(rtk->cookie, bfr);
3149bd1d9a0SSven Peter else if (bfr->buffer)
3159bd1d9a0SSven Peter dma_free_coherent(rtk->dev, bfr->size, bfr->buffer, bfr->iova);
3169bd1d9a0SSven Peter
3179bd1d9a0SSven Peter bfr->buffer = NULL;
3189bd1d9a0SSven Peter bfr->iomem = NULL;
3199bd1d9a0SSven Peter bfr->iova = 0;
3209bd1d9a0SSven Peter bfr->size = 0;
3219bd1d9a0SSven Peter bfr->is_mapped = false;
3229bd1d9a0SSven Peter }
3239bd1d9a0SSven Peter
apple_rtkit_memcpy(struct apple_rtkit * rtk,void * dst,struct apple_rtkit_shmem * bfr,size_t offset,size_t len)3249bd1d9a0SSven Peter static void apple_rtkit_memcpy(struct apple_rtkit *rtk, void *dst,
3259bd1d9a0SSven Peter struct apple_rtkit_shmem *bfr, size_t offset,
3269bd1d9a0SSven Peter size_t len)
3279bd1d9a0SSven Peter {
3289bd1d9a0SSven Peter if (bfr->iomem)
3299bd1d9a0SSven Peter memcpy_fromio(dst, bfr->iomem + offset, len);
3309bd1d9a0SSven Peter else
3319bd1d9a0SSven Peter memcpy(dst, bfr->buffer + offset, len);
3329bd1d9a0SSven Peter }
3339bd1d9a0SSven Peter
apple_rtkit_crashlog_rx(struct apple_rtkit * rtk,u64 msg)3349bd1d9a0SSven Peter static void apple_rtkit_crashlog_rx(struct apple_rtkit *rtk, u64 msg)
3359bd1d9a0SSven Peter {
3369bd1d9a0SSven Peter u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg);
3379bd1d9a0SSven Peter u8 *bfr;
3389bd1d9a0SSven Peter
3399bd1d9a0SSven Peter if (type != APPLE_RTKIT_CRASHLOG_CRASH) {
3409bd1d9a0SSven Peter dev_warn(rtk->dev, "RTKit: Unknown crashlog message: %llx\n",
3419bd1d9a0SSven Peter msg);
3429bd1d9a0SSven Peter return;
3439bd1d9a0SSven Peter }
3449bd1d9a0SSven Peter
3459bd1d9a0SSven Peter if (!rtk->crashlog_buffer.size) {
3469bd1d9a0SSven Peter apple_rtkit_common_rx_get_buffer(rtk, &rtk->crashlog_buffer,
3479bd1d9a0SSven Peter APPLE_RTKIT_EP_CRASHLOG, msg);
3489bd1d9a0SSven Peter return;
3499bd1d9a0SSven Peter }
3509bd1d9a0SSven Peter
3519bd1d9a0SSven Peter dev_err(rtk->dev, "RTKit: co-processor has crashed\n");
3529bd1d9a0SSven Peter
3539bd1d9a0SSven Peter /*
3549bd1d9a0SSven Peter * create a shadow copy here to make sure the co-processor isn't able
3559bd1d9a0SSven Peter * to change the log while we're dumping it. this also ensures
3569bd1d9a0SSven Peter * the buffer is in normal memory and not iomem for e.g. the SMC
3579bd1d9a0SSven Peter */
3589bd1d9a0SSven Peter bfr = kzalloc(rtk->crashlog_buffer.size, GFP_KERNEL);
3599bd1d9a0SSven Peter if (bfr) {
3609bd1d9a0SSven Peter apple_rtkit_memcpy(rtk, bfr, &rtk->crashlog_buffer, 0,
3619bd1d9a0SSven Peter rtk->crashlog_buffer.size);
3629bd1d9a0SSven Peter apple_rtkit_crashlog_dump(rtk, bfr, rtk->crashlog_buffer.size);
3639bd1d9a0SSven Peter kfree(bfr);
3649bd1d9a0SSven Peter } else {
3659bd1d9a0SSven Peter dev_err(rtk->dev,
3669bd1d9a0SSven Peter "RTKit: Couldn't allocate crashlog shadow buffer\n");
3679bd1d9a0SSven Peter }
3689bd1d9a0SSven Peter
3699bd1d9a0SSven Peter rtk->crashed = true;
3709bd1d9a0SSven Peter if (rtk->ops->crashed)
3719bd1d9a0SSven Peter rtk->ops->crashed(rtk->cookie);
3729bd1d9a0SSven Peter }
3739bd1d9a0SSven Peter
apple_rtkit_ioreport_rx(struct apple_rtkit * rtk,u64 msg)3749bd1d9a0SSven Peter static void apple_rtkit_ioreport_rx(struct apple_rtkit *rtk, u64 msg)
3759bd1d9a0SSven Peter {
3769bd1d9a0SSven Peter u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg);
3779bd1d9a0SSven Peter
3789bd1d9a0SSven Peter switch (type) {
3799bd1d9a0SSven Peter case APPLE_RTKIT_BUFFER_REQUEST:
3809bd1d9a0SSven Peter apple_rtkit_common_rx_get_buffer(rtk, &rtk->ioreport_buffer,
3819bd1d9a0SSven Peter APPLE_RTKIT_EP_IOREPORT, msg);
3829bd1d9a0SSven Peter break;
3839bd1d9a0SSven Peter /* unknown, must be ACKed or the co-processor will hang */
3849bd1d9a0SSven Peter case 0x8:
3859bd1d9a0SSven Peter case 0xc:
3869bd1d9a0SSven Peter apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_IOREPORT, msg,
3879bd1d9a0SSven Peter NULL, false);
3889bd1d9a0SSven Peter break;
3899bd1d9a0SSven Peter default:
3909bd1d9a0SSven Peter dev_warn(rtk->dev, "RTKit: Unknown ioreport message: %llx\n",
3919bd1d9a0SSven Peter msg);
3929bd1d9a0SSven Peter }
3939bd1d9a0SSven Peter }
3949bd1d9a0SSven Peter
apple_rtkit_syslog_rx_init(struct apple_rtkit * rtk,u64 msg)3959bd1d9a0SSven Peter static void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg)
3969bd1d9a0SSven Peter {
3979bd1d9a0SSven Peter rtk->syslog_n_entries = FIELD_GET(APPLE_RTKIT_SYSLOG_N_ENTRIES, msg);
3989bd1d9a0SSven Peter rtk->syslog_msg_size = FIELD_GET(APPLE_RTKIT_SYSLOG_MSG_SIZE, msg);
3999bd1d9a0SSven Peter
4009bd1d9a0SSven Peter rtk->syslog_msg_buffer = kzalloc(rtk->syslog_msg_size, GFP_KERNEL);
4019bd1d9a0SSven Peter
4029bd1d9a0SSven Peter dev_dbg(rtk->dev,
4039bd1d9a0SSven Peter "RTKit: syslog initialized: entries: %zd, msg_size: %zd\n",
4049bd1d9a0SSven Peter rtk->syslog_n_entries, rtk->syslog_msg_size);
4059bd1d9a0SSven Peter }
4069bd1d9a0SSven Peter
should_crop_syslog_char(char c)407bdfe6de2SMartin Povišer static bool should_crop_syslog_char(char c)
408bdfe6de2SMartin Povišer {
409bdfe6de2SMartin Povišer return c == '\n' || c == '\r' || c == ' ' || c == '\0';
410bdfe6de2SMartin Povišer }
411bdfe6de2SMartin Povišer
apple_rtkit_syslog_rx_log(struct apple_rtkit * rtk,u64 msg)4129bd1d9a0SSven Peter static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg)
4139bd1d9a0SSven Peter {
4149bd1d9a0SSven Peter u8 idx = msg & 0xff;
4159bd1d9a0SSven Peter char log_context[24];
4169bd1d9a0SSven Peter size_t entry_size = 0x20 + rtk->syslog_msg_size;
417bdfe6de2SMartin Povišer int msglen;
4189bd1d9a0SSven Peter
4199bd1d9a0SSven Peter if (!rtk->syslog_msg_buffer) {
4209bd1d9a0SSven Peter dev_warn(
4219bd1d9a0SSven Peter rtk->dev,
4229bd1d9a0SSven Peter "RTKit: received syslog message but no syslog_msg_buffer\n");
4239bd1d9a0SSven Peter goto done;
4249bd1d9a0SSven Peter }
4259bd1d9a0SSven Peter if (!rtk->syslog_buffer.size) {
4269bd1d9a0SSven Peter dev_warn(
4279bd1d9a0SSven Peter rtk->dev,
4289bd1d9a0SSven Peter "RTKit: received syslog message but syslog_buffer.size is zero\n");
4299bd1d9a0SSven Peter goto done;
4309bd1d9a0SSven Peter }
4319bd1d9a0SSven Peter if (!rtk->syslog_buffer.buffer && !rtk->syslog_buffer.iomem) {
4329bd1d9a0SSven Peter dev_warn(
4339bd1d9a0SSven Peter rtk->dev,
4349bd1d9a0SSven Peter "RTKit: received syslog message but no syslog_buffer.buffer or syslog_buffer.iomem\n");
4359bd1d9a0SSven Peter goto done;
4369bd1d9a0SSven Peter }
4379bd1d9a0SSven Peter if (idx > rtk->syslog_n_entries) {
4389bd1d9a0SSven Peter dev_warn(rtk->dev, "RTKit: syslog index %d out of range\n",
4399bd1d9a0SSven Peter idx);
4409bd1d9a0SSven Peter goto done;
4419bd1d9a0SSven Peter }
4429bd1d9a0SSven Peter
4439bd1d9a0SSven Peter apple_rtkit_memcpy(rtk, log_context, &rtk->syslog_buffer,
4449bd1d9a0SSven Peter idx * entry_size + 8, sizeof(log_context));
4459bd1d9a0SSven Peter apple_rtkit_memcpy(rtk, rtk->syslog_msg_buffer, &rtk->syslog_buffer,
4469bd1d9a0SSven Peter idx * entry_size + 8 + sizeof(log_context),
4479bd1d9a0SSven Peter rtk->syslog_msg_size);
4489bd1d9a0SSven Peter
4499bd1d9a0SSven Peter log_context[sizeof(log_context) - 1] = 0;
450bdfe6de2SMartin Povišer
451bdfe6de2SMartin Povišer msglen = rtk->syslog_msg_size - 1;
452bdfe6de2SMartin Povišer while (msglen > 0 &&
453bdfe6de2SMartin Povišer should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1]))
454bdfe6de2SMartin Povišer msglen--;
455bdfe6de2SMartin Povišer
456bdfe6de2SMartin Povišer rtk->syslog_msg_buffer[msglen] = 0;
4579bd1d9a0SSven Peter dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context,
4589bd1d9a0SSven Peter rtk->syslog_msg_buffer);
4599bd1d9a0SSven Peter
4609bd1d9a0SSven Peter done:
4619bd1d9a0SSven Peter apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_SYSLOG, msg, NULL, false);
4629bd1d9a0SSven Peter }
4639bd1d9a0SSven Peter
apple_rtkit_syslog_rx(struct apple_rtkit * rtk,u64 msg)4649bd1d9a0SSven Peter static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg)
4659bd1d9a0SSven Peter {
4669bd1d9a0SSven Peter u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg);
4679bd1d9a0SSven Peter
4689bd1d9a0SSven Peter switch (type) {
4699bd1d9a0SSven Peter case APPLE_RTKIT_BUFFER_REQUEST:
4709bd1d9a0SSven Peter apple_rtkit_common_rx_get_buffer(rtk, &rtk->syslog_buffer,
4719bd1d9a0SSven Peter APPLE_RTKIT_EP_SYSLOG, msg);
4729bd1d9a0SSven Peter break;
4739bd1d9a0SSven Peter case APPLE_RTKIT_SYSLOG_INIT:
4749bd1d9a0SSven Peter apple_rtkit_syslog_rx_init(rtk, msg);
4759bd1d9a0SSven Peter break;
4769bd1d9a0SSven Peter case APPLE_RTKIT_SYSLOG_LOG:
4779bd1d9a0SSven Peter apple_rtkit_syslog_rx_log(rtk, msg);
4789bd1d9a0SSven Peter break;
4799bd1d9a0SSven Peter default:
4809bd1d9a0SSven Peter dev_warn(rtk->dev, "RTKit: Unknown syslog message: %llx\n",
4819bd1d9a0SSven Peter msg);
4829bd1d9a0SSven Peter }
4839bd1d9a0SSven Peter }
4849bd1d9a0SSven Peter
apple_rtkit_oslog_rx_init(struct apple_rtkit * rtk,u64 msg)4859bd1d9a0SSven Peter static void apple_rtkit_oslog_rx_init(struct apple_rtkit *rtk, u64 msg)
4869bd1d9a0SSven Peter {
4879bd1d9a0SSven Peter u64 ack;
4889bd1d9a0SSven Peter
4899bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: oslog init: msg: 0x%llx\n", msg);
4909bd1d9a0SSven Peter ack = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_ACK);
4919bd1d9a0SSven Peter apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_OSLOG, ack, NULL, false);
4929bd1d9a0SSven Peter }
4939bd1d9a0SSven Peter
apple_rtkit_oslog_rx(struct apple_rtkit * rtk,u64 msg)4949bd1d9a0SSven Peter static void apple_rtkit_oslog_rx(struct apple_rtkit *rtk, u64 msg)
4959bd1d9a0SSven Peter {
4969bd1d9a0SSven Peter u8 type = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg);
4979bd1d9a0SSven Peter
4989bd1d9a0SSven Peter switch (type) {
4999bd1d9a0SSven Peter case APPLE_RTKIT_OSLOG_INIT:
5009bd1d9a0SSven Peter apple_rtkit_oslog_rx_init(rtk, msg);
5019bd1d9a0SSven Peter break;
5029bd1d9a0SSven Peter default:
5039bd1d9a0SSven Peter dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", msg);
5049bd1d9a0SSven Peter }
5059bd1d9a0SSven Peter }
5069bd1d9a0SSven Peter
apple_rtkit_rx_work(struct work_struct * work)5079bd1d9a0SSven Peter static void apple_rtkit_rx_work(struct work_struct *work)
5089bd1d9a0SSven Peter {
5099bd1d9a0SSven Peter struct apple_rtkit_rx_work *rtk_work =
5109bd1d9a0SSven Peter container_of(work, struct apple_rtkit_rx_work, work);
5119bd1d9a0SSven Peter struct apple_rtkit *rtk = rtk_work->rtk;
5129bd1d9a0SSven Peter
5139bd1d9a0SSven Peter switch (rtk_work->ep) {
5149bd1d9a0SSven Peter case APPLE_RTKIT_EP_MGMT:
5159bd1d9a0SSven Peter apple_rtkit_management_rx(rtk, rtk_work->msg);
5169bd1d9a0SSven Peter break;
5179bd1d9a0SSven Peter case APPLE_RTKIT_EP_CRASHLOG:
5189bd1d9a0SSven Peter apple_rtkit_crashlog_rx(rtk, rtk_work->msg);
5199bd1d9a0SSven Peter break;
5209bd1d9a0SSven Peter case APPLE_RTKIT_EP_SYSLOG:
5219bd1d9a0SSven Peter apple_rtkit_syslog_rx(rtk, rtk_work->msg);
5229bd1d9a0SSven Peter break;
5239bd1d9a0SSven Peter case APPLE_RTKIT_EP_IOREPORT:
5249bd1d9a0SSven Peter apple_rtkit_ioreport_rx(rtk, rtk_work->msg);
5259bd1d9a0SSven Peter break;
5269bd1d9a0SSven Peter case APPLE_RTKIT_EP_OSLOG:
5279bd1d9a0SSven Peter apple_rtkit_oslog_rx(rtk, rtk_work->msg);
5289bd1d9a0SSven Peter break;
5299bd1d9a0SSven Peter case APPLE_RTKIT_APP_ENDPOINT_START ... 0xff:
5309bd1d9a0SSven Peter if (rtk->ops->recv_message)
5319bd1d9a0SSven Peter rtk->ops->recv_message(rtk->cookie, rtk_work->ep,
5329bd1d9a0SSven Peter rtk_work->msg);
5339bd1d9a0SSven Peter else
5349bd1d9a0SSven Peter dev_warn(
5359bd1d9a0SSven Peter rtk->dev,
5369bd1d9a0SSven Peter "Received unexpected message to EP%02d: %llx\n",
5379bd1d9a0SSven Peter rtk_work->ep, rtk_work->msg);
5389bd1d9a0SSven Peter break;
5399bd1d9a0SSven Peter default:
5409bd1d9a0SSven Peter dev_warn(rtk->dev,
5419bd1d9a0SSven Peter "RTKit: message to unknown endpoint %02x: %llx\n",
5429bd1d9a0SSven Peter rtk_work->ep, rtk_work->msg);
5439bd1d9a0SSven Peter }
5449bd1d9a0SSven Peter
5459bd1d9a0SSven Peter kfree(rtk_work);
5469bd1d9a0SSven Peter }
5479bd1d9a0SSven Peter
apple_rtkit_rx(struct apple_mbox * mbox,struct apple_mbox_msg msg,void * cookie)548*bb538effSHector Martin static void apple_rtkit_rx(struct apple_mbox *mbox, struct apple_mbox_msg msg,
549*bb538effSHector Martin void *cookie)
5509bd1d9a0SSven Peter {
551*bb538effSHector Martin struct apple_rtkit *rtk = cookie;
5529bd1d9a0SSven Peter struct apple_rtkit_rx_work *work;
553*bb538effSHector Martin u8 ep = msg.msg1;
5549bd1d9a0SSven Peter
5559bd1d9a0SSven Peter /*
5569bd1d9a0SSven Peter * The message was read from a MMIO FIFO and we have to make
5579bd1d9a0SSven Peter * sure all reads from buffers sent with that message happen
5589bd1d9a0SSven Peter * afterwards.
5599bd1d9a0SSven Peter */
5609bd1d9a0SSven Peter dma_rmb();
5619bd1d9a0SSven Peter
5629bd1d9a0SSven Peter if (!test_bit(ep, rtk->endpoints))
5639bd1d9a0SSven Peter dev_warn(rtk->dev,
5649bd1d9a0SSven Peter "RTKit: Message to undiscovered endpoint 0x%02x\n",
5659bd1d9a0SSven Peter ep);
5669bd1d9a0SSven Peter
5679bd1d9a0SSven Peter if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
5689bd1d9a0SSven Peter rtk->ops->recv_message_early &&
569*bb538effSHector Martin rtk->ops->recv_message_early(rtk->cookie, ep, msg.msg0))
5709bd1d9a0SSven Peter return;
5719bd1d9a0SSven Peter
5729bd1d9a0SSven Peter work = kzalloc(sizeof(*work), GFP_ATOMIC);
5739bd1d9a0SSven Peter if (!work)
5749bd1d9a0SSven Peter return;
5759bd1d9a0SSven Peter
5769bd1d9a0SSven Peter work->rtk = rtk;
5779bd1d9a0SSven Peter work->ep = ep;
578*bb538effSHector Martin work->msg = msg.msg0;
5799bd1d9a0SSven Peter INIT_WORK(&work->work, apple_rtkit_rx_work);
5809bd1d9a0SSven Peter queue_work(rtk->wq, &work->work);
5819bd1d9a0SSven Peter }
5829bd1d9a0SSven Peter
apple_rtkit_send_message(struct apple_rtkit * rtk,u8 ep,u64 message,struct completion * completion,bool atomic)5839bd1d9a0SSven Peter int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
5849bd1d9a0SSven Peter struct completion *completion, bool atomic)
5859bd1d9a0SSven Peter {
586*bb538effSHector Martin struct apple_mbox_msg msg = {
587*bb538effSHector Martin .msg0 = message,
588*bb538effSHector Martin .msg1 = ep,
589*bb538effSHector Martin };
5909bd1d9a0SSven Peter
5919bd1d9a0SSven Peter if (rtk->crashed)
5929bd1d9a0SSven Peter return -EINVAL;
5939bd1d9a0SSven Peter if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
5949bd1d9a0SSven Peter !apple_rtkit_is_running(rtk))
5959bd1d9a0SSven Peter return -EINVAL;
5969bd1d9a0SSven Peter
5979bd1d9a0SSven Peter /*
5989bd1d9a0SSven Peter * The message will be sent with a MMIO write. We need the barrier
5999bd1d9a0SSven Peter * here to ensure any previous writes to buffers are visible to the
6009bd1d9a0SSven Peter * device before that MMIO write happens.
6019bd1d9a0SSven Peter */
6029bd1d9a0SSven Peter dma_wmb();
6039bd1d9a0SSven Peter
604*bb538effSHector Martin return apple_mbox_send(rtk->mbox, msg, atomic);
6059bd1d9a0SSven Peter }
6069bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_send_message);
6079bd1d9a0SSven Peter
apple_rtkit_poll(struct apple_rtkit * rtk)608f5a5e833SHector Martin int apple_rtkit_poll(struct apple_rtkit *rtk)
609f5a5e833SHector Martin {
610*bb538effSHector Martin return apple_mbox_poll(rtk->mbox);
611f5a5e833SHector Martin }
612f5a5e833SHector Martin EXPORT_SYMBOL_GPL(apple_rtkit_poll);
613f5a5e833SHector Martin
apple_rtkit_start_ep(struct apple_rtkit * rtk,u8 endpoint)6149bd1d9a0SSven Peter int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint)
6159bd1d9a0SSven Peter {
6169bd1d9a0SSven Peter u64 msg;
6179bd1d9a0SSven Peter
6189bd1d9a0SSven Peter if (!test_bit(endpoint, rtk->endpoints))
6199bd1d9a0SSven Peter return -EINVAL;
6209bd1d9a0SSven Peter if (endpoint >= APPLE_RTKIT_APP_ENDPOINT_START &&
6219bd1d9a0SSven Peter !apple_rtkit_is_running(rtk))
6229bd1d9a0SSven Peter return -EINVAL;
6239bd1d9a0SSven Peter
6249bd1d9a0SSven Peter msg = FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoint);
6259bd1d9a0SSven Peter msg |= APPLE_RTKIT_MGMT_STARTEP_FLAG;
6269bd1d9a0SSven Peter apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_STARTEP, msg);
6279bd1d9a0SSven Peter
6289bd1d9a0SSven Peter return 0;
6299bd1d9a0SSven Peter }
6309bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_start_ep);
6319bd1d9a0SSven Peter
apple_rtkit_init(struct device * dev,void * cookie,const char * mbox_name,int mbox_idx,const struct apple_rtkit_ops * ops)632b3892860SAsahi Lina struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
6339bd1d9a0SSven Peter const char *mbox_name, int mbox_idx,
6349bd1d9a0SSven Peter const struct apple_rtkit_ops *ops)
6359bd1d9a0SSven Peter {
6369bd1d9a0SSven Peter struct apple_rtkit *rtk;
6379bd1d9a0SSven Peter int ret;
6389bd1d9a0SSven Peter
6399bd1d9a0SSven Peter if (!ops)
6409bd1d9a0SSven Peter return ERR_PTR(-EINVAL);
6419bd1d9a0SSven Peter
6429bd1d9a0SSven Peter rtk = kzalloc(sizeof(*rtk), GFP_KERNEL);
6439bd1d9a0SSven Peter if (!rtk)
6449bd1d9a0SSven Peter return ERR_PTR(-ENOMEM);
6459bd1d9a0SSven Peter
6469bd1d9a0SSven Peter rtk->dev = dev;
6479bd1d9a0SSven Peter rtk->cookie = cookie;
6489bd1d9a0SSven Peter rtk->ops = ops;
6499bd1d9a0SSven Peter
6509bd1d9a0SSven Peter init_completion(&rtk->epmap_completion);
6519bd1d9a0SSven Peter init_completion(&rtk->iop_pwr_ack_completion);
6529bd1d9a0SSven Peter init_completion(&rtk->ap_pwr_ack_completion);
6539bd1d9a0SSven Peter
6549bd1d9a0SSven Peter bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS);
6559bd1d9a0SSven Peter set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints);
6569bd1d9a0SSven Peter
657*bb538effSHector Martin if (mbox_name)
658*bb538effSHector Martin rtk->mbox = apple_mbox_get_byname(dev, mbox_name);
659*bb538effSHector Martin else
660*bb538effSHector Martin rtk->mbox = apple_mbox_get(dev, mbox_idx);
661*bb538effSHector Martin
662*bb538effSHector Martin if (IS_ERR(rtk->mbox)) {
663*bb538effSHector Martin ret = PTR_ERR(rtk->mbox);
664*bb538effSHector Martin goto free_rtk;
665*bb538effSHector Martin }
666*bb538effSHector Martin
667*bb538effSHector Martin rtk->mbox->rx = apple_rtkit_rx;
668*bb538effSHector Martin rtk->mbox->cookie = rtk;
6699bd1d9a0SSven Peter
6709bd1d9a0SSven Peter rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM,
6719bd1d9a0SSven Peter dev_name(rtk->dev));
6729bd1d9a0SSven Peter if (!rtk->wq) {
6739bd1d9a0SSven Peter ret = -ENOMEM;
6749bd1d9a0SSven Peter goto free_rtk;
6759bd1d9a0SSven Peter }
6769bd1d9a0SSven Peter
677*bb538effSHector Martin ret = apple_mbox_start(rtk->mbox);
6789bd1d9a0SSven Peter if (ret)
6799bd1d9a0SSven Peter goto destroy_wq;
6809bd1d9a0SSven Peter
6819bd1d9a0SSven Peter return rtk;
6829bd1d9a0SSven Peter
6839bd1d9a0SSven Peter destroy_wq:
6849bd1d9a0SSven Peter destroy_workqueue(rtk->wq);
6859bd1d9a0SSven Peter free_rtk:
6869bd1d9a0SSven Peter kfree(rtk);
6879bd1d9a0SSven Peter return ERR_PTR(ret);
6889bd1d9a0SSven Peter }
689b3892860SAsahi Lina EXPORT_SYMBOL_GPL(apple_rtkit_init);
6909bd1d9a0SSven Peter
apple_rtkit_wait_for_completion(struct completion * c)6919bd1d9a0SSven Peter static int apple_rtkit_wait_for_completion(struct completion *c)
6929bd1d9a0SSven Peter {
6939bd1d9a0SSven Peter long t;
6949bd1d9a0SSven Peter
6959bd1d9a0SSven Peter t = wait_for_completion_interruptible_timeout(c,
6969bd1d9a0SSven Peter msecs_to_jiffies(1000));
6979bd1d9a0SSven Peter if (t < 0)
6989bd1d9a0SSven Peter return t;
6999bd1d9a0SSven Peter else if (t == 0)
7009bd1d9a0SSven Peter return -ETIME;
7019bd1d9a0SSven Peter else
7029bd1d9a0SSven Peter return 0;
7039bd1d9a0SSven Peter }
7049bd1d9a0SSven Peter
apple_rtkit_reinit(struct apple_rtkit * rtk)7059bd1d9a0SSven Peter int apple_rtkit_reinit(struct apple_rtkit *rtk)
7069bd1d9a0SSven Peter {
7079bd1d9a0SSven Peter /* make sure we don't handle any messages while reinitializing */
708*bb538effSHector Martin apple_mbox_stop(rtk->mbox);
7099bd1d9a0SSven Peter flush_workqueue(rtk->wq);
7109bd1d9a0SSven Peter
7119bd1d9a0SSven Peter apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
7129bd1d9a0SSven Peter apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer);
7139bd1d9a0SSven Peter apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer);
7149bd1d9a0SSven Peter
7159bd1d9a0SSven Peter kfree(rtk->syslog_msg_buffer);
7169bd1d9a0SSven Peter
7179bd1d9a0SSven Peter rtk->syslog_msg_buffer = NULL;
7189bd1d9a0SSven Peter rtk->syslog_n_entries = 0;
7199bd1d9a0SSven Peter rtk->syslog_msg_size = 0;
7209bd1d9a0SSven Peter
7219bd1d9a0SSven Peter bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS);
7229bd1d9a0SSven Peter set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints);
7239bd1d9a0SSven Peter
7249bd1d9a0SSven Peter reinit_completion(&rtk->epmap_completion);
7259bd1d9a0SSven Peter reinit_completion(&rtk->iop_pwr_ack_completion);
7269bd1d9a0SSven Peter reinit_completion(&rtk->ap_pwr_ack_completion);
7279bd1d9a0SSven Peter
7289bd1d9a0SSven Peter rtk->crashed = false;
7299bd1d9a0SSven Peter rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_OFF;
7309bd1d9a0SSven Peter rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_OFF;
7319bd1d9a0SSven Peter
732*bb538effSHector Martin return apple_mbox_start(rtk->mbox);
7339bd1d9a0SSven Peter }
7349bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_reinit);
7359bd1d9a0SSven Peter
apple_rtkit_set_ap_power_state(struct apple_rtkit * rtk,unsigned int state)7369bd1d9a0SSven Peter static int apple_rtkit_set_ap_power_state(struct apple_rtkit *rtk,
7379bd1d9a0SSven Peter unsigned int state)
7389bd1d9a0SSven Peter {
7399bd1d9a0SSven Peter u64 msg;
7409bd1d9a0SSven Peter int ret;
7419bd1d9a0SSven Peter
7429bd1d9a0SSven Peter reinit_completion(&rtk->ap_pwr_ack_completion);
7439bd1d9a0SSven Peter
7449bd1d9a0SSven Peter msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state);
7459bd1d9a0SSven Peter apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE,
7469bd1d9a0SSven Peter msg);
7479bd1d9a0SSven Peter
7489bd1d9a0SSven Peter ret = apple_rtkit_wait_for_completion(&rtk->ap_pwr_ack_completion);
7499bd1d9a0SSven Peter if (ret)
7509bd1d9a0SSven Peter return ret;
7519bd1d9a0SSven Peter
7529bd1d9a0SSven Peter if (rtk->ap_power_state != state)
7539bd1d9a0SSven Peter return -EINVAL;
7549bd1d9a0SSven Peter return 0;
7559bd1d9a0SSven Peter }
7569bd1d9a0SSven Peter
apple_rtkit_set_iop_power_state(struct apple_rtkit * rtk,unsigned int state)7579bd1d9a0SSven Peter static int apple_rtkit_set_iop_power_state(struct apple_rtkit *rtk,
7589bd1d9a0SSven Peter unsigned int state)
7599bd1d9a0SSven Peter {
7609bd1d9a0SSven Peter u64 msg;
7619bd1d9a0SSven Peter int ret;
7629bd1d9a0SSven Peter
7639bd1d9a0SSven Peter reinit_completion(&rtk->iop_pwr_ack_completion);
7649bd1d9a0SSven Peter
7659bd1d9a0SSven Peter msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state);
7669bd1d9a0SSven Peter apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
7679bd1d9a0SSven Peter msg);
7689bd1d9a0SSven Peter
7699bd1d9a0SSven Peter ret = apple_rtkit_wait_for_completion(&rtk->iop_pwr_ack_completion);
7709bd1d9a0SSven Peter if (ret)
7719bd1d9a0SSven Peter return ret;
7729bd1d9a0SSven Peter
7739bd1d9a0SSven Peter if (rtk->iop_power_state != state)
7749bd1d9a0SSven Peter return -EINVAL;
7759bd1d9a0SSven Peter return 0;
7769bd1d9a0SSven Peter }
7779bd1d9a0SSven Peter
apple_rtkit_boot(struct apple_rtkit * rtk)7789bd1d9a0SSven Peter int apple_rtkit_boot(struct apple_rtkit *rtk)
7799bd1d9a0SSven Peter {
7809bd1d9a0SSven Peter int ret;
7819bd1d9a0SSven Peter
7829bd1d9a0SSven Peter if (apple_rtkit_is_running(rtk))
7839bd1d9a0SSven Peter return 0;
7849bd1d9a0SSven Peter if (rtk->crashed)
7859bd1d9a0SSven Peter return -EINVAL;
7869bd1d9a0SSven Peter
7879bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: waiting for boot to finish\n");
7889bd1d9a0SSven Peter ret = apple_rtkit_wait_for_completion(&rtk->epmap_completion);
7899bd1d9a0SSven Peter if (ret)
7909bd1d9a0SSven Peter return ret;
7919bd1d9a0SSven Peter if (rtk->boot_result)
7929bd1d9a0SSven Peter return rtk->boot_result;
7939bd1d9a0SSven Peter
7949bd1d9a0SSven Peter dev_dbg(rtk->dev, "RTKit: waiting for IOP power state ACK\n");
7959bd1d9a0SSven Peter ret = apple_rtkit_wait_for_completion(&rtk->iop_pwr_ack_completion);
7969bd1d9a0SSven Peter if (ret)
7979bd1d9a0SSven Peter return ret;
7989bd1d9a0SSven Peter
7999bd1d9a0SSven Peter return apple_rtkit_set_ap_power_state(rtk, APPLE_RTKIT_PWR_STATE_ON);
8009bd1d9a0SSven Peter }
8019bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_boot);
8029bd1d9a0SSven Peter
apple_rtkit_shutdown(struct apple_rtkit * rtk)8039bd1d9a0SSven Peter int apple_rtkit_shutdown(struct apple_rtkit *rtk)
8049bd1d9a0SSven Peter {
8059bd1d9a0SSven Peter int ret;
8069bd1d9a0SSven Peter
8079bd1d9a0SSven Peter /* if OFF is used here the co-processor will not wake up again */
8089bd1d9a0SSven Peter ret = apple_rtkit_set_ap_power_state(rtk,
8099bd1d9a0SSven Peter APPLE_RTKIT_PWR_STATE_QUIESCED);
8109bd1d9a0SSven Peter if (ret)
8119bd1d9a0SSven Peter return ret;
8129bd1d9a0SSven Peter
8139bd1d9a0SSven Peter ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_SLEEP);
8149bd1d9a0SSven Peter if (ret)
8159bd1d9a0SSven Peter return ret;
8169bd1d9a0SSven Peter
8179bd1d9a0SSven Peter return apple_rtkit_reinit(rtk);
8189bd1d9a0SSven Peter }
8199bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_shutdown);
8209bd1d9a0SSven Peter
apple_rtkit_idle(struct apple_rtkit * rtk)82140eaa8c0SHector Martin int apple_rtkit_idle(struct apple_rtkit *rtk)
82240eaa8c0SHector Martin {
82340eaa8c0SHector Martin int ret;
82440eaa8c0SHector Martin
82540eaa8c0SHector Martin /* if OFF is used here the co-processor will not wake up again */
82640eaa8c0SHector Martin ret = apple_rtkit_set_ap_power_state(rtk,
82740eaa8c0SHector Martin APPLE_RTKIT_PWR_STATE_IDLE);
82840eaa8c0SHector Martin if (ret)
82940eaa8c0SHector Martin return ret;
83040eaa8c0SHector Martin
83140eaa8c0SHector Martin ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_IDLE);
83240eaa8c0SHector Martin if (ret)
83340eaa8c0SHector Martin return ret;
83440eaa8c0SHector Martin
83540eaa8c0SHector Martin rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_IDLE;
83640eaa8c0SHector Martin rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_IDLE;
83740eaa8c0SHector Martin return 0;
83840eaa8c0SHector Martin }
83940eaa8c0SHector Martin EXPORT_SYMBOL_GPL(apple_rtkit_idle);
84040eaa8c0SHector Martin
apple_rtkit_quiesce(struct apple_rtkit * rtk)8419bd1d9a0SSven Peter int apple_rtkit_quiesce(struct apple_rtkit *rtk)
8429bd1d9a0SSven Peter {
8439bd1d9a0SSven Peter int ret;
8449bd1d9a0SSven Peter
8459bd1d9a0SSven Peter ret = apple_rtkit_set_ap_power_state(rtk,
8469bd1d9a0SSven Peter APPLE_RTKIT_PWR_STATE_QUIESCED);
8479bd1d9a0SSven Peter if (ret)
8489bd1d9a0SSven Peter return ret;
8499bd1d9a0SSven Peter
8509bd1d9a0SSven Peter ret = apple_rtkit_set_iop_power_state(rtk,
8519bd1d9a0SSven Peter APPLE_RTKIT_PWR_STATE_QUIESCED);
8529bd1d9a0SSven Peter if (ret)
8539bd1d9a0SSven Peter return ret;
8549bd1d9a0SSven Peter
8559bd1d9a0SSven Peter ret = apple_rtkit_reinit(rtk);
8569bd1d9a0SSven Peter if (ret)
8579bd1d9a0SSven Peter return ret;
8589bd1d9a0SSven Peter
8599bd1d9a0SSven Peter rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED;
8609bd1d9a0SSven Peter rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED;
8619bd1d9a0SSven Peter return 0;
8629bd1d9a0SSven Peter }
8639bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_quiesce);
8649bd1d9a0SSven Peter
apple_rtkit_wake(struct apple_rtkit * rtk)8659bd1d9a0SSven Peter int apple_rtkit_wake(struct apple_rtkit *rtk)
8669bd1d9a0SSven Peter {
8679bd1d9a0SSven Peter u64 msg;
8689bd1d9a0SSven Peter
8699bd1d9a0SSven Peter if (apple_rtkit_is_running(rtk))
8709bd1d9a0SSven Peter return -EINVAL;
8719bd1d9a0SSven Peter
8729bd1d9a0SSven Peter reinit_completion(&rtk->iop_pwr_ack_completion);
8739bd1d9a0SSven Peter
8749bd1d9a0SSven Peter /*
8759bd1d9a0SSven Peter * Use open-coded apple_rtkit_set_iop_power_state since apple_rtkit_boot
8769bd1d9a0SSven Peter * will wait for the completion anyway.
8779bd1d9a0SSven Peter */
8789bd1d9a0SSven Peter msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
8799bd1d9a0SSven Peter apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
8809bd1d9a0SSven Peter msg);
8819bd1d9a0SSven Peter
8829bd1d9a0SSven Peter return apple_rtkit_boot(rtk);
8839bd1d9a0SSven Peter }
8849bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(apple_rtkit_wake);
8859bd1d9a0SSven Peter
apple_rtkit_free(struct apple_rtkit * rtk)886b3892860SAsahi Lina void apple_rtkit_free(struct apple_rtkit *rtk)
8879bd1d9a0SSven Peter {
888*bb538effSHector Martin apple_mbox_stop(rtk->mbox);
8899bd1d9a0SSven Peter destroy_workqueue(rtk->wq);
8909bd1d9a0SSven Peter
8919bd1d9a0SSven Peter apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
8929bd1d9a0SSven Peter apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer);
8939bd1d9a0SSven Peter apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer);
8949bd1d9a0SSven Peter
8959bd1d9a0SSven Peter kfree(rtk->syslog_msg_buffer);
8969bd1d9a0SSven Peter kfree(rtk);
8979bd1d9a0SSven Peter }
898b3892860SAsahi Lina EXPORT_SYMBOL_GPL(apple_rtkit_free);
899b3892860SAsahi Lina
apple_rtkit_free_wrapper(void * data)900b3892860SAsahi Lina static void apple_rtkit_free_wrapper(void *data)
901b3892860SAsahi Lina {
902b3892860SAsahi Lina apple_rtkit_free(data);
903b3892860SAsahi Lina }
9049bd1d9a0SSven Peter
devm_apple_rtkit_init(struct device * dev,void * cookie,const char * mbox_name,int mbox_idx,const struct apple_rtkit_ops * ops)9059bd1d9a0SSven Peter struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie,
9069bd1d9a0SSven Peter const char *mbox_name, int mbox_idx,
9079bd1d9a0SSven Peter const struct apple_rtkit_ops *ops)
9089bd1d9a0SSven Peter {
9099bd1d9a0SSven Peter struct apple_rtkit *rtk;
9109bd1d9a0SSven Peter int ret;
9119bd1d9a0SSven Peter
9129bd1d9a0SSven Peter rtk = apple_rtkit_init(dev, cookie, mbox_name, mbox_idx, ops);
9139bd1d9a0SSven Peter if (IS_ERR(rtk))
9149bd1d9a0SSven Peter return rtk;
9159bd1d9a0SSven Peter
916b3892860SAsahi Lina ret = devm_add_action_or_reset(dev, apple_rtkit_free_wrapper, rtk);
9179bd1d9a0SSven Peter if (ret)
9189bd1d9a0SSven Peter return ERR_PTR(ret);
9199bd1d9a0SSven Peter
9209bd1d9a0SSven Peter return rtk;
9219bd1d9a0SSven Peter }
9229bd1d9a0SSven Peter EXPORT_SYMBOL_GPL(devm_apple_rtkit_init);
9239bd1d9a0SSven Peter
9249bd1d9a0SSven Peter MODULE_LICENSE("Dual MIT/GPL");
9259bd1d9a0SSven Peter MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
9269bd1d9a0SSven Peter MODULE_DESCRIPTION("Apple RTKit driver");
927