blob: 5e8e282ec0e2a7338b7100825019645e39fdb02f [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>
Hector Martin0b9e2da2025-04-20 13:58:04 +020014#include <linux/sizes.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060015#include <linux/types.h>
Mark Kettenis72d73012022-01-22 20:38:14 +010016
17#define APPLE_RTKIT_EP_MGMT 0
18#define APPLE_RTKIT_EP_CRASHLOG 1
19#define APPLE_RTKIT_EP_SYSLOG 2
20#define APPLE_RTKIT_EP_DEBUG 3
21#define APPLE_RTKIT_EP_IOREPORT 4
Janne Grunaue3a438f2022-06-14 09:09:07 +020022#define APPLE_RTKIT_EP_TRACEKIT 10
Mark Kettenis72d73012022-01-22 20:38:14 +010023
24/* Messages for management endpoint. */
25#define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52)
26
27#define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0)
28
29#define APPLE_RTKIT_MGMT_HELLO 1
30#define APPLE_RTKIT_MGMT_HELLO_REPLY 2
31#define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0)
32#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16)
33
34#define APPLE_RTKIT_MGMT_STARTEP 5
35#define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32)
36#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1)
37
38#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6
39#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7
Hector Martinaa4e96b2025-04-20 13:58:03 +020040#define APPLE_RTKIT_MGMT_SET_AP_PWR_STATE 11
Mark Kettenis72d73012022-01-22 20:38:14 +010041
42#define APPLE_RTKIT_MGMT_EPMAP 8
43#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
44#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
45#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
46
47#define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
48#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
49
50#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
51#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
52
53/* Messages for internal endpoints. */
54#define APPLE_RTKIT_BUFFER_REQUEST 1
55#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
56#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
57
Janne Grunau16eda4e2022-06-14 09:09:09 +020058#define TIMEOUT_1SEC_US 1000000
59
Janne Grunaue3a438f2022-06-14 09:09:07 +020060struct apple_rtkit {
61 struct mbox_chan *chan;
62 void *cookie;
63 apple_rtkit_shmem_setup shmem_setup;
64 apple_rtkit_shmem_destroy shmem_destroy;
65
66 struct apple_rtkit_buffer syslog_buffer;
67 struct apple_rtkit_buffer crashlog_buffer;
68 struct apple_rtkit_buffer ioreport_buffer;
Hector Martinaa4e96b2025-04-20 13:58:03 +020069
70 int iop_pwr;
71 int ap_pwr;
Janne Grunaue3a438f2022-06-14 09:09:07 +020072};
73
74struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie,
75 apple_rtkit_shmem_setup shmem_setup,
76 apple_rtkit_shmem_destroy shmem_destroy)
77{
78 struct apple_rtkit *rtk;
79
80 rtk = calloc(sizeof(*rtk), 1);
81 if (!rtk)
82 return NULL;
83
84 rtk->chan = chan;
85 rtk->cookie = cookie;
86 rtk->shmem_setup = shmem_setup;
87 rtk->shmem_destroy = shmem_destroy;
88
89 return rtk;
90}
91
92void apple_rtkit_free(struct apple_rtkit *rtk)
93{
94 if (rtk->shmem_destroy) {
95 if (rtk->syslog_buffer.buffer)
96 rtk->shmem_destroy(rtk->cookie, &rtk->syslog_buffer);
97 if (rtk->crashlog_buffer.buffer)
98 rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer);
99 if (rtk->ioreport_buffer.buffer)
100 rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer);
Hector Martin0b9e2da2025-04-20 13:58:04 +0200101 } else {
102 if (rtk->syslog_buffer.buffer)
103 free(rtk->syslog_buffer.buffer);
104 if (rtk->crashlog_buffer.buffer)
105 free(rtk->crashlog_buffer.buffer);
106 if (rtk->ioreport_buffer.buffer)
107 free(rtk->ioreport_buffer.buffer);
Janne Grunaue3a438f2022-06-14 09:09:07 +0200108 }
109 free(rtk);
110}
111
112static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg)
113{
114 struct apple_rtkit_buffer *buf;
115 size_t num_4kpages;
116 int ret;
117
118 num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0);
119
120 if (num_4kpages == 0) {
121 printf("%s: unexpected request for buffer without size\n", __func__);
122 return -1;
123 }
124
125 switch (endpoint) {
126 case APPLE_RTKIT_EP_CRASHLOG:
127 buf = &rtk->crashlog_buffer;
128 break;
129 case APPLE_RTKIT_EP_SYSLOG:
130 buf = &rtk->syslog_buffer;
131 break;
132 case APPLE_RTKIT_EP_IOREPORT:
133 buf = &rtk->ioreport_buffer;
134 break;
135 default:
136 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
137 return -1;
138 }
139
140 buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0);
141 buf->size = num_4kpages << 12;
Hector Martin0b9e2da2025-04-20 13:58:04 +0200142 buf->is_mapped = !!buf->dva;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200143
144 if (rtk->shmem_setup) {
145 ret = rtk->shmem_setup(rtk->cookie, buf);
146 if (ret < 0) {
147 printf("%s: shmen_setup failed for endpoint %d\n", __func__,
148 endpoint);
149 return ret;
150 }
Hector Martin0b9e2da2025-04-20 13:58:04 +0200151 } else if (!buf->is_mapped){
152 buf->buffer = memalign(SZ_16K, ALIGN(buf->size, SZ_16K));
153 if (!buf->buffer)
154 return -ENOMEM;
155
156 buf->dva = (u64)buf->buffer;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200157 }
158
159 if (!buf->is_mapped) {
160 msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
161 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) |
162 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva);
163 msg->msg1 = endpoint;
164
165 return mbox_send(rtk->chan, msg);
166 }
167
168 return 0;
169}
170
Hector Martinaa4e96b2025-04-20 13:58:03 +0200171int apple_rtkit_poll(struct apple_rtkit *rtk, ulong timeout)
172{
173 struct apple_mbox_msg msg;
174 int ret;
175 int endpoint;
176 int msgtype;
177
178 ret = mbox_recv(rtk->chan, &msg, timeout);
179 if (ret < 0)
180 return ret;
181
182 endpoint = msg.msg1;
183 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
184
185 if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
186 endpoint == APPLE_RTKIT_EP_SYSLOG ||
187 endpoint == APPLE_RTKIT_EP_IOREPORT) {
188 if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) {
189 ret = rtkit_handle_buf_req(rtk, endpoint, &msg);
190 if (ret < 0)
191 return ret;
192 return 0;
193 }
194 }
195
196 if (endpoint == APPLE_RTKIT_EP_IOREPORT) {
197 // these two messages have to be ack-ed for proper startup
198 if (msgtype == 0xc || msgtype == 0x8) {
199 ret = mbox_send(rtk->chan, &msg);
200 if (ret < 0)
201 return ret;
202 return 0;
203 }
204 }
205
206 if (endpoint == APPLE_RTKIT_EP_SYSLOG) {
207 /* Ignore init */
208 if (msgtype == 0x8)
209 return 0;
210
211 /* Ack logs */
212 if (msgtype == 0x5) {
213 ret = mbox_send(rtk->chan, &msg);
214 if (ret < 0)
215 return ret;
216 return 0;
217 }
218 }
219
220 if (endpoint != APPLE_RTKIT_EP_MGMT) {
221 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
222 return -EINVAL;
223 }
224
225 switch (msgtype) {
226 case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK:
227 rtk->iop_pwr = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
228 return 0;
229 case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE:
230 rtk->ap_pwr = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
231 return 0;
232 default:
233 printf("%s: unexpected message type %d\n", __func__, msgtype);
234
235 /* Just ignore it */
236 return 0;
237 }
238}
239
Janne Grunaue3a438f2022-06-14 09:09:07 +0200240int apple_rtkit_boot(struct apple_rtkit *rtk)
Mark Kettenis72d73012022-01-22 20:38:14 +0100241{
242 struct apple_mbox_msg msg;
243 int endpoints[256];
244 int nendpoints = 0;
245 int endpoint;
246 int min_ver, max_ver, want_ver;
Hector Martinaa4e96b2025-04-20 13:58:03 +0200247 int msgtype;
Mark Kettenis72d73012022-01-22 20:38:14 +0100248 u64 reply;
249 u32 bitmap, base;
250 int i, ret;
251
252 /* Wakup the IOP. */
253 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
254 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
255 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200256 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100257 if (ret < 0)
258 return ret;
259
260 /* Wait for protocol version negotiation message. */
Janne Grunau16eda4e2022-06-14 09:09:09 +0200261 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100262 if (ret < 0)
263 return ret;
264
265 endpoint = msg.msg1;
266 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
267 if (endpoint != APPLE_RTKIT_EP_MGMT) {
268 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
269 return -EINVAL;
270 }
271 if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
272 printf("%s: unexpected message type %d\n", __func__, msgtype);
273 return -EINVAL;
274 }
275
276 min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
277 max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
278 want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
279
280 if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
281 printf("%s: firmware min version %d is too new\n",
282 __func__, min_ver);
283 return -ENOTSUPP;
284 }
285
286 if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
287 printf("%s: firmware max version %d is too old\n",
288 __func__, max_ver);
289 return -ENOTSUPP;
290 }
291
292 /* Ack version. */
293 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
294 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
295 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
296 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200297 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100298 if (ret < 0)
299 return ret;
300
301wait_epmap:
302 /* Wait for endpoint map message. */
Janne Grunau16eda4e2022-06-14 09:09:09 +0200303 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100304 if (ret < 0)
305 return ret;
306
307 endpoint = msg.msg1;
308 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
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_EPMAP) {
314 printf("%s: unexpected message type %d\n", __func__, msgtype);
315 return -EINVAL;
316 }
317
318 bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
319 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
320 for (i = 0; i < 32; i++) {
321 if (bitmap & (1U << i))
322 endpoints[nendpoints++] = base * 32 + i;
323 }
324
325 /* Ack endpoint map. */
326 reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
327 FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
328 if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
329 reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
330 else
331 reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
332 msg.msg0 = reply;
333 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200334 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100335 if (ret < 0)
336 return ret;
337
338 if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
339 goto wait_epmap;
340
341 for (i = 0; i < nendpoints; i++) {
Janne Grunaue3a438f2022-06-14 09:09:07 +0200342 /* Start only necessary endpoints. The syslog endpoint is
343 * particularly noisy and its message can't easily be handled
344 * within U-Boot.
345 */
346 switch (endpoints[i]) {
347 case APPLE_RTKIT_EP_MGMT:
348 case APPLE_RTKIT_EP_SYSLOG:
349 case APPLE_RTKIT_EP_DEBUG:
350 case APPLE_RTKIT_EP_TRACEKIT:
Mark Kettenis72d73012022-01-22 20:38:14 +0100351 continue;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200352 default:
353 break;
354 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100355
356 /* Request endpoint. */
357 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
358 FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
359 APPLE_RTKIT_MGMT_STARTEP_FLAG;
360 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200361 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100362 if (ret < 0)
363 return ret;
364 }
365
Hector Martinaa4e96b2025-04-20 13:58:03 +0200366 rtk->iop_pwr = APPLE_RTKIT_PWR_STATE_SLEEP;
367 rtk->ap_pwr = APPLE_RTKIT_PWR_STATE_QUIESCED;
368
369 while (rtk->iop_pwr != APPLE_RTKIT_PWR_STATE_ON) {
370 ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100371 if (ret < 0)
372 return ret;
Hector Martinaa4e96b2025-04-20 13:58:03 +0200373 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100374
Hector Martinaa4e96b2025-04-20 13:58:03 +0200375 return 0;
376}
Mark Kettenis72d73012022-01-22 20:38:14 +0100377
Hector Martinaa4e96b2025-04-20 13:58:03 +0200378int apple_rtkit_set_ap_power(struct apple_rtkit *rtk, int pwrstate)
379{
380 struct apple_mbox_msg msg;
381 int ret;
Mark Kettenis72d73012022-01-22 20:38:14 +0100382
Hector Martinaa4e96b2025-04-20 13:58:03 +0200383 if (rtk->ap_pwr == pwrstate)
384 return 0;
Mark Kettenis72d73012022-01-22 20:38:14 +0100385
Hector Martinaa4e96b2025-04-20 13:58:03 +0200386 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE) |
387 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
388 msg.msg1 = APPLE_RTKIT_EP_MGMT;
389 ret = mbox_send(rtk->chan, &msg);
390 if (ret < 0)
391 return ret;
Mark Kettenis72d73012022-01-22 20:38:14 +0100392
Hector Martinaa4e96b2025-04-20 13:58:03 +0200393 while (rtk->ap_pwr != pwrstate) {
394 ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US);
395 if (ret < 0)
396 return ret;
Mark Kettenis72d73012022-01-22 20:38:14 +0100397 }
398
399 return 0;
400}
401
Janne Grunaue3a438f2022-06-14 09:09:07 +0200402int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate)
Mark Kettenis72d73012022-01-22 20:38:14 +0100403{
404 struct apple_mbox_msg msg;
405 int ret;
406
Hector Martinaa4e96b2025-04-20 13:58:03 +0200407 if (rtk->ap_pwr != APPLE_RTKIT_PWR_STATE_QUIESCED) {
408 ret = apple_rtkit_set_ap_power(rtk, APPLE_RTKIT_PWR_STATE_QUIESCED);
409 if (ret < 0)
410 return ret;
411 }
412
Mark Kettenis72d73012022-01-22 20:38:14 +0100413 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
414 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
415 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200416 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100417 if (ret < 0)
418 return ret;
419
Hector Martinaa4e96b2025-04-20 13:58:03 +0200420 while (rtk->iop_pwr != pwrstate) {
421 ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US);
422 if (ret < 0)
423 return ret;
424 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100425
426 return 0;
427}