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