blob: b8f4771e5e71928db9152a3dec301730ae8195d8 [file] [log] [blame]
Mark Kettenis72d73012022-01-22 20:38:14 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
4 * (C) Copyright 2021 Copyright The Asahi Linux Contributors
5 */
6
Mark Kettenis72d73012022-01-22 20:38:14 +01007#include <mailbox.h>
8#include <malloc.h>
9
10#include <asm/arch/rtkit.h>
11#include <linux/apple-mailbox.h>
12#include <linux/bitfield.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060013#include <linux/errno.h>
14#include <linux/types.h>
Mark Kettenis72d73012022-01-22 20:38:14 +010015
16#define APPLE_RTKIT_EP_MGMT 0
17#define APPLE_RTKIT_EP_CRASHLOG 1
18#define APPLE_RTKIT_EP_SYSLOG 2
19#define APPLE_RTKIT_EP_DEBUG 3
20#define APPLE_RTKIT_EP_IOREPORT 4
Janne Grunaue3a438f2022-06-14 09:09:07 +020021#define APPLE_RTKIT_EP_TRACEKIT 10
Mark Kettenis72d73012022-01-22 20:38:14 +010022
23/* Messages for management endpoint. */
24#define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52)
25
26#define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0)
27
28#define APPLE_RTKIT_MGMT_HELLO 1
29#define APPLE_RTKIT_MGMT_HELLO_REPLY 2
30#define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0)
31#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16)
32
33#define APPLE_RTKIT_MGMT_STARTEP 5
34#define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32)
35#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1)
36
37#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6
38#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7
39
40#define APPLE_RTKIT_MGMT_EPMAP 8
41#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
42#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
43#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
44
45#define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
46#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
47
48#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
49#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
50
51/* Messages for internal endpoints. */
52#define APPLE_RTKIT_BUFFER_REQUEST 1
53#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
54#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
55
Janne Grunau16eda4e2022-06-14 09:09:09 +020056#define TIMEOUT_1SEC_US 1000000
57
Janne Grunaue3a438f2022-06-14 09:09:07 +020058struct apple_rtkit {
59 struct mbox_chan *chan;
60 void *cookie;
61 apple_rtkit_shmem_setup shmem_setup;
62 apple_rtkit_shmem_destroy shmem_destroy;
63
64 struct apple_rtkit_buffer syslog_buffer;
65 struct apple_rtkit_buffer crashlog_buffer;
66 struct apple_rtkit_buffer ioreport_buffer;
67};
68
69struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie,
70 apple_rtkit_shmem_setup shmem_setup,
71 apple_rtkit_shmem_destroy shmem_destroy)
72{
73 struct apple_rtkit *rtk;
74
75 rtk = calloc(sizeof(*rtk), 1);
76 if (!rtk)
77 return NULL;
78
79 rtk->chan = chan;
80 rtk->cookie = cookie;
81 rtk->shmem_setup = shmem_setup;
82 rtk->shmem_destroy = shmem_destroy;
83
84 return rtk;
85}
86
87void apple_rtkit_free(struct apple_rtkit *rtk)
88{
89 if (rtk->shmem_destroy) {
90 if (rtk->syslog_buffer.buffer)
91 rtk->shmem_destroy(rtk->cookie, &rtk->syslog_buffer);
92 if (rtk->crashlog_buffer.buffer)
93 rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer);
94 if (rtk->ioreport_buffer.buffer)
95 rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer);
96 }
97 free(rtk);
98}
99
100static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg)
101{
102 struct apple_rtkit_buffer *buf;
103 size_t num_4kpages;
104 int ret;
105
106 num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0);
107
108 if (num_4kpages == 0) {
109 printf("%s: unexpected request for buffer without size\n", __func__);
110 return -1;
111 }
112
113 switch (endpoint) {
114 case APPLE_RTKIT_EP_CRASHLOG:
115 buf = &rtk->crashlog_buffer;
116 break;
117 case APPLE_RTKIT_EP_SYSLOG:
118 buf = &rtk->syslog_buffer;
119 break;
120 case APPLE_RTKIT_EP_IOREPORT:
121 buf = &rtk->ioreport_buffer;
122 break;
123 default:
124 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
125 return -1;
126 }
127
128 buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0);
129 buf->size = num_4kpages << 12;
130 buf->is_mapped = false;
131
132 if (rtk->shmem_setup) {
133 ret = rtk->shmem_setup(rtk->cookie, buf);
134 if (ret < 0) {
135 printf("%s: shmen_setup failed for endpoint %d\n", __func__,
136 endpoint);
137 return ret;
138 }
139 }
140
141 if (!buf->is_mapped) {
142 msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
143 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) |
144 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva);
145 msg->msg1 = endpoint;
146
147 return mbox_send(rtk->chan, msg);
148 }
149
150 return 0;
151}
152
153int apple_rtkit_boot(struct apple_rtkit *rtk)
Mark Kettenis72d73012022-01-22 20:38:14 +0100154{
155 struct apple_mbox_msg msg;
156 int endpoints[256];
157 int nendpoints = 0;
158 int endpoint;
159 int min_ver, max_ver, want_ver;
160 int msgtype, pwrstate;
161 u64 reply;
162 u32 bitmap, base;
163 int i, ret;
164
165 /* Wakup the IOP. */
166 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
167 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
168 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200169 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100170 if (ret < 0)
171 return ret;
172
173 /* Wait for protocol version negotiation message. */
Janne Grunau16eda4e2022-06-14 09:09:09 +0200174 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100175 if (ret < 0)
176 return ret;
177
178 endpoint = msg.msg1;
179 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
180 if (endpoint != APPLE_RTKIT_EP_MGMT) {
181 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
182 return -EINVAL;
183 }
184 if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
185 printf("%s: unexpected message type %d\n", __func__, msgtype);
186 return -EINVAL;
187 }
188
189 min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
190 max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
191 want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
192
193 if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
194 printf("%s: firmware min version %d is too new\n",
195 __func__, min_ver);
196 return -ENOTSUPP;
197 }
198
199 if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
200 printf("%s: firmware max version %d is too old\n",
201 __func__, max_ver);
202 return -ENOTSUPP;
203 }
204
205 /* Ack version. */
206 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
207 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
208 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
209 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200210 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100211 if (ret < 0)
212 return ret;
213
214wait_epmap:
215 /* Wait for endpoint map message. */
Janne Grunau16eda4e2022-06-14 09:09:09 +0200216 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100217 if (ret < 0)
218 return ret;
219
220 endpoint = msg.msg1;
221 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
222 if (endpoint != APPLE_RTKIT_EP_MGMT) {
223 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
224 return -EINVAL;
225 }
226 if (msgtype != APPLE_RTKIT_MGMT_EPMAP) {
227 printf("%s: unexpected message type %d\n", __func__, msgtype);
228 return -EINVAL;
229 }
230
231 bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
232 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
233 for (i = 0; i < 32; i++) {
234 if (bitmap & (1U << i))
235 endpoints[nendpoints++] = base * 32 + i;
236 }
237
238 /* Ack endpoint map. */
239 reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
240 FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
241 if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
242 reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
243 else
244 reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
245 msg.msg0 = reply;
246 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200247 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100248 if (ret < 0)
249 return ret;
250
251 if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
252 goto wait_epmap;
253
254 for (i = 0; i < nendpoints; i++) {
Janne Grunaue3a438f2022-06-14 09:09:07 +0200255 /* Start only necessary endpoints. The syslog endpoint is
256 * particularly noisy and its message can't easily be handled
257 * within U-Boot.
258 */
259 switch (endpoints[i]) {
260 case APPLE_RTKIT_EP_MGMT:
261 case APPLE_RTKIT_EP_SYSLOG:
262 case APPLE_RTKIT_EP_DEBUG:
263 case APPLE_RTKIT_EP_TRACEKIT:
Mark Kettenis72d73012022-01-22 20:38:14 +0100264 continue;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200265 default:
266 break;
267 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100268
269 /* Request endpoint. */
270 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
271 FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
272 APPLE_RTKIT_MGMT_STARTEP_FLAG;
273 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200274 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100275 if (ret < 0)
276 return ret;
277 }
278
279 pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP;
280 while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) {
Janne Grunau16eda4e2022-06-14 09:09:09 +0200281 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100282 if (ret < 0)
283 return ret;
284
285 endpoint = msg.msg1;
286 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
287
288 if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
289 endpoint == APPLE_RTKIT_EP_SYSLOG ||
290 endpoint == APPLE_RTKIT_EP_IOREPORT) {
Janne Grunaue3a438f2022-06-14 09:09:07 +0200291 if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) {
292 ret = rtkit_handle_buf_req(rtk, endpoint, &msg);
293 if (ret < 0)
294 return ret;
Mark Kettenis72d73012022-01-22 20:38:14 +0100295 continue;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200296 }
297 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100298
Janne Grunaue3a438f2022-06-14 09:09:07 +0200299 if (endpoint == APPLE_RTKIT_EP_IOREPORT) {
300 // these two messages have to be ack-ed for proper startup
301 if (msgtype == 0xc || msgtype == 0x8) {
302 ret = mbox_send(rtk->chan, &msg);
303 if (ret < 0)
304 return ret;
305 continue;
306 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100307 }
308
309 if (endpoint != APPLE_RTKIT_EP_MGMT) {
310 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
311 return -EINVAL;
312 }
313 if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) {
314 printf("%s: unexpected message type %d\n", __func__, msgtype);
315 return -EINVAL;
316 }
317
318 pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
319 }
320
321 return 0;
322}
323
Janne Grunaue3a438f2022-06-14 09:09:07 +0200324int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate)
Mark Kettenis72d73012022-01-22 20:38:14 +0100325{
326 struct apple_mbox_msg msg;
327 int ret;
328
329 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
330 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
331 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200332 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100333 if (ret < 0)
334 return ret;
335
Janne Grunau16eda4e2022-06-14 09:09:09 +0200336 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100337 if (ret < 0)
338 return ret;
339
340 return 0;
341}