xref: /openbmc/qemu/hw/i3c/remote-i3c.c (revision 762f59c8)
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