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