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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 900b3892860SAsahi Lina static void apple_rtkit_free_wrapper(void *data) 901b3892860SAsahi Lina { 902b3892860SAsahi Lina apple_rtkit_free(data); 903b3892860SAsahi Lina } 9049bd1d9a0SSven Peter 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