1 /*
2 * Remote I3C Device
3 *
4 * Copyright (c) 2023 Google LLC
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "qemu/osdep.h"
18 #include "qemu/bswap.h"
19 #include "qemu/log.h"
20 #include "qemu/fifo8.h"
21 #include "chardev/char-fe.h"
22 #include "trace.h"
23 #include "hw/i3c/i3c.h"
24 #include "hw/i3c/remote-i3c.h"
25 #include "hw/qdev-properties-system.h"
26
27 typedef enum {
28 IBI_RX_STATE_DONE = 0,
29 IBI_RX_STATE_READ_ADDR = 1,
30 IBI_RX_STATE_READ_RNW = 2,
31 IBI_RX_STATE_READ_SIZE = 3,
32 IBI_RX_STATE_READ_DATA = 4,
33 } IBIRXState;
34
35 typedef struct {
36 uint8_t addr;
37 bool is_recv;
38 uint32_t num_bytes;
39 uint8_t *data;
40 } IBIData;
41
42 typedef struct {
43 I3CTarget parent_obj;
44 CharBackend chr;
45 /* For ease of debugging. */
46
47 struct {
48 char *name;
49 uint32_t buf_size;
50 } cfg;
51
52 /* Intermediate buffer to store IBI data received over socket. */
53 IBIData ibi_data;
54 Fifo8 tx_fifo;
55 Fifo8 rx_fifo;
56 uint8_t current_cmd;
57 IBIRXState ibi_rx_state;
58 /*
59 * To keep track of where we are in reading in data that's longer than
60 * 1-byte.
61 */
62 uint32_t ibi_bytes_rxed;
63 } RemoteI3C;
64
remote_i3c_recv(I3CTarget * t,uint8_t * data,uint32_t num_to_read)65 static uint32_t remote_i3c_recv(I3CTarget *t, uint8_t *data,
66 uint32_t num_to_read)
67 {
68 RemoteI3C *i3c = REMOTE_I3C(t);
69 uint8_t type = REMOTE_I3C_RECV;
70 uint32_t num_read;
71
72 qemu_chr_fe_write_all(&i3c->chr, &type, 1);
73 uint32_t num_to_read_le = cpu_to_le32(num_to_read);
74 qemu_chr_fe_write_all(&i3c->chr, (uint8_t *)&num_to_read_le,
75 sizeof(num_to_read_le));
76 /*
77 * The response will first contain the size of the packet, as a LE uint32.
78 */
79 qemu_chr_fe_read_all(&i3c->chr, (uint8_t *)&num_read, sizeof(num_read));
80
81 num_read = le32_to_cpu(num_read);
82 qemu_chr_fe_read_all(&i3c->chr, data, num_read);
83 trace_remote_i3c_recv(i3c->cfg.name, num_read, num_to_read);
84 return num_read;
85 }
86
remote_i3c_tx_in_progress(RemoteI3C * i3c)87 static inline bool remote_i3c_tx_in_progress(RemoteI3C *i3c)
88 {
89 return !fifo8_is_empty(&i3c->tx_fifo);
90 }
91
remote_i3c_chr_send_bytes(RemoteI3C * i3c)92 static int remote_i3c_chr_send_bytes(RemoteI3C *i3c)
93 {
94 uint32_t i;
95 uint32_t num_bytes = fifo8_num_used(&i3c->tx_fifo);
96 g_autofree uint8_t *buf = g_new0(uint8_t, num_bytes);
97
98 qemu_chr_fe_write_all(&i3c->chr, &i3c->current_cmd,
99 sizeof(i3c->current_cmd));
100
101 /* The FIFO data is stored in a ring buffer, move it into a linear one. */
102 for (i = 0; i < num_bytes; i++) {
103 buf[i] = fifo8_pop(&i3c->tx_fifo);
104 }
105
106 uint32_t num_bytes_le = cpu_to_le32(num_bytes);
107 qemu_chr_fe_write_all(&i3c->chr, (uint8_t *)&num_bytes_le, 4);
108 qemu_chr_fe_write_all(&i3c->chr, buf, num_bytes);
109 trace_remote_i3c_send(i3c->cfg.name, num_bytes, i3c->current_cmd ==
110 REMOTE_I3C_HANDLE_CCC_WRITE);
111
112 return 0;
113 }
114
remote_i3c_tx_fifo_push(RemoteI3C * i3c,const uint8_t * data,uint32_t num_to_send,uint32_t * num_sent)115 static bool remote_i3c_tx_fifo_push(RemoteI3C *i3c, const uint8_t *data,
116 uint32_t num_to_send, uint32_t *num_sent)
117 {
118 uint32_t num_to_push = num_to_send;
119 bool ack = true;
120
121 /*
122 * For performance reasons, we buffer data being sent from the controller to
123 * us.
124 * If this FIFO has data in it, we transmit it when we receive an I3C
125 * STOP or START.
126 */
127 if (fifo8_num_free(&i3c->tx_fifo) < num_to_send) {
128 qemu_log_mask(LOG_GUEST_ERROR, "%s-%s: TX FIFO buffer full.\n",
129 object_get_canonical_path(OBJECT(i3c)), i3c->cfg.name);
130 num_to_push = fifo8_num_free(&i3c->tx_fifo);
131 ack = false;
132 }
133
134 *num_sent = num_to_push;
135 for (uint32_t i = 0; i < num_to_push; i++) {
136 fifo8_push(&i3c->tx_fifo, data[i]);
137 }
138
139 return ack;
140 }
141
remote_i3c_send(I3CTarget * t,const uint8_t * data,uint32_t num_to_send,uint32_t * num_sent)142 static int remote_i3c_send(I3CTarget *t, const uint8_t *data,
143 uint32_t num_to_send, uint32_t *num_sent)
144 {
145 RemoteI3C *i3c = REMOTE_I3C(t);
146 i3c->current_cmd = REMOTE_I3C_SEND;
147 if (!remote_i3c_tx_fifo_push(i3c, data, num_to_send, num_sent)) {
148 return -1;
149 }
150
151 return 0;
152 }
153
remote_i3c_handle_ccc_read(I3CTarget * t,uint8_t * data,uint32_t num_to_read,uint32_t * num_read)154 static int remote_i3c_handle_ccc_read(I3CTarget *t, uint8_t *data,
155 uint32_t num_to_read, uint32_t *num_read)
156 {
157 RemoteI3C *i3c = REMOTE_I3C(t);
158 uint8_t type = REMOTE_I3C_HANDLE_CCC_READ;
159
160 qemu_chr_fe_write_all(&i3c->chr, &type, 1);
161 /*
162 * The response will first contain the size of the packet, as a LE uint32.
163 */
164 qemu_chr_fe_read_all(&i3c->chr, (uint8_t *)num_read, 4);
165 *num_read = le32_to_cpu(*num_read);
166 qemu_chr_fe_read_all(&i3c->chr, data, *num_read);
167 trace_remote_i3c_ccc_read(i3c->cfg.name, *num_read, num_to_read);
168
169 return 0;
170 }
171
remote_i3c_handle_ccc_write(I3CTarget * t,const uint8_t * data,uint32_t num_to_send,uint32_t * num_sent)172 static int remote_i3c_handle_ccc_write(I3CTarget *t, const uint8_t *data,
173 uint32_t num_to_send, uint32_t *num_sent)
174 {
175 RemoteI3C *i3c = REMOTE_I3C(t);
176 i3c->current_cmd = REMOTE_I3C_HANDLE_CCC_WRITE;
177 if (!remote_i3c_tx_fifo_push(i3c, data, num_to_send, num_sent)) {
178 return -1;
179 }
180
181 return 0;
182 }
183
remote_i3c_event(I3CTarget * t,enum I3CEvent event)184 static int remote_i3c_event(I3CTarget *t, enum I3CEvent event)
185 {
186 RemoteI3C *i3c = REMOTE_I3C(t);
187 uint8_t type;
188 trace_remote_i3c_event(i3c->cfg.name, event);
189 switch (event) {
190 case I3C_START_RECV:
191 type = REMOTE_I3C_START_RECV;
192 break;
193 case I3C_START_SEND:
194 type = REMOTE_I3C_START_SEND;
195 break;
196 case I3C_STOP:
197 type = REMOTE_I3C_STOP;
198 break;
199 case I3C_NACK:
200 type = REMOTE_I3C_NACK;
201 break;
202 default:
203 qemu_log_mask(LOG_GUEST_ERROR, "%s-%s: Unknown I3C event %d\n",
204 object_get_canonical_path(OBJECT(i3c)), i3c->cfg.name,
205 event);
206 return -1;
207 }
208
209 /*
210 * If we have a transfer buffered, send it out before we tell the remote
211 * target about the next event.
212 */
213 if (remote_i3c_tx_in_progress(i3c)) {
214 remote_i3c_chr_send_bytes(i3c);
215 }
216
217 qemu_chr_fe_write_all(&i3c->chr, &type, 1);
218 return 0;
219 }
220
remote_i3c_chr_event(void * opaque,QEMUChrEvent evt)221 static void remote_i3c_chr_event(void *opaque, QEMUChrEvent evt)
222 {
223 switch (evt) {
224 case CHR_EVENT_OPENED:
225 case CHR_EVENT_CLOSED:
226 case CHR_EVENT_BREAK:
227 case CHR_EVENT_MUX_IN:
228 case CHR_EVENT_MUX_OUT:
229 /*
230 * Ignore events.
231 * Our behavior stays the same regardless of what happens.
232 */
233 break;
234 default:
235 g_assert_not_reached();
236 }
237 }
238
remote_i3c_rx_ibi(RemoteI3C * i3c,const uint8_t * buf,int size)239 static void remote_i3c_rx_ibi(RemoteI3C *i3c, const uint8_t *buf, int size)
240 {
241 uint32_t p_buf = 0;
242 while (p_buf < size) {
243 switch (i3c->ibi_rx_state) {
244 /* This is the start of a new IBI request. */
245 case IBI_RX_STATE_DONE:
246 i3c->ibi_rx_state = IBI_RX_STATE_READ_ADDR;
247 p_buf++;
248 break;
249 case IBI_RX_STATE_READ_ADDR:
250 i3c->ibi_data.addr = buf[p_buf];
251 p_buf++;
252 i3c->ibi_rx_state = IBI_RX_STATE_READ_RNW;
253 break;
254 case IBI_RX_STATE_READ_RNW:
255 i3c->ibi_data.is_recv = buf[p_buf];
256 p_buf++;
257 i3c->ibi_rx_state = IBI_RX_STATE_READ_SIZE;
258 break;
259 case IBI_RX_STATE_READ_SIZE:
260 i3c->ibi_data.num_bytes |= ((uint32_t)buf[p_buf] <<
261 (8 * i3c->ibi_bytes_rxed));
262 i3c->ibi_bytes_rxed++;
263 p_buf++;
264 /*
265 * If we're done reading the num_bytes portion, move on to reading
266 * data.
267 */
268 if (i3c->ibi_bytes_rxed == sizeof(i3c->ibi_data.num_bytes)) {
269 i3c->ibi_data.num_bytes = le32_to_cpu(i3c->ibi_data.num_bytes);
270 i3c->ibi_bytes_rxed = 0;
271 i3c->ibi_rx_state = IBI_RX_STATE_READ_DATA;
272 /* If there's no data to read, we're done. */
273 if (i3c->ibi_data.num_bytes == 0) {
274 /*
275 * Sanity check to see if the remote target is doing
276 * something wonky. This would only happen if it sends
277 * another IBI before the first one has been ACKed/NACKed
278 * by the controller.
279 * We'll try to recover by just exiting early and discarding
280 * the leftover bytes.
281 */
282 if (p_buf < size) {
283 qemu_log_mask(LOG_GUEST_ERROR, "%s-%s: Remote target "
284 "sent trailing bytes at the end of the "
285 "IBI request.",
286 object_get_canonical_path(OBJECT(i3c)),
287 i3c->cfg.name);
288 return;
289 }
290 i3c->ibi_rx_state = IBI_RX_STATE_DONE;
291 } else {
292 /*
293 * We have IBI bytes to read, allocate memory for it.
294 * Freed when we're done sending the IBI to the controller.
295 */
296 i3c->ibi_data.data = g_new0(uint8_t,
297 i3c->ibi_data.num_bytes);
298 }
299 }
300 break;
301 case IBI_RX_STATE_READ_DATA:
302 i3c->ibi_data.data[i3c->ibi_bytes_rxed] = buf[p_buf];
303 i3c->ibi_bytes_rxed++;
304 p_buf++;
305 if (i3c->ibi_bytes_rxed == i3c->ibi_data.num_bytes) {
306 /*
307 * Sanity check to see if the remote target is doing something
308 * wonky. This would only happen if it sends another IBI before
309 * the first one has been ACKed/NACKed by the controller.
310 * We'll try to recover by just exiting early and discarding the
311 * leftover bytes.
312 */
313 if (p_buf < size) {
314 qemu_log_mask(LOG_GUEST_ERROR, "%s-%s: Remote target "
315 "sent trailing bytes at the end of the "
316 "IBI request.",
317 object_get_canonical_path(OBJECT(i3c)), i3c->cfg.name);
318 return;
319 }
320 i3c->ibi_rx_state = IBI_RX_STATE_DONE;
321 }
322 break;
323 default:
324 qemu_log_mask(LOG_GUEST_ERROR, "%s-%s: Remote target IBI state "
325 "machine reached unknown state 0x%x\n",
326 object_get_canonical_path(OBJECT(i3c)), i3c->cfg.name,
327 i3c->ibi_rx_state);
328 g_assert_not_reached();
329 }
330 }
331 }
332
remote_i3c_ibi_rx_state_reset(RemoteI3C * i3c)333 static void remote_i3c_ibi_rx_state_reset(RemoteI3C *i3c)
334 {
335 if (i3c->ibi_data.num_bytes) {
336 free(i3c->ibi_data.data);
337 }
338 i3c->ibi_data.addr = 0;
339 i3c->ibi_data.is_recv = 0;
340 i3c->ibi_data.num_bytes = 0;
341 i3c->ibi_bytes_rxed = 0;
342 i3c->ibi_rx_state = IBI_RX_STATE_DONE;
343 }
344
remote_i3c_do_ibi(RemoteI3C * i3c)345 static void remote_i3c_do_ibi(RemoteI3C *i3c)
346 {
347 uint32_t i;
348 uint8_t resp = REMOTE_I3C_IBI_ACK;
349
350 trace_remote_i3c_do_ibi(i3c->cfg.name, i3c->ibi_data.addr,
351 i3c->ibi_data.is_recv);
352 if (i3c_target_send_ibi(&i3c->parent_obj, i3c->ibi_data.addr,
353 i3c->ibi_data.is_recv)) {
354 resp = REMOTE_I3C_IBI_NACK;
355 } else {
356 for (i = 0; i < i3c->ibi_data.num_bytes; i++) {
357 if (i3c_target_send_ibi_bytes(&i3c->parent_obj,
358 i3c->ibi_data.data[i])) {
359 resp = REMOTE_I3C_IBI_DATA_NACK;
360 break;
361 }
362 }
363 }
364
365 if (i3c_target_ibi_finish(&i3c->parent_obj, 0x00)) {
366 resp = REMOTE_I3C_IBI_NACK;
367 }
368 qemu_chr_fe_write_all(&i3c->chr, &resp, sizeof(resp));
369 remote_i3c_ibi_rx_state_reset(i3c);
370 }
371
remote_i3c_chr_can_receive(void * opaque)372 static int remote_i3c_chr_can_receive(void *opaque)
373 {
374 return 1;
375 }
376
remote_i3c_chr_receive(void * opaque,const uint8_t * buf,int size)377 static void remote_i3c_chr_receive(void *opaque, const uint8_t *buf, int size)
378 {
379 RemoteI3C *i3c = REMOTE_I3C(opaque);
380
381 /*
382 * The only things we expect to receive unprompted are:
383 * - An ACK of a previous transfer
384 * - A NACK of a previous transfer
385 * - An IBI requested by the remote target.
386 * - Bytes for an IBI request.
387 */
388 /* If we're in the middle of handling an IBI request, parse it here. */
389 if (i3c->ibi_rx_state != IBI_RX_STATE_DONE) {
390 remote_i3c_rx_ibi(i3c, buf, size);
391 /* If we finished reading the IBI, do it. */
392 if (i3c->ibi_rx_state == IBI_RX_STATE_DONE) {
393 remote_i3c_do_ibi(i3c);
394 }
395 return;
396 }
397
398 switch (buf[0]) {
399 case REMOTE_I3C_RX_ACK:
400 break;
401 case REMOTE_I3C_RX_NACK:
402 qemu_log_mask(LOG_GUEST_ERROR, "%s-%s: Received NACK from remote "
403 "target\n", object_get_canonical_path(OBJECT(i3c)),
404 i3c->cfg.name);
405 break;
406 case REMOTE_I3C_IBI:
407 remote_i3c_rx_ibi(i3c, buf, size);
408 /* If we finished reading the IBI, do it. */
409 if (i3c->ibi_rx_state == IBI_RX_STATE_DONE) {
410 remote_i3c_do_ibi(i3c);
411 }
412 break;
413 default:
414 qemu_log_mask(LOG_GUEST_ERROR, "%s-%s: Unknown response 0x%x\n",
415 object_get_canonical_path(OBJECT(i3c)), i3c->cfg.name,
416 buf[0]);
417 break;
418 }
419 }
420
remote_i3c_realize(DeviceState * dev,Error ** errp)421 static void remote_i3c_realize(DeviceState *dev, Error **errp)
422 {
423 RemoteI3C *i3c = REMOTE_I3C(dev);
424
425 fifo8_create(&i3c->tx_fifo, i3c->cfg.buf_size);
426 fifo8_create(&i3c->rx_fifo, i3c->cfg.buf_size);
427 i3c->ibi_data.data = g_new0(uint8_t, i3c->cfg.buf_size);
428 remote_i3c_ibi_rx_state_reset(i3c);
429
430 qemu_chr_fe_set_handlers(&i3c->chr, remote_i3c_chr_can_receive,
431 remote_i3c_chr_receive, remote_i3c_chr_event,
432 NULL, OBJECT(i3c), NULL, true);
433 }
434
435 static Property remote_i3c_props[] = {
436 DEFINE_PROP_CHR("chardev", RemoteI3C, chr),
437 DEFINE_PROP_UINT32("buf-size", RemoteI3C, cfg.buf_size, 0x10000),
438 DEFINE_PROP_STRING("device-name", RemoteI3C, cfg.name),
439 DEFINE_PROP_END_OF_LIST(),
440 };
441
remote_i3c_class_init(ObjectClass * klass,void * data)442 static void remote_i3c_class_init(ObjectClass *klass, void *data)
443 {
444 DeviceClass *dc = DEVICE_CLASS(klass);
445 I3CTargetClass *k = I3C_TARGET_CLASS(klass);
446
447 k->recv = &remote_i3c_recv;
448 k->send = &remote_i3c_send;
449 k->event = &remote_i3c_event;
450 k->handle_ccc_read = &remote_i3c_handle_ccc_read;
451 k->handle_ccc_write = &remote_i3c_handle_ccc_write;
452 device_class_set_props(dc, remote_i3c_props);
453 dc->realize = remote_i3c_realize;
454 }
455
456 static const TypeInfo remote_i3c_type = {
457 .name = TYPE_REMOTE_I3C,
458 .parent = TYPE_I3C_TARGET,
459 .instance_size = sizeof(RemoteI3C),
460 .class_size = sizeof(I3CTargetClass),
461 .class_init = remote_i3c_class_init,
462 };
463
remote_i3c_register(void)464 static void remote_i3c_register(void)
465 {
466 type_register_static(&remote_i3c_type);
467 }
468
469 type_init(remote_i3c_register)
470