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