blob: 433ffb259eed7f5b745af0c4dc06939c1f9cab0a [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
Hector Martinaa4e96b2025-04-20 13:58:03 +020039#define APPLE_RTKIT_MGMT_SET_AP_PWR_STATE 11
Mark Kettenis72d73012022-01-22 20:38:14 +010040
41#define APPLE_RTKIT_MGMT_EPMAP 8
42#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
43#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
44#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
45
46#define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
47#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
48
49#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
50#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
51
52/* Messages for internal endpoints. */
53#define APPLE_RTKIT_BUFFER_REQUEST 1
54#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
55#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
56
Janne Grunau16eda4e2022-06-14 09:09:09 +020057#define TIMEOUT_1SEC_US 1000000
58
Janne Grunaue3a438f2022-06-14 09:09:07 +020059struct apple_rtkit {
60 struct mbox_chan *chan;
61 void *cookie;
62 apple_rtkit_shmem_setup shmem_setup;
63 apple_rtkit_shmem_destroy shmem_destroy;
64
65 struct apple_rtkit_buffer syslog_buffer;
66 struct apple_rtkit_buffer crashlog_buffer;
67 struct apple_rtkit_buffer ioreport_buffer;
Hector Martinaa4e96b2025-04-20 13:58:03 +020068
69 int iop_pwr;
70 int ap_pwr;
Janne Grunaue3a438f2022-06-14 09:09:07 +020071};
72
73struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie,
74 apple_rtkit_shmem_setup shmem_setup,
75 apple_rtkit_shmem_destroy shmem_destroy)
76{
77 struct apple_rtkit *rtk;
78
79 rtk = calloc(sizeof(*rtk), 1);
80 if (!rtk)
81 return NULL;
82
83 rtk->chan = chan;
84 rtk->cookie = cookie;
85 rtk->shmem_setup = shmem_setup;
86 rtk->shmem_destroy = shmem_destroy;
87
88 return rtk;
89}
90
91void apple_rtkit_free(struct apple_rtkit *rtk)
92{
93 if (rtk->shmem_destroy) {
94 if (rtk->syslog_buffer.buffer)
95 rtk->shmem_destroy(rtk->cookie, &rtk->syslog_buffer);
96 if (rtk->crashlog_buffer.buffer)
97 rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer);
98 if (rtk->ioreport_buffer.buffer)
99 rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer);
100 }
101 free(rtk);
102}
103
104static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg)
105{
106 struct apple_rtkit_buffer *buf;
107 size_t num_4kpages;
108 int ret;
109
110 num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0);
111
112 if (num_4kpages == 0) {
113 printf("%s: unexpected request for buffer without size\n", __func__);
114 return -1;
115 }
116
117 switch (endpoint) {
118 case APPLE_RTKIT_EP_CRASHLOG:
119 buf = &rtk->crashlog_buffer;
120 break;
121 case APPLE_RTKIT_EP_SYSLOG:
122 buf = &rtk->syslog_buffer;
123 break;
124 case APPLE_RTKIT_EP_IOREPORT:
125 buf = &rtk->ioreport_buffer;
126 break;
127 default:
128 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
129 return -1;
130 }
131
132 buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0);
133 buf->size = num_4kpages << 12;
134 buf->is_mapped = false;
135
136 if (rtk->shmem_setup) {
137 ret = rtk->shmem_setup(rtk->cookie, buf);
138 if (ret < 0) {
139 printf("%s: shmen_setup failed for endpoint %d\n", __func__,
140 endpoint);
141 return ret;
142 }
143 }
144
145 if (!buf->is_mapped) {
146 msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
147 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) |
148 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva);
149 msg->msg1 = endpoint;
150
151 return mbox_send(rtk->chan, msg);
152 }
153
154 return 0;
155}
156
Hector Martinaa4e96b2025-04-20 13:58:03 +0200157int apple_rtkit_poll(struct apple_rtkit *rtk, ulong timeout)
158{
159 struct apple_mbox_msg msg;
160 int ret;
161 int endpoint;
162 int msgtype;
163
164 ret = mbox_recv(rtk->chan, &msg, timeout);
165 if (ret < 0)
166 return ret;
167
168 endpoint = msg.msg1;
169 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
170
171 if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
172 endpoint == APPLE_RTKIT_EP_SYSLOG ||
173 endpoint == APPLE_RTKIT_EP_IOREPORT) {
174 if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) {
175 ret = rtkit_handle_buf_req(rtk, endpoint, &msg);
176 if (ret < 0)
177 return ret;
178 return 0;
179 }
180 }
181
182 if (endpoint == APPLE_RTKIT_EP_IOREPORT) {
183 // these two messages have to be ack-ed for proper startup
184 if (msgtype == 0xc || msgtype == 0x8) {
185 ret = mbox_send(rtk->chan, &msg);
186 if (ret < 0)
187 return ret;
188 return 0;
189 }
190 }
191
192 if (endpoint == APPLE_RTKIT_EP_SYSLOG) {
193 /* Ignore init */
194 if (msgtype == 0x8)
195 return 0;
196
197 /* Ack logs */
198 if (msgtype == 0x5) {
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_MGMT) {
207 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
208 return -EINVAL;
209 }
210
211 switch (msgtype) {
212 case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK:
213 rtk->iop_pwr = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
214 return 0;
215 case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE:
216 rtk->ap_pwr = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
217 return 0;
218 default:
219 printf("%s: unexpected message type %d\n", __func__, msgtype);
220
221 /* Just ignore it */
222 return 0;
223 }
224}
225
Janne Grunaue3a438f2022-06-14 09:09:07 +0200226int apple_rtkit_boot(struct apple_rtkit *rtk)
Mark Kettenis72d73012022-01-22 20:38:14 +0100227{
228 struct apple_mbox_msg msg;
229 int endpoints[256];
230 int nendpoints = 0;
231 int endpoint;
232 int min_ver, max_ver, want_ver;
Hector Martinaa4e96b2025-04-20 13:58:03 +0200233 int msgtype;
Mark Kettenis72d73012022-01-22 20:38:14 +0100234 u64 reply;
235 u32 bitmap, base;
236 int i, ret;
237
238 /* Wakup the IOP. */
239 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
240 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
241 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200242 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100243 if (ret < 0)
244 return ret;
245
246 /* Wait for protocol version negotiation message. */
Janne Grunau16eda4e2022-06-14 09:09:09 +0200247 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100248 if (ret < 0)
249 return ret;
250
251 endpoint = msg.msg1;
252 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
253 if (endpoint != APPLE_RTKIT_EP_MGMT) {
254 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
255 return -EINVAL;
256 }
257 if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
258 printf("%s: unexpected message type %d\n", __func__, msgtype);
259 return -EINVAL;
260 }
261
262 min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
263 max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
264 want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
265
266 if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
267 printf("%s: firmware min version %d is too new\n",
268 __func__, min_ver);
269 return -ENOTSUPP;
270 }
271
272 if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
273 printf("%s: firmware max version %d is too old\n",
274 __func__, max_ver);
275 return -ENOTSUPP;
276 }
277
278 /* Ack version. */
279 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
280 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
281 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
282 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200283 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100284 if (ret < 0)
285 return ret;
286
287wait_epmap:
288 /* Wait for endpoint map message. */
Janne Grunau16eda4e2022-06-14 09:09:09 +0200289 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100290 if (ret < 0)
291 return ret;
292
293 endpoint = msg.msg1;
294 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
295 if (endpoint != APPLE_RTKIT_EP_MGMT) {
296 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
297 return -EINVAL;
298 }
299 if (msgtype != APPLE_RTKIT_MGMT_EPMAP) {
300 printf("%s: unexpected message type %d\n", __func__, msgtype);
301 return -EINVAL;
302 }
303
304 bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
305 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
306 for (i = 0; i < 32; i++) {
307 if (bitmap & (1U << i))
308 endpoints[nendpoints++] = base * 32 + i;
309 }
310
311 /* Ack endpoint map. */
312 reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
313 FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
314 if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
315 reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
316 else
317 reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
318 msg.msg0 = reply;
319 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200320 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100321 if (ret < 0)
322 return ret;
323
324 if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
325 goto wait_epmap;
326
327 for (i = 0; i < nendpoints; i++) {
Janne Grunaue3a438f2022-06-14 09:09:07 +0200328 /* Start only necessary endpoints. The syslog endpoint is
329 * particularly noisy and its message can't easily be handled
330 * within U-Boot.
331 */
332 switch (endpoints[i]) {
333 case APPLE_RTKIT_EP_MGMT:
334 case APPLE_RTKIT_EP_SYSLOG:
335 case APPLE_RTKIT_EP_DEBUG:
336 case APPLE_RTKIT_EP_TRACEKIT:
Mark Kettenis72d73012022-01-22 20:38:14 +0100337 continue;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200338 default:
339 break;
340 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100341
342 /* Request endpoint. */
343 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
344 FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
345 APPLE_RTKIT_MGMT_STARTEP_FLAG;
346 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200347 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100348 if (ret < 0)
349 return ret;
350 }
351
Hector Martinaa4e96b2025-04-20 13:58:03 +0200352 rtk->iop_pwr = APPLE_RTKIT_PWR_STATE_SLEEP;
353 rtk->ap_pwr = APPLE_RTKIT_PWR_STATE_QUIESCED;
354
355 while (rtk->iop_pwr != APPLE_RTKIT_PWR_STATE_ON) {
356 ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US);
Mark Kettenis72d73012022-01-22 20:38:14 +0100357 if (ret < 0)
358 return ret;
Hector Martinaa4e96b2025-04-20 13:58:03 +0200359 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100360
Hector Martinaa4e96b2025-04-20 13:58:03 +0200361 return 0;
362}
Mark Kettenis72d73012022-01-22 20:38:14 +0100363
Hector Martinaa4e96b2025-04-20 13:58:03 +0200364int apple_rtkit_set_ap_power(struct apple_rtkit *rtk, int pwrstate)
365{
366 struct apple_mbox_msg msg;
367 int ret;
Mark Kettenis72d73012022-01-22 20:38:14 +0100368
Hector Martinaa4e96b2025-04-20 13:58:03 +0200369 if (rtk->ap_pwr == pwrstate)
370 return 0;
Mark Kettenis72d73012022-01-22 20:38:14 +0100371
Hector Martinaa4e96b2025-04-20 13:58:03 +0200372 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE) |
373 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
374 msg.msg1 = APPLE_RTKIT_EP_MGMT;
375 ret = mbox_send(rtk->chan, &msg);
376 if (ret < 0)
377 return ret;
Mark Kettenis72d73012022-01-22 20:38:14 +0100378
Hector Martinaa4e96b2025-04-20 13:58:03 +0200379 while (rtk->ap_pwr != pwrstate) {
380 ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US);
381 if (ret < 0)
382 return ret;
Mark Kettenis72d73012022-01-22 20:38:14 +0100383 }
384
385 return 0;
386}
387
Janne Grunaue3a438f2022-06-14 09:09:07 +0200388int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate)
Mark Kettenis72d73012022-01-22 20:38:14 +0100389{
390 struct apple_mbox_msg msg;
391 int ret;
392
Hector Martinaa4e96b2025-04-20 13:58:03 +0200393 if (rtk->ap_pwr != APPLE_RTKIT_PWR_STATE_QUIESCED) {
394 ret = apple_rtkit_set_ap_power(rtk, APPLE_RTKIT_PWR_STATE_QUIESCED);
395 if (ret < 0)
396 return ret;
397 }
398
Mark Kettenis72d73012022-01-22 20:38:14 +0100399 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
400 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
401 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200402 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis72d73012022-01-22 20:38:14 +0100403 if (ret < 0)
404 return ret;
405
Hector Martinaa4e96b2025-04-20 13:58:03 +0200406 while (rtk->iop_pwr != pwrstate) {
407 ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US);
408 if (ret < 0)
409 return ret;
410 }
Mark Kettenis72d73012022-01-22 20:38:14 +0100411
412 return 0;
413}