blob: a550b553b663bcde0ac70fbd56a51d11b4823cb4 [file] [log] [blame]
Mark Kettenis02e25882022-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
7#include <common.h>
8#include <mailbox.h>
9#include <malloc.h>
10
11#include <asm/arch/rtkit.h>
12#include <linux/apple-mailbox.h>
13#include <linux/bitfield.h>
14
15#define APPLE_RTKIT_EP_MGMT 0
16#define APPLE_RTKIT_EP_CRASHLOG 1
17#define APPLE_RTKIT_EP_SYSLOG 2
18#define APPLE_RTKIT_EP_DEBUG 3
19#define APPLE_RTKIT_EP_IOREPORT 4
Janne Grunaue44d59c2022-06-14 09:09:07 +020020#define APPLE_RTKIT_EP_TRACEKIT 10
Mark Kettenis02e25882022-01-22 20:38:14 +010021
22/* Messages for management endpoint. */
23#define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52)
24
25#define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0)
26
27#define APPLE_RTKIT_MGMT_HELLO 1
28#define APPLE_RTKIT_MGMT_HELLO_REPLY 2
29#define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0)
30#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16)
31
32#define APPLE_RTKIT_MGMT_STARTEP 5
33#define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32)
34#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1)
35
36#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6
37#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7
38
39#define APPLE_RTKIT_MGMT_EPMAP 8
40#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
41#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
42#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
43
44#define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
45#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
46
47#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
48#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
49
50/* Messages for internal endpoints. */
51#define APPLE_RTKIT_BUFFER_REQUEST 1
52#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
53#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
54
Janne Grunau942b54b2022-06-14 09:09:09 +020055#define TIMEOUT_1SEC_US 1000000
56
Janne Grunaue44d59c2022-06-14 09:09:07 +020057struct apple_rtkit {
58 struct mbox_chan *chan;
59 void *cookie;
60 apple_rtkit_shmem_setup shmem_setup;
61 apple_rtkit_shmem_destroy shmem_destroy;
62
63 struct apple_rtkit_buffer syslog_buffer;
64 struct apple_rtkit_buffer crashlog_buffer;
65 struct apple_rtkit_buffer ioreport_buffer;
66};
67
68struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie,
69 apple_rtkit_shmem_setup shmem_setup,
70 apple_rtkit_shmem_destroy shmem_destroy)
71{
72 struct apple_rtkit *rtk;
73
74 rtk = calloc(sizeof(*rtk), 1);
75 if (!rtk)
76 return NULL;
77
78 rtk->chan = chan;
79 rtk->cookie = cookie;
80 rtk->shmem_setup = shmem_setup;
81 rtk->shmem_destroy = shmem_destroy;
82
83 return rtk;
84}
85
86void apple_rtkit_free(struct apple_rtkit *rtk)
87{
88 if (rtk->shmem_destroy) {
89 if (rtk->syslog_buffer.buffer)
90 rtk->shmem_destroy(rtk->cookie, &rtk->syslog_buffer);
91 if (rtk->crashlog_buffer.buffer)
92 rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer);
93 if (rtk->ioreport_buffer.buffer)
94 rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer);
95 }
96 free(rtk);
97}
98
99static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg)
100{
101 struct apple_rtkit_buffer *buf;
102 size_t num_4kpages;
103 int ret;
104
105 num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0);
106
107 if (num_4kpages == 0) {
108 printf("%s: unexpected request for buffer without size\n", __func__);
109 return -1;
110 }
111
112 switch (endpoint) {
113 case APPLE_RTKIT_EP_CRASHLOG:
114 buf = &rtk->crashlog_buffer;
115 break;
116 case APPLE_RTKIT_EP_SYSLOG:
117 buf = &rtk->syslog_buffer;
118 break;
119 case APPLE_RTKIT_EP_IOREPORT:
120 buf = &rtk->ioreport_buffer;
121 break;
122 default:
123 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
124 return -1;
125 }
126
127 buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0);
128 buf->size = num_4kpages << 12;
129 buf->is_mapped = false;
130
131 if (rtk->shmem_setup) {
132 ret = rtk->shmem_setup(rtk->cookie, buf);
133 if (ret < 0) {
134 printf("%s: shmen_setup failed for endpoint %d\n", __func__,
135 endpoint);
136 return ret;
137 }
138 }
139
140 if (!buf->is_mapped) {
141 msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
142 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) |
143 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva);
144 msg->msg1 = endpoint;
145
146 return mbox_send(rtk->chan, msg);
147 }
148
149 return 0;
150}
151
152int apple_rtkit_boot(struct apple_rtkit *rtk)
Mark Kettenis02e25882022-01-22 20:38:14 +0100153{
154 struct apple_mbox_msg msg;
155 int endpoints[256];
156 int nendpoints = 0;
157 int endpoint;
158 int min_ver, max_ver, want_ver;
159 int msgtype, pwrstate;
160 u64 reply;
161 u32 bitmap, base;
162 int i, ret;
163
164 /* Wakup the IOP. */
165 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
166 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
167 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue44d59c2022-06-14 09:09:07 +0200168 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis02e25882022-01-22 20:38:14 +0100169 if (ret < 0)
170 return ret;
171
172 /* Wait for protocol version negotiation message. */
Janne Grunau942b54b2022-06-14 09:09:09 +0200173 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis02e25882022-01-22 20:38:14 +0100174 if (ret < 0)
175 return ret;
176
177 endpoint = msg.msg1;
178 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
179 if (endpoint != APPLE_RTKIT_EP_MGMT) {
180 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
181 return -EINVAL;
182 }
183 if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
184 printf("%s: unexpected message type %d\n", __func__, msgtype);
185 return -EINVAL;
186 }
187
188 min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
189 max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
190 want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
191
192 if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
193 printf("%s: firmware min version %d is too new\n",
194 __func__, min_ver);
195 return -ENOTSUPP;
196 }
197
198 if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
199 printf("%s: firmware max version %d is too old\n",
200 __func__, max_ver);
201 return -ENOTSUPP;
202 }
203
204 /* Ack version. */
205 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
206 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
207 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
208 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue44d59c2022-06-14 09:09:07 +0200209 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis02e25882022-01-22 20:38:14 +0100210 if (ret < 0)
211 return ret;
212
213wait_epmap:
214 /* Wait for endpoint map message. */
Janne Grunau942b54b2022-06-14 09:09:09 +0200215 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis02e25882022-01-22 20:38:14 +0100216 if (ret < 0)
217 return ret;
218
219 endpoint = msg.msg1;
220 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
221 if (endpoint != APPLE_RTKIT_EP_MGMT) {
222 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
223 return -EINVAL;
224 }
225 if (msgtype != APPLE_RTKIT_MGMT_EPMAP) {
226 printf("%s: unexpected message type %d\n", __func__, msgtype);
227 return -EINVAL;
228 }
229
230 bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
231 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
232 for (i = 0; i < 32; i++) {
233 if (bitmap & (1U << i))
234 endpoints[nendpoints++] = base * 32 + i;
235 }
236
237 /* Ack endpoint map. */
238 reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
239 FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
240 if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
241 reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
242 else
243 reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
244 msg.msg0 = reply;
245 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue44d59c2022-06-14 09:09:07 +0200246 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis02e25882022-01-22 20:38:14 +0100247 if (ret < 0)
248 return ret;
249
250 if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
251 goto wait_epmap;
252
253 for (i = 0; i < nendpoints; i++) {
Janne Grunaue44d59c2022-06-14 09:09:07 +0200254 /* Start only necessary endpoints. The syslog endpoint is
255 * particularly noisy and its message can't easily be handled
256 * within U-Boot.
257 */
258 switch (endpoints[i]) {
259 case APPLE_RTKIT_EP_MGMT:
260 case APPLE_RTKIT_EP_SYSLOG:
261 case APPLE_RTKIT_EP_DEBUG:
262 case APPLE_RTKIT_EP_TRACEKIT:
Mark Kettenis02e25882022-01-22 20:38:14 +0100263 continue;
Janne Grunaue44d59c2022-06-14 09:09:07 +0200264 default:
265 break;
266 }
Mark Kettenis02e25882022-01-22 20:38:14 +0100267
268 /* Request endpoint. */
269 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
270 FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
271 APPLE_RTKIT_MGMT_STARTEP_FLAG;
272 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue44d59c2022-06-14 09:09:07 +0200273 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis02e25882022-01-22 20:38:14 +0100274 if (ret < 0)
275 return ret;
276 }
277
278 pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP;
279 while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) {
Janne Grunau942b54b2022-06-14 09:09:09 +0200280 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis02e25882022-01-22 20:38:14 +0100281 if (ret < 0)
282 return ret;
283
284 endpoint = msg.msg1;
285 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
286
287 if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
288 endpoint == APPLE_RTKIT_EP_SYSLOG ||
289 endpoint == APPLE_RTKIT_EP_IOREPORT) {
Janne Grunaue44d59c2022-06-14 09:09:07 +0200290 if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) {
291 ret = rtkit_handle_buf_req(rtk, endpoint, &msg);
292 if (ret < 0)
293 return ret;
Mark Kettenis02e25882022-01-22 20:38:14 +0100294 continue;
Janne Grunaue44d59c2022-06-14 09:09:07 +0200295 }
296 }
Mark Kettenis02e25882022-01-22 20:38:14 +0100297
Janne Grunaue44d59c2022-06-14 09:09:07 +0200298 if (endpoint == APPLE_RTKIT_EP_IOREPORT) {
299 // these two messages have to be ack-ed for proper startup
300 if (msgtype == 0xc || msgtype == 0x8) {
301 ret = mbox_send(rtk->chan, &msg);
302 if (ret < 0)
303 return ret;
304 continue;
305 }
Mark Kettenis02e25882022-01-22 20:38:14 +0100306 }
307
308 if (endpoint != APPLE_RTKIT_EP_MGMT) {
309 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
310 return -EINVAL;
311 }
312 if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) {
313 printf("%s: unexpected message type %d\n", __func__, msgtype);
314 return -EINVAL;
315 }
316
317 pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
318 }
319
320 return 0;
321}
322
Janne Grunaue44d59c2022-06-14 09:09:07 +0200323int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate)
Mark Kettenis02e25882022-01-22 20:38:14 +0100324{
325 struct apple_mbox_msg msg;
326 int ret;
327
328 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
329 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
330 msg.msg1 = APPLE_RTKIT_EP_MGMT;
Janne Grunaue44d59c2022-06-14 09:09:07 +0200331 ret = mbox_send(rtk->chan, &msg);
Mark Kettenis02e25882022-01-22 20:38:14 +0100332 if (ret < 0)
333 return ret;
334
Janne Grunau942b54b2022-06-14 09:09:09 +0200335 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
Mark Kettenis02e25882022-01-22 20:38:14 +0100336 if (ret < 0)
337 return ret;
338
339 return 0;
340}