xref: /linux/drivers/soc/apple/rtkit.c (revision b3892860f50920ea46342d32bf51323877365082)
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