Commit | Line | Data |
---|---|---|
9bd1d9a0 SP |
1 | // SPDX-License-Identifier: GPL-2.0-only OR MIT |
2 | /* | |
3 | * Apple RTKit IPC library | |
4 | * Copyright (C) The Asahi Linux Contributors | |
5 | */ | |
6 | ||
7 | #include "rtkit-internal.h" | |
8 | ||
9 | enum { | |
10 | APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */ | |
11 | APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */ | |
40eaa8c0 | 12 | APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */ |
9bd1d9a0 SP |
13 | APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */ |
14 | APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */ | |
15 | }; | |
16 | ||
17 | enum { | |
18 | APPLE_RTKIT_EP_MGMT = 0, | |
19 | APPLE_RTKIT_EP_CRASHLOG = 1, | |
20 | APPLE_RTKIT_EP_SYSLOG = 2, | |
21 | APPLE_RTKIT_EP_DEBUG = 3, | |
22 | APPLE_RTKIT_EP_IOREPORT = 4, | |
23 | APPLE_RTKIT_EP_OSLOG = 8, | |
24 | }; | |
25 | ||
26 | #define APPLE_RTKIT_MGMT_TYPE GENMASK_ULL(59, 52) | |
27 | ||
28 | enum { | |
29 | APPLE_RTKIT_MGMT_HELLO = 1, | |
30 | APPLE_RTKIT_MGMT_HELLO_REPLY = 2, | |
31 | APPLE_RTKIT_MGMT_STARTEP = 5, | |
32 | APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE = 6, | |
33 | APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK = 7, | |
34 | APPLE_RTKIT_MGMT_EPMAP = 8, | |
35 | APPLE_RTKIT_MGMT_EPMAP_REPLY = 8, | |
36 | APPLE_RTKIT_MGMT_SET_AP_PWR_STATE = 0xb, | |
37 | APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK = 0xb, | |
38 | }; | |
39 | ||
40 | #define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK_ULL(15, 0) | |
41 | #define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK_ULL(31, 16) | |
42 | ||
43 | #define APPLE_RTKIT_MGMT_EPMAP_LAST BIT_ULL(51) | |
44 | #define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK_ULL(34, 32) | |
45 | #define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK_ULL(31, 0) | |
46 | ||
47 | #define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT_ULL(0) | |
48 | ||
49 | #define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK_ULL(39, 32) | |
50 | #define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT_ULL(1) | |
51 | ||
52 | #define APPLE_RTKIT_MGMT_PWR_STATE GENMASK_ULL(15, 0) | |
53 | ||
54 | #define APPLE_RTKIT_CRASHLOG_CRASH 1 | |
55 | ||
56 | #define APPLE_RTKIT_BUFFER_REQUEST 1 | |
57 | #define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44) | |
22344488 | 58 | #define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0) |
9bd1d9a0 SP |
59 | |
60 | #define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52) | |
61 | ||
62 | #define APPLE_RTKIT_SYSLOG_LOG 5 | |
63 | ||
64 | #define APPLE_RTKIT_SYSLOG_INIT 8 | |
65 | #define APPLE_RTKIT_SYSLOG_N_ENTRIES GENMASK_ULL(7, 0) | |
66 | #define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24) | |
67 | ||
68 | #define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56) | |
69 | #define APPLE_RTKIT_OSLOG_INIT 1 | |
70 | #define APPLE_RTKIT_OSLOG_ACK 3 | |
71 | ||
72 | #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 | |
73 | #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 | |
74 | ||
75 | struct apple_rtkit_msg { | |
76 | struct completion *completion; | |
77 | struct apple_mbox_msg mbox_msg; | |
78 | }; | |
79 | ||
80 | struct apple_rtkit_rx_work { | |
81 | struct apple_rtkit *rtk; | |
82 | u8 ep; | |
83 | u64 msg; | |
84 | struct work_struct work; | |
85 | }; | |
86 | ||
87 | bool apple_rtkit_is_running(struct apple_rtkit *rtk) | |
88 | { | |
89 | if (rtk->crashed) | |
90 | return false; | |
91 | if ((rtk->iop_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) | |
92 | return false; | |
93 | if ((rtk->ap_power_state & 0xff) != APPLE_RTKIT_PWR_STATE_ON) | |
94 | return false; | |
95 | return true; | |
96 | } | |
97 | EXPORT_SYMBOL_GPL(apple_rtkit_is_running); | |
98 | ||
99 | bool apple_rtkit_is_crashed(struct apple_rtkit *rtk) | |
100 | { | |
101 | return rtk->crashed; | |
102 | } | |
103 | EXPORT_SYMBOL_GPL(apple_rtkit_is_crashed); | |
104 | ||
105 | static void apple_rtkit_management_send(struct apple_rtkit *rtk, u8 type, | |
106 | u64 msg) | |
107 | { | |
108 | msg &= ~APPLE_RTKIT_MGMT_TYPE; | |
109 | msg |= FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, type); | |
110 | apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_MGMT, msg, NULL, false); | |
111 | } | |
112 | ||
113 | static void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg) | |
114 | { | |
115 | u64 reply; | |
116 | ||
117 | int min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg); | |
118 | int max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg); | |
119 | int want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver); | |
120 | ||
121 | dev_dbg(rtk->dev, "RTKit: Min ver %d, max ver %d\n", min_ver, max_ver); | |
122 | ||
123 | if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) { | |
124 | dev_err(rtk->dev, "RTKit: Firmware min version %d is too new\n", | |
125 | min_ver); | |
126 | goto abort_boot; | |
127 | } | |
128 | ||
129 | if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) { | |
130 | dev_err(rtk->dev, "RTKit: Firmware max version %d is too old\n", | |
131 | max_ver); | |
132 | goto abort_boot; | |
133 | } | |
134 | ||
135 | dev_info(rtk->dev, "RTKit: Initializing (protocol version %d)\n", | |
136 | want_ver); | |
137 | rtk->version = want_ver; | |
138 | ||
139 | reply = FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver); | |
140 | reply |= FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver); | |
141 | apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_HELLO_REPLY, reply); | |
142 | ||
143 | return; | |
144 | ||
145 | abort_boot: | |
146 | rtk->boot_result = -EINVAL; | |
147 | complete_all(&rtk->epmap_completion); | |
148 | } | |
149 | ||
150 | static void apple_rtkit_management_rx_epmap(struct apple_rtkit *rtk, u64 msg) | |
151 | { | |
152 | int i, ep; | |
153 | u64 reply; | |
154 | unsigned long bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg); | |
155 | u32 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg); | |
156 | ||
157 | dev_dbg(rtk->dev, | |
158 | "RTKit: received endpoint bitmap 0x%lx with base 0x%x\n", | |
159 | bitmap, base); | |
160 | ||
161 | for_each_set_bit(i, &bitmap, 32) { | |
162 | ep = 32 * base + i; | |
163 | dev_dbg(rtk->dev, "RTKit: Discovered endpoint 0x%02x\n", ep); | |
164 | set_bit(ep, rtk->endpoints); | |
165 | } | |
166 | ||
167 | reply = FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base); | |
168 | if (msg & APPLE_RTKIT_MGMT_EPMAP_LAST) | |
169 | reply |= APPLE_RTKIT_MGMT_EPMAP_LAST; | |
170 | else | |
171 | reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE; | |
172 | ||
173 | apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_EPMAP_REPLY, reply); | |
174 | ||
175 | if (!(msg & APPLE_RTKIT_MGMT_EPMAP_LAST)) | |
176 | return; | |
177 | ||
178 | for_each_set_bit(ep, rtk->endpoints, APPLE_RTKIT_APP_ENDPOINT_START) { | |
179 | switch (ep) { | |
180 | /* the management endpoint is started by default */ | |
181 | case APPLE_RTKIT_EP_MGMT: | |
182 | break; | |
183 | ||
184 | /* without starting these RTKit refuses to boot */ | |
185 | case APPLE_RTKIT_EP_SYSLOG: | |
186 | case APPLE_RTKIT_EP_CRASHLOG: | |
187 | case APPLE_RTKIT_EP_DEBUG: | |
188 | case APPLE_RTKIT_EP_IOREPORT: | |
189 | case APPLE_RTKIT_EP_OSLOG: | |
190 | dev_dbg(rtk->dev, | |
191 | "RTKit: Starting system endpoint 0x%02x\n", ep); | |
192 | apple_rtkit_start_ep(rtk, ep); | |
193 | break; | |
194 | ||
195 | default: | |
196 | dev_warn(rtk->dev, | |
197 | "RTKit: Unknown system endpoint: 0x%02x\n", | |
198 | ep); | |
199 | } | |
200 | } | |
201 | ||
202 | rtk->boot_result = 0; | |
203 | complete_all(&rtk->epmap_completion); | |
204 | } | |
205 | ||
206 | static void apple_rtkit_management_rx_iop_pwr_ack(struct apple_rtkit *rtk, | |
207 | u64 msg) | |
208 | { | |
209 | unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); | |
210 | ||
211 | dev_dbg(rtk->dev, "RTKit: IOP power state transition: 0x%x -> 0x%x\n", | |
212 | rtk->iop_power_state, new_state); | |
213 | rtk->iop_power_state = new_state; | |
214 | ||
215 | complete_all(&rtk->iop_pwr_ack_completion); | |
216 | } | |
217 | ||
218 | static void apple_rtkit_management_rx_ap_pwr_ack(struct apple_rtkit *rtk, | |
219 | u64 msg) | |
220 | { | |
221 | unsigned int new_state = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg); | |
222 | ||
223 | dev_dbg(rtk->dev, "RTKit: AP power state transition: 0x%x -> 0x%x\n", | |
224 | rtk->ap_power_state, new_state); | |
225 | rtk->ap_power_state = new_state; | |
226 | ||
227 | complete_all(&rtk->ap_pwr_ack_completion); | |
228 | } | |
229 | ||
230 | static void apple_rtkit_management_rx(struct apple_rtkit *rtk, u64 msg) | |
231 | { | |
232 | u8 type = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg); | |
233 | ||
234 | switch (type) { | |
235 | case APPLE_RTKIT_MGMT_HELLO: | |
236 | apple_rtkit_management_rx_hello(rtk, msg); | |
237 | break; | |
238 | case APPLE_RTKIT_MGMT_EPMAP: | |
239 | apple_rtkit_management_rx_epmap(rtk, msg); | |
240 | break; | |
241 | case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK: | |
242 | apple_rtkit_management_rx_iop_pwr_ack(rtk, msg); | |
243 | break; | |
244 | case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE_ACK: | |
245 | apple_rtkit_management_rx_ap_pwr_ack(rtk, msg); | |
246 | break; | |
247 | default: | |
248 | dev_warn( | |
249 | rtk->dev, | |
250 | "RTKit: unknown management message: 0x%llx (type: 0x%02x)\n", | |
251 | msg, type); | |
252 | } | |
253 | } | |
254 | ||
255 | static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk, | |
256 | struct apple_rtkit_shmem *buffer, | |
257 | u8 ep, u64 msg) | |
258 | { | |
259 | size_t n_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg); | |
260 | u64 reply; | |
261 | int err; | |
262 | ||
263 | buffer->buffer = NULL; | |
264 | buffer->iomem = NULL; | |
265 | buffer->is_mapped = false; | |
266 | buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg); | |
267 | buffer->size = n_4kpages << 12; | |
268 | ||
269 | dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n", | |
270 | buffer->size, &buffer->iova); | |
271 | ||
272 | if (buffer->iova && | |
273 | (!rtk->ops->shmem_setup || !rtk->ops->shmem_destroy)) { | |
274 | err = -EINVAL; | |
275 | goto error; | |
276 | } | |
277 | ||
278 | if (rtk->ops->shmem_setup) { | |
279 | err = rtk->ops->shmem_setup(rtk->cookie, buffer); | |
280 | if (err) | |
281 | goto error; | |
282 | } else { | |
283 | buffer->buffer = dma_alloc_coherent(rtk->dev, buffer->size, | |
284 | &buffer->iova, GFP_KERNEL); | |
285 | if (!buffer->buffer) { | |
286 | err = -ENOMEM; | |
287 | goto error; | |
288 | } | |
289 | } | |
290 | ||
291 | if (!buffer->is_mapped) { | |
292 | reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE, | |
293 | APPLE_RTKIT_BUFFER_REQUEST); | |
294 | reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, n_4kpages); | |
295 | reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, | |
296 | buffer->iova); | |
297 | apple_rtkit_send_message(rtk, ep, reply, NULL, false); | |
298 | } | |
299 | ||
300 | return 0; | |
301 | ||
302 | error: | |
303 | buffer->buffer = NULL; | |
304 | buffer->iomem = NULL; | |
305 | buffer->iova = 0; | |
306 | buffer->size = 0; | |
307 | buffer->is_mapped = false; | |
308 | return err; | |
309 | } | |
310 | ||
311 | static void apple_rtkit_free_buffer(struct apple_rtkit *rtk, | |
312 | struct apple_rtkit_shmem *bfr) | |
313 | { | |
314 | if (bfr->size == 0) | |
315 | return; | |
316 | ||
317 | if (rtk->ops->shmem_destroy) | |
318 | rtk->ops->shmem_destroy(rtk->cookie, bfr); | |
319 | else if (bfr->buffer) | |
320 | dma_free_coherent(rtk->dev, bfr->size, bfr->buffer, bfr->iova); | |
321 | ||
322 | bfr->buffer = NULL; | |
323 | bfr->iomem = NULL; | |
324 | bfr->iova = 0; | |
325 | bfr->size = 0; | |
326 | bfr->is_mapped = false; | |
327 | } | |
328 | ||
329 | static void apple_rtkit_memcpy(struct apple_rtkit *rtk, void *dst, | |
330 | struct apple_rtkit_shmem *bfr, size_t offset, | |
331 | size_t len) | |
332 | { | |
333 | if (bfr->iomem) | |
334 | memcpy_fromio(dst, bfr->iomem + offset, len); | |
335 | else | |
336 | memcpy(dst, bfr->buffer + offset, len); | |
337 | } | |
338 | ||
339 | static void apple_rtkit_crashlog_rx(struct apple_rtkit *rtk, u64 msg) | |
340 | { | |
341 | u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); | |
342 | u8 *bfr; | |
343 | ||
344 | if (type != APPLE_RTKIT_CRASHLOG_CRASH) { | |
345 | dev_warn(rtk->dev, "RTKit: Unknown crashlog message: %llx\n", | |
346 | msg); | |
347 | return; | |
348 | } | |
349 | ||
350 | if (!rtk->crashlog_buffer.size) { | |
351 | apple_rtkit_common_rx_get_buffer(rtk, &rtk->crashlog_buffer, | |
352 | APPLE_RTKIT_EP_CRASHLOG, msg); | |
353 | return; | |
354 | } | |
355 | ||
356 | dev_err(rtk->dev, "RTKit: co-processor has crashed\n"); | |
357 | ||
358 | /* | |
359 | * create a shadow copy here to make sure the co-processor isn't able | |
360 | * to change the log while we're dumping it. this also ensures | |
361 | * the buffer is in normal memory and not iomem for e.g. the SMC | |
362 | */ | |
363 | bfr = kzalloc(rtk->crashlog_buffer.size, GFP_KERNEL); | |
364 | if (bfr) { | |
365 | apple_rtkit_memcpy(rtk, bfr, &rtk->crashlog_buffer, 0, | |
366 | rtk->crashlog_buffer.size); | |
367 | apple_rtkit_crashlog_dump(rtk, bfr, rtk->crashlog_buffer.size); | |
368 | kfree(bfr); | |
369 | } else { | |
370 | dev_err(rtk->dev, | |
371 | "RTKit: Couldn't allocate crashlog shadow buffer\n"); | |
372 | } | |
373 | ||
374 | rtk->crashed = true; | |
375 | if (rtk->ops->crashed) | |
376 | rtk->ops->crashed(rtk->cookie); | |
377 | } | |
378 | ||
379 | static void apple_rtkit_ioreport_rx(struct apple_rtkit *rtk, u64 msg) | |
380 | { | |
381 | u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); | |
382 | ||
383 | switch (type) { | |
384 | case APPLE_RTKIT_BUFFER_REQUEST: | |
385 | apple_rtkit_common_rx_get_buffer(rtk, &rtk->ioreport_buffer, | |
386 | APPLE_RTKIT_EP_IOREPORT, msg); | |
387 | break; | |
388 | /* unknown, must be ACKed or the co-processor will hang */ | |
389 | case 0x8: | |
390 | case 0xc: | |
391 | apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_IOREPORT, msg, | |
392 | NULL, false); | |
393 | break; | |
394 | default: | |
395 | dev_warn(rtk->dev, "RTKit: Unknown ioreport message: %llx\n", | |
396 | msg); | |
397 | } | |
398 | } | |
399 | ||
400 | static void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg) | |
401 | { | |
402 | rtk->syslog_n_entries = FIELD_GET(APPLE_RTKIT_SYSLOG_N_ENTRIES, msg); | |
403 | rtk->syslog_msg_size = FIELD_GET(APPLE_RTKIT_SYSLOG_MSG_SIZE, msg); | |
404 | ||
405 | rtk->syslog_msg_buffer = kzalloc(rtk->syslog_msg_size, GFP_KERNEL); | |
406 | ||
407 | dev_dbg(rtk->dev, | |
408 | "RTKit: syslog initialized: entries: %zd, msg_size: %zd\n", | |
409 | rtk->syslog_n_entries, rtk->syslog_msg_size); | |
410 | } | |
411 | ||
bdfe6de2 MP |
412 | static bool should_crop_syslog_char(char c) |
413 | { | |
414 | return c == '\n' || c == '\r' || c == ' ' || c == '\0'; | |
415 | } | |
416 | ||
9bd1d9a0 SP |
417 | static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg) |
418 | { | |
419 | u8 idx = msg & 0xff; | |
420 | char log_context[24]; | |
421 | size_t entry_size = 0x20 + rtk->syslog_msg_size; | |
bdfe6de2 | 422 | int msglen; |
9bd1d9a0 SP |
423 | |
424 | if (!rtk->syslog_msg_buffer) { | |
425 | dev_warn( | |
426 | rtk->dev, | |
427 | "RTKit: received syslog message but no syslog_msg_buffer\n"); | |
428 | goto done; | |
429 | } | |
430 | if (!rtk->syslog_buffer.size) { | |
431 | dev_warn( | |
432 | rtk->dev, | |
433 | "RTKit: received syslog message but syslog_buffer.size is zero\n"); | |
434 | goto done; | |
435 | } | |
436 | if (!rtk->syslog_buffer.buffer && !rtk->syslog_buffer.iomem) { | |
437 | dev_warn( | |
438 | rtk->dev, | |
439 | "RTKit: received syslog message but no syslog_buffer.buffer or syslog_buffer.iomem\n"); | |
440 | goto done; | |
441 | } | |
442 | if (idx > rtk->syslog_n_entries) { | |
443 | dev_warn(rtk->dev, "RTKit: syslog index %d out of range\n", | |
444 | idx); | |
445 | goto done; | |
446 | } | |
447 | ||
448 | apple_rtkit_memcpy(rtk, log_context, &rtk->syslog_buffer, | |
449 | idx * entry_size + 8, sizeof(log_context)); | |
450 | apple_rtkit_memcpy(rtk, rtk->syslog_msg_buffer, &rtk->syslog_buffer, | |
451 | idx * entry_size + 8 + sizeof(log_context), | |
452 | rtk->syslog_msg_size); | |
453 | ||
454 | log_context[sizeof(log_context) - 1] = 0; | |
bdfe6de2 MP |
455 | |
456 | msglen = rtk->syslog_msg_size - 1; | |
457 | while (msglen > 0 && | |
458 | should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1])) | |
459 | msglen--; | |
460 | ||
461 | rtk->syslog_msg_buffer[msglen] = 0; | |
9bd1d9a0 SP |
462 | dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context, |
463 | rtk->syslog_msg_buffer); | |
464 | ||
465 | done: | |
466 | apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_SYSLOG, msg, NULL, false); | |
467 | } | |
468 | ||
469 | static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg) | |
470 | { | |
471 | u8 type = FIELD_GET(APPLE_RTKIT_SYSLOG_TYPE, msg); | |
472 | ||
473 | switch (type) { | |
474 | case APPLE_RTKIT_BUFFER_REQUEST: | |
475 | apple_rtkit_common_rx_get_buffer(rtk, &rtk->syslog_buffer, | |
476 | APPLE_RTKIT_EP_SYSLOG, msg); | |
477 | break; | |
478 | case APPLE_RTKIT_SYSLOG_INIT: | |
479 | apple_rtkit_syslog_rx_init(rtk, msg); | |
480 | break; | |
481 | case APPLE_RTKIT_SYSLOG_LOG: | |
482 | apple_rtkit_syslog_rx_log(rtk, msg); | |
483 | break; | |
484 | default: | |
485 | dev_warn(rtk->dev, "RTKit: Unknown syslog message: %llx\n", | |
486 | msg); | |
487 | } | |
488 | } | |
489 | ||
490 | static void apple_rtkit_oslog_rx_init(struct apple_rtkit *rtk, u64 msg) | |
491 | { | |
492 | u64 ack; | |
493 | ||
494 | dev_dbg(rtk->dev, "RTKit: oslog init: msg: 0x%llx\n", msg); | |
495 | ack = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_ACK); | |
496 | apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_OSLOG, ack, NULL, false); | |
497 | } | |
498 | ||
499 | static void apple_rtkit_oslog_rx(struct apple_rtkit *rtk, u64 msg) | |
500 | { | |
501 | u8 type = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg); | |
502 | ||
503 | switch (type) { | |
504 | case APPLE_RTKIT_OSLOG_INIT: | |
505 | apple_rtkit_oslog_rx_init(rtk, msg); | |
506 | break; | |
507 | default: | |
508 | dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", msg); | |
509 | } | |
510 | } | |
511 | ||
512 | static void apple_rtkit_rx_work(struct work_struct *work) | |
513 | { | |
514 | struct apple_rtkit_rx_work *rtk_work = | |
515 | container_of(work, struct apple_rtkit_rx_work, work); | |
516 | struct apple_rtkit *rtk = rtk_work->rtk; | |
517 | ||
518 | switch (rtk_work->ep) { | |
519 | case APPLE_RTKIT_EP_MGMT: | |
520 | apple_rtkit_management_rx(rtk, rtk_work->msg); | |
521 | break; | |
522 | case APPLE_RTKIT_EP_CRASHLOG: | |
523 | apple_rtkit_crashlog_rx(rtk, rtk_work->msg); | |
524 | break; | |
525 | case APPLE_RTKIT_EP_SYSLOG: | |
526 | apple_rtkit_syslog_rx(rtk, rtk_work->msg); | |
527 | break; | |
528 | case APPLE_RTKIT_EP_IOREPORT: | |
529 | apple_rtkit_ioreport_rx(rtk, rtk_work->msg); | |
530 | break; | |
531 | case APPLE_RTKIT_EP_OSLOG: | |
532 | apple_rtkit_oslog_rx(rtk, rtk_work->msg); | |
533 | break; | |
534 | case APPLE_RTKIT_APP_ENDPOINT_START ... 0xff: | |
535 | if (rtk->ops->recv_message) | |
536 | rtk->ops->recv_message(rtk->cookie, rtk_work->ep, | |
537 | rtk_work->msg); | |
538 | else | |
539 | dev_warn( | |
540 | rtk->dev, | |
541 | "Received unexpected message to EP%02d: %llx\n", | |
542 | rtk_work->ep, rtk_work->msg); | |
543 | break; | |
544 | default: | |
545 | dev_warn(rtk->dev, | |
546 | "RTKit: message to unknown endpoint %02x: %llx\n", | |
547 | rtk_work->ep, rtk_work->msg); | |
548 | } | |
549 | ||
550 | kfree(rtk_work); | |
551 | } | |
552 | ||
553 | static void apple_rtkit_rx(struct mbox_client *cl, void *mssg) | |
554 | { | |
555 | struct apple_rtkit *rtk = container_of(cl, struct apple_rtkit, mbox_cl); | |
556 | struct apple_mbox_msg *msg = mssg; | |
557 | struct apple_rtkit_rx_work *work; | |
558 | u8 ep = msg->msg1; | |
559 | ||
560 | /* | |
561 | * The message was read from a MMIO FIFO and we have to make | |
562 | * sure all reads from buffers sent with that message happen | |
563 | * afterwards. | |
564 | */ | |
565 | dma_rmb(); | |
566 | ||
567 | if (!test_bit(ep, rtk->endpoints)) | |
568 | dev_warn(rtk->dev, | |
569 | "RTKit: Message to undiscovered endpoint 0x%02x\n", | |
570 | ep); | |
571 | ||
572 | if (ep >= APPLE_RTKIT_APP_ENDPOINT_START && | |
573 | rtk->ops->recv_message_early && | |
574 | rtk->ops->recv_message_early(rtk->cookie, ep, msg->msg0)) | |
575 | return; | |
576 | ||
577 | work = kzalloc(sizeof(*work), GFP_ATOMIC); | |
578 | if (!work) | |
579 | return; | |
580 | ||
581 | work->rtk = rtk; | |
582 | work->ep = ep; | |
583 | work->msg = msg->msg0; | |
584 | INIT_WORK(&work->work, apple_rtkit_rx_work); | |
585 | queue_work(rtk->wq, &work->work); | |
586 | } | |
587 | ||
588 | static void apple_rtkit_tx_done(struct mbox_client *cl, void *mssg, int r) | |
589 | { | |
590 | struct apple_rtkit_msg *msg = | |
591 | container_of(mssg, struct apple_rtkit_msg, mbox_msg); | |
592 | ||
593 | if (r == -ETIME) | |
594 | return; | |
595 | ||
596 | if (msg->completion) | |
597 | complete(msg->completion); | |
598 | kfree(msg); | |
599 | } | |
600 | ||
601 | int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message, | |
602 | struct completion *completion, bool atomic) | |
603 | { | |
604 | struct apple_rtkit_msg *msg; | |
605 | int ret; | |
606 | gfp_t flags; | |
607 | ||
608 | if (rtk->crashed) | |
609 | return -EINVAL; | |
610 | if (ep >= APPLE_RTKIT_APP_ENDPOINT_START && | |
611 | !apple_rtkit_is_running(rtk)) | |
612 | return -EINVAL; | |
613 | ||
614 | if (atomic) | |
615 | flags = GFP_ATOMIC; | |
616 | else | |
617 | flags = GFP_KERNEL; | |
618 | ||
619 | msg = kzalloc(sizeof(*msg), flags); | |
620 | if (!msg) | |
621 | return -ENOMEM; | |
622 | ||
623 | msg->mbox_msg.msg0 = message; | |
624 | msg->mbox_msg.msg1 = ep; | |
625 | msg->completion = completion; | |
626 | ||
627 | /* | |
628 | * The message will be sent with a MMIO write. We need the barrier | |
629 | * here to ensure any previous writes to buffers are visible to the | |
630 | * device before that MMIO write happens. | |
631 | */ | |
632 | dma_wmb(); | |
633 | ||
634 | ret = mbox_send_message(rtk->mbox_chan, &msg->mbox_msg); | |
635 | if (ret < 0) { | |
636 | kfree(msg); | |
637 | return ret; | |
638 | } | |
639 | ||
640 | return 0; | |
641 | } | |
642 | EXPORT_SYMBOL_GPL(apple_rtkit_send_message); | |
643 | ||
644 | int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message, | |
645 | unsigned long timeout, bool atomic) | |
646 | { | |
647 | DECLARE_COMPLETION_ONSTACK(completion); | |
648 | int ret; | |
649 | long t; | |
650 | ||
651 | ret = apple_rtkit_send_message(rtk, ep, message, &completion, atomic); | |
652 | if (ret < 0) | |
653 | return ret; | |
654 | ||
655 | if (atomic) { | |
656 | ret = mbox_flush(rtk->mbox_chan, timeout); | |
657 | if (ret < 0) | |
658 | return ret; | |
659 | ||
660 | if (try_wait_for_completion(&completion)) | |
661 | return 0; | |
662 | ||
663 | return -ETIME; | |
664 | } else { | |
665 | t = wait_for_completion_interruptible_timeout( | |
666 | &completion, msecs_to_jiffies(timeout)); | |
667 | if (t < 0) | |
668 | return t; | |
669 | else if (t == 0) | |
670 | return -ETIME; | |
671 | return 0; | |
672 | } | |
673 | } | |
674 | EXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait); | |
675 | ||
f5a5e833 HM |
676 | int apple_rtkit_poll(struct apple_rtkit *rtk) |
677 | { | |
678 | return mbox_client_peek_data(rtk->mbox_chan); | |
679 | } | |
680 | EXPORT_SYMBOL_GPL(apple_rtkit_poll); | |
681 | ||
9bd1d9a0 SP |
682 | int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint) |
683 | { | |
684 | u64 msg; | |
685 | ||
686 | if (!test_bit(endpoint, rtk->endpoints)) | |
687 | return -EINVAL; | |
688 | if (endpoint >= APPLE_RTKIT_APP_ENDPOINT_START && | |
689 | !apple_rtkit_is_running(rtk)) | |
690 | return -EINVAL; | |
691 | ||
692 | msg = FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoint); | |
693 | msg |= APPLE_RTKIT_MGMT_STARTEP_FLAG; | |
694 | apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_STARTEP, msg); | |
695 | ||
696 | return 0; | |
697 | } | |
698 | EXPORT_SYMBOL_GPL(apple_rtkit_start_ep); | |
699 | ||
700 | static int apple_rtkit_request_mbox_chan(struct apple_rtkit *rtk) | |
701 | { | |
702 | if (rtk->mbox_name) | |
703 | rtk->mbox_chan = mbox_request_channel_byname(&rtk->mbox_cl, | |
704 | rtk->mbox_name); | |
705 | else | |
706 | rtk->mbox_chan = | |
707 | mbox_request_channel(&rtk->mbox_cl, rtk->mbox_idx); | |
708 | ||
709 | if (IS_ERR(rtk->mbox_chan)) | |
710 | return PTR_ERR(rtk->mbox_chan); | |
711 | return 0; | |
712 | } | |
713 | ||
b3892860 | 714 | struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, |
9bd1d9a0 SP |
715 | const char *mbox_name, int mbox_idx, |
716 | const struct apple_rtkit_ops *ops) | |
717 | { | |
718 | struct apple_rtkit *rtk; | |
719 | int ret; | |
720 | ||
721 | if (!ops) | |
722 | return ERR_PTR(-EINVAL); | |
723 | ||
724 | rtk = kzalloc(sizeof(*rtk), GFP_KERNEL); | |
725 | if (!rtk) | |
726 | return ERR_PTR(-ENOMEM); | |
727 | ||
728 | rtk->dev = dev; | |
729 | rtk->cookie = cookie; | |
730 | rtk->ops = ops; | |
731 | ||
732 | init_completion(&rtk->epmap_completion); | |
733 | init_completion(&rtk->iop_pwr_ack_completion); | |
734 | init_completion(&rtk->ap_pwr_ack_completion); | |
735 | ||
736 | bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS); | |
737 | set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints); | |
738 | ||
739 | rtk->mbox_name = mbox_name; | |
740 | rtk->mbox_idx = mbox_idx; | |
741 | rtk->mbox_cl.dev = dev; | |
742 | rtk->mbox_cl.tx_block = false; | |
743 | rtk->mbox_cl.knows_txdone = false; | |
744 | rtk->mbox_cl.rx_callback = &apple_rtkit_rx; | |
745 | rtk->mbox_cl.tx_done = &apple_rtkit_tx_done; | |
746 | ||
747 | rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM, | |
748 | dev_name(rtk->dev)); | |
749 | if (!rtk->wq) { | |
750 | ret = -ENOMEM; | |
751 | goto free_rtk; | |
752 | } | |
753 | ||
754 | ret = apple_rtkit_request_mbox_chan(rtk); | |
755 | if (ret) | |
756 | goto destroy_wq; | |
757 | ||
758 | return rtk; | |
759 | ||
760 | destroy_wq: | |
761 | destroy_workqueue(rtk->wq); | |
762 | free_rtk: | |
763 | kfree(rtk); | |
764 | return ERR_PTR(ret); | |
765 | } | |
b3892860 | 766 | EXPORT_SYMBOL_GPL(apple_rtkit_init); |
9bd1d9a0 SP |
767 | |
768 | static int apple_rtkit_wait_for_completion(struct completion *c) | |
769 | { | |
770 | long t; | |
771 | ||
772 | t = wait_for_completion_interruptible_timeout(c, | |
773 | msecs_to_jiffies(1000)); | |
774 | if (t < 0) | |
775 | return t; | |
776 | else if (t == 0) | |
777 | return -ETIME; | |
778 | else | |
779 | return 0; | |
780 | } | |
781 | ||
782 | int apple_rtkit_reinit(struct apple_rtkit *rtk) | |
783 | { | |
784 | /* make sure we don't handle any messages while reinitializing */ | |
785 | mbox_free_channel(rtk->mbox_chan); | |
786 | flush_workqueue(rtk->wq); | |
787 | ||
788 | apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); | |
789 | apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); | |
790 | apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); | |
791 | ||
792 | kfree(rtk->syslog_msg_buffer); | |
793 | ||
794 | rtk->syslog_msg_buffer = NULL; | |
795 | rtk->syslog_n_entries = 0; | |
796 | rtk->syslog_msg_size = 0; | |
797 | ||
798 | bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS); | |
799 | set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints); | |
800 | ||
801 | reinit_completion(&rtk->epmap_completion); | |
802 | reinit_completion(&rtk->iop_pwr_ack_completion); | |
803 | reinit_completion(&rtk->ap_pwr_ack_completion); | |
804 | ||
805 | rtk->crashed = false; | |
806 | rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_OFF; | |
807 | rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_OFF; | |
808 | ||
809 | return apple_rtkit_request_mbox_chan(rtk); | |
810 | } | |
811 | EXPORT_SYMBOL_GPL(apple_rtkit_reinit); | |
812 | ||
813 | static int apple_rtkit_set_ap_power_state(struct apple_rtkit *rtk, | |
814 | unsigned int state) | |
815 | { | |
816 | u64 msg; | |
817 | int ret; | |
818 | ||
819 | reinit_completion(&rtk->ap_pwr_ack_completion); | |
820 | ||
821 | msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state); | |
822 | apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE, | |
823 | msg); | |
824 | ||
825 | ret = apple_rtkit_wait_for_completion(&rtk->ap_pwr_ack_completion); | |
826 | if (ret) | |
827 | return ret; | |
828 | ||
829 | if (rtk->ap_power_state != state) | |
830 | return -EINVAL; | |
831 | return 0; | |
832 | } | |
833 | ||
834 | static int apple_rtkit_set_iop_power_state(struct apple_rtkit *rtk, | |
835 | unsigned int state) | |
836 | { | |
837 | u64 msg; | |
838 | int ret; | |
839 | ||
840 | reinit_completion(&rtk->iop_pwr_ack_completion); | |
841 | ||
842 | msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state); | |
843 | apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE, | |
844 | msg); | |
845 | ||
846 | ret = apple_rtkit_wait_for_completion(&rtk->iop_pwr_ack_completion); | |
847 | if (ret) | |
848 | return ret; | |
849 | ||
850 | if (rtk->iop_power_state != state) | |
851 | return -EINVAL; | |
852 | return 0; | |
853 | } | |
854 | ||
855 | int apple_rtkit_boot(struct apple_rtkit *rtk) | |
856 | { | |
857 | int ret; | |
858 | ||
859 | if (apple_rtkit_is_running(rtk)) | |
860 | return 0; | |
861 | if (rtk->crashed) | |
862 | return -EINVAL; | |
863 | ||
864 | dev_dbg(rtk->dev, "RTKit: waiting for boot to finish\n"); | |
865 | ret = apple_rtkit_wait_for_completion(&rtk->epmap_completion); | |
866 | if (ret) | |
867 | return ret; | |
868 | if (rtk->boot_result) | |
869 | return rtk->boot_result; | |
870 | ||
871 | dev_dbg(rtk->dev, "RTKit: waiting for IOP power state ACK\n"); | |
872 | ret = apple_rtkit_wait_for_completion(&rtk->iop_pwr_ack_completion); | |
873 | if (ret) | |
874 | return ret; | |
875 | ||
876 | return apple_rtkit_set_ap_power_state(rtk, APPLE_RTKIT_PWR_STATE_ON); | |
877 | } | |
878 | EXPORT_SYMBOL_GPL(apple_rtkit_boot); | |
879 | ||
880 | int apple_rtkit_shutdown(struct apple_rtkit *rtk) | |
881 | { | |
882 | int ret; | |
883 | ||
884 | /* if OFF is used here the co-processor will not wake up again */ | |
885 | ret = apple_rtkit_set_ap_power_state(rtk, | |
886 | APPLE_RTKIT_PWR_STATE_QUIESCED); | |
887 | if (ret) | |
888 | return ret; | |
889 | ||
890 | ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_SLEEP); | |
891 | if (ret) | |
892 | return ret; | |
893 | ||
894 | return apple_rtkit_reinit(rtk); | |
895 | } | |
896 | EXPORT_SYMBOL_GPL(apple_rtkit_shutdown); | |
897 | ||
40eaa8c0 HM |
898 | int apple_rtkit_idle(struct apple_rtkit *rtk) |
899 | { | |
900 | int ret; | |
901 | ||
902 | /* if OFF is used here the co-processor will not wake up again */ | |
903 | ret = apple_rtkit_set_ap_power_state(rtk, | |
904 | APPLE_RTKIT_PWR_STATE_IDLE); | |
905 | if (ret) | |
906 | return ret; | |
907 | ||
908 | ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_IDLE); | |
909 | if (ret) | |
910 | return ret; | |
911 | ||
912 | rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_IDLE; | |
913 | rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_IDLE; | |
914 | return 0; | |
915 | } | |
916 | EXPORT_SYMBOL_GPL(apple_rtkit_idle); | |
917 | ||
9bd1d9a0 SP |
918 | int apple_rtkit_quiesce(struct apple_rtkit *rtk) |
919 | { | |
920 | int ret; | |
921 | ||
922 | ret = apple_rtkit_set_ap_power_state(rtk, | |
923 | APPLE_RTKIT_PWR_STATE_QUIESCED); | |
924 | if (ret) | |
925 | return ret; | |
926 | ||
927 | ret = apple_rtkit_set_iop_power_state(rtk, | |
928 | APPLE_RTKIT_PWR_STATE_QUIESCED); | |
929 | if (ret) | |
930 | return ret; | |
931 | ||
932 | ret = apple_rtkit_reinit(rtk); | |
933 | if (ret) | |
934 | return ret; | |
935 | ||
936 | rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED; | |
937 | rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_QUIESCED; | |
938 | return 0; | |
939 | } | |
940 | EXPORT_SYMBOL_GPL(apple_rtkit_quiesce); | |
941 | ||
942 | int apple_rtkit_wake(struct apple_rtkit *rtk) | |
943 | { | |
944 | u64 msg; | |
945 | ||
946 | if (apple_rtkit_is_running(rtk)) | |
947 | return -EINVAL; | |
948 | ||
949 | reinit_completion(&rtk->iop_pwr_ack_completion); | |
950 | ||
951 | /* | |
952 | * Use open-coded apple_rtkit_set_iop_power_state since apple_rtkit_boot | |
953 | * will wait for the completion anyway. | |
954 | */ | |
955 | msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON); | |
956 | apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE, | |
957 | msg); | |
958 | ||
959 | return apple_rtkit_boot(rtk); | |
960 | } | |
961 | EXPORT_SYMBOL_GPL(apple_rtkit_wake); | |
962 | ||
b3892860 | 963 | void apple_rtkit_free(struct apple_rtkit *rtk) |
9bd1d9a0 SP |
964 | { |
965 | mbox_free_channel(rtk->mbox_chan); | |
966 | destroy_workqueue(rtk->wq); | |
967 | ||
968 | apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer); | |
969 | apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer); | |
970 | apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer); | |
971 | ||
972 | kfree(rtk->syslog_msg_buffer); | |
973 | kfree(rtk); | |
974 | } | |
b3892860 AL |
975 | EXPORT_SYMBOL_GPL(apple_rtkit_free); |
976 | ||
977 | static void apple_rtkit_free_wrapper(void *data) | |
978 | { | |
979 | apple_rtkit_free(data); | |
980 | } | |
9bd1d9a0 SP |
981 | |
982 | struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie, | |
983 | const char *mbox_name, int mbox_idx, | |
984 | const struct apple_rtkit_ops *ops) | |
985 | { | |
986 | struct apple_rtkit *rtk; | |
987 | int ret; | |
988 | ||
989 | rtk = apple_rtkit_init(dev, cookie, mbox_name, mbox_idx, ops); | |
990 | if (IS_ERR(rtk)) | |
991 | return rtk; | |
992 | ||
b3892860 | 993 | ret = devm_add_action_or_reset(dev, apple_rtkit_free_wrapper, rtk); |
9bd1d9a0 SP |
994 | if (ret) |
995 | return ERR_PTR(ret); | |
996 | ||
997 | return rtk; | |
998 | } | |
999 | EXPORT_SYMBOL_GPL(devm_apple_rtkit_init); | |
1000 | ||
1001 | MODULE_LICENSE("Dual MIT/GPL"); | |
1002 | MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); | |
1003 | MODULE_DESCRIPTION("Apple RTKit driver"); |