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