xref: /qemu/hw/net/can/ctucan_core.c (revision 2acf4f8f)
1 /*
2  * CTU CAN FD PCI device emulation
3  * http://canbus.pages.fel.cvut.cz/
4  *
5  * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com)
6  *
7  * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
8  * Jin Yang and Pavel Pisa
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28 
29 #include "qemu/osdep.h"
30 #include "qemu/log.h"
31 #include "chardev/char.h"
32 #include "hw/irq.h"
33 #include "migration/vmstate.h"
34 #include "net/can_emu.h"
35 
36 #include "ctucan_core.h"
37 
38 #ifndef DEBUG_CAN
39 #define DEBUG_CAN 0
40 #endif /*DEBUG_CAN*/
41 
42 #define DPRINTF(fmt, ...) \
43     do { \
44         if (DEBUG_CAN) { \
45             qemu_log("[ctucan]: " fmt , ## __VA_ARGS__); \
46         } \
47     } while (0)
48 
49 static void ctucan_buff2frame(const uint8_t *buff, qemu_can_frame *frame)
50 {
51     frame->can_id = 0;
52     frame->can_dlc = 0;
53     frame->flags = 0;
54 
55     if (buff == NULL) {
56         return;
57     }
58     {
59         union ctu_can_fd_frame_form_w frame_form_w;
60         union ctu_can_fd_identifier_w identifier_w;
61         unsigned int ide;
62         uint32_t w;
63 
64         w = le32_to_cpu(*(uint32_t *)buff);
65         frame_form_w = (union ctu_can_fd_frame_form_w)w;
66         frame->can_dlc = can_dlc2len(frame_form_w.s.dlc);
67 
68         w = le32_to_cpu(*(uint32_t *)(buff + 4));
69         identifier_w = (union ctu_can_fd_identifier_w)w;
70 
71         ide = frame_form_w.s.ide;
72         if (ide) {
73             frame->can_id = (identifier_w.s.identifier_base << 18) |
74                             identifier_w.s.identifier_ext;
75             frame->can_id |= QEMU_CAN_EFF_FLAG;
76         } else {
77             frame->can_id = identifier_w.s.identifier_base;
78         }
79 
80         if (frame_form_w.s.esi_rsv) {
81             frame->flags |= QEMU_CAN_FRMF_ESI;
82         }
83 
84         if (frame_form_w.s.rtr) {
85             frame->can_id |= QEMU_CAN_RTR_FLAG;
86         }
87 
88         if (frame_form_w.s.fdf) {   /*CAN FD*/
89             frame->flags |= QEMU_CAN_FRMF_TYPE_FD;
90             if (frame_form_w.s.brs) {
91                 frame->flags |= QEMU_CAN_FRMF_BRS;
92             }
93         }
94     }
95 
96     memcpy(frame->data, buff + 0x10, 0x40);
97 }
98 
99 
100 static int ctucan_frame2buff(const qemu_can_frame *frame, uint8_t *buff)
101 {
102     unsigned int bytes_cnt = -1;
103     memset(buff, 0, CTUCAN_MSG_MAX_LEN * sizeof(*buff));
104 
105     if (frame == NULL) {
106         return bytes_cnt;
107     }
108     {
109         union ctu_can_fd_frame_form_w frame_form_w;
110         union ctu_can_fd_identifier_w identifier_w;
111 
112         frame_form_w.u32 = 0;
113         identifier_w.u32 = 0;
114 
115         bytes_cnt = frame->can_dlc;
116         bytes_cnt = (bytes_cnt + 3) & ~3;
117         bytes_cnt += 16;
118         frame_form_w.s.rwcnt = (bytes_cnt >> 2) - 1;
119 
120         frame_form_w.s.dlc = can_len2dlc(frame->can_dlc);
121 
122         if (frame->can_id & QEMU_CAN_EFF_FLAG) {
123             frame_form_w.s.ide = 1;
124             identifier_w.s.identifier_base =
125                                     (frame->can_id & 0x1FFC0000) >> 18;
126             identifier_w.s.identifier_ext = frame->can_id & 0x3FFFF;
127         } else {
128             identifier_w.s.identifier_base = frame->can_id & 0x7FF;
129         }
130 
131         if (frame->flags & QEMU_CAN_FRMF_ESI) {
132             frame_form_w.s.esi_rsv = 1;
133         }
134 
135         if (frame->can_id & QEMU_CAN_RTR_FLAG) {
136             frame_form_w.s.rtr = 1;
137         }
138 
139         if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) {  /*CAN FD*/
140            frame_form_w.s.fdf = 1;
141             if (frame->flags & QEMU_CAN_FRMF_BRS) {
142                 frame_form_w.s.brs = 1;
143             }
144         }
145         *(uint32_t *)buff = cpu_to_le32(frame_form_w.u32);
146         *(uint32_t *)(buff + 4) = cpu_to_le32(identifier_w.u32);
147     }
148 
149     memcpy(buff + 0x10, frame->data, 0x40);
150 
151     return bytes_cnt;
152 }
153 
154 static void ctucan_update_irq(CtuCanCoreState *s)
155 {
156     union ctu_can_fd_int_stat int_rq;
157 
158     int_rq.u32 = 0;
159 
160     if (s->rx_status_rx_settings.s.rxfrc) {
161         int_rq.s.rbnei = 1;
162     }
163 
164     int_rq.u32 &= ~s->int_mask.u32;
165     s->int_stat.u32 |= int_rq.u32;
166     if (s->int_stat.u32 & s->int_ena.u32) {
167         qemu_irq_raise(s->irq);
168     } else {
169         qemu_irq_lower(s->irq);
170     }
171 }
172 
173 static void ctucan_update_txnf(CtuCanCoreState *s)
174 {
175     int i;
176     int txnf;
177     unsigned int buff_st;
178 
179     txnf = 0;
180 
181     for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
182         buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
183         if (buff_st == TXT_ETY) {
184             txnf = 1;
185         }
186     }
187     s->status.s.txnf = txnf;
188 }
189 
190 void ctucan_hardware_reset(CtuCanCoreState *s)
191 {
192     DPRINTF("Hardware reset in progress!!!\n");
193     int i;
194     unsigned int buff_st;
195     uint32_t buff_st_mask;
196 
197     s->tx_status.u32 = 0;
198     for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
199         buff_st_mask = 0xf << (i * 4);
200         buff_st = TXT_ETY;
201         s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
202             (buff_st << (i * 4));
203     }
204     s->status.s.idle = 1;
205 
206     ctucan_update_txnf(s);
207 
208     s->rx_status_rx_settings.u32 = 0;
209     s->rx_tail_pos = 0;
210     s->rx_cnt = 0;
211     s->rx_frame_rem = 0;
212 
213     /* Flush RX buffer */
214     s->rx_tail_pos = 0;
215     s->rx_cnt = 0;
216     s->rx_frame_rem = 0;
217 
218     /* Set on progdokum reset value */
219     s->mode_settings.u32 = 0;
220     s->mode_settings.s.fde = 1;
221 
222     s->int_stat.u32 = 0;
223     s->int_ena.u32 = 0;
224     s->int_mask.u32 = 0;
225 
226     s->rx_status_rx_settings.u32 = 0;
227     s->rx_status_rx_settings.s.rxe = 0;
228 
229     s->rx_fr_ctr.u32 = 0;
230     s->tx_fr_ctr.u32 = 0;
231 
232     s->yolo_reg.s.yolo_val = 3735928559;
233 
234     qemu_irq_lower(s->irq);
235 }
236 
237 static void ctucan_send_ready_buffers(CtuCanCoreState *s)
238 {
239     qemu_can_frame frame;
240     uint8_t *pf;
241     int buff2tx_idx;
242     uint32_t tx_prio_max;
243     unsigned int buff_st;
244     uint32_t buff_st_mask;
245 
246     if (!s->mode_settings.s.ena) {
247         return;
248     }
249 
250     do {
251         union ctu_can_fd_int_stat int_stat;
252         int i;
253         buff2tx_idx = -1;
254         tx_prio_max = 0;
255 
256         for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
257             uint32_t prio;
258 
259             buff_st_mask = 0xf << (i * 4);
260             buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
261 
262             if (buff_st != TXT_RDY) {
263                 continue;
264             }
265             prio = (s->tx_priority.u32 >> (i * 4)) & 0x7;
266             if (tx_prio_max < prio) {
267                 tx_prio_max = prio;
268                 buff2tx_idx = i;
269             }
270         }
271         if (buff2tx_idx == -1) {
272             break;
273         }
274         buff_st_mask = 0xf << (buff2tx_idx * 4);
275         buff_st = (s->tx_status.u32 >> (buff2tx_idx * 4)) & 0xf;
276         int_stat.u32 = 0;
277         buff_st = TXT_RDY;
278         pf = s->tx_buffer[buff2tx_idx].data;
279         ctucan_buff2frame(pf, &frame);
280         s->status.s.idle = 0;
281         s->status.s.txs = 1;
282         can_bus_client_send(&s->bus_client, &frame, 1);
283         s->status.s.idle = 1;
284         s->status.s.txs = 0;
285         s->tx_fr_ctr.s.tx_fr_ctr_val++;
286         buff_st = TXT_TOK;
287         int_stat.s.txi = 1;
288         int_stat.s.txbhci = 1;
289         s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
290         s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
291                         (buff_st << (buff2tx_idx * 4));
292     } while (1);
293 }
294 
295 #define CTUCAN_CORE_TXBUFF_SPAN \
296             (CTU_CAN_FD_TXTB2_DATA_1 - CTU_CAN_FD_TXTB1_DATA_1)
297 
298 void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
299                        unsigned size)
300 {
301     int              i;
302 
303     DPRINTF("write 0x%02llx addr 0x%02x\n",
304             (unsigned long long)val, (unsigned int)addr);
305 
306     if (addr > CTUCAN_CORE_MEM_SIZE) {
307         return;
308     }
309 
310     if (addr >= CTU_CAN_FD_TXTB1_DATA_1) {
311         int buff_num;
312         addr -= CTU_CAN_FD_TXTB1_DATA_1;
313         buff_num = addr / CTUCAN_CORE_TXBUFF_SPAN;
314         addr %= CTUCAN_CORE_TXBUFF_SPAN;
315         if (buff_num < CTUCAN_CORE_TXBUF_NUM) {
316             uint32_t *bufp = (uint32_t *)(s->tx_buffer[buff_num].data + addr);
317             *bufp = cpu_to_le32(val);
318         }
319     } else {
320         switch (addr & ~3) {
321         case CTU_CAN_FD_MODE:
322             s->mode_settings.u32 = (uint32_t)val;
323             if (s->mode_settings.s.rst) {
324                 ctucan_hardware_reset(s);
325                 s->mode_settings.s.rst = 0;
326             }
327             break;
328         case CTU_CAN_FD_COMMAND:
329         {
330             union ctu_can_fd_command command;
331             command.u32 = (uint32_t)val;
332             if (command.s.cdo) {
333                 s->status.s.dor = 0;
334             }
335             if (command.s.rrb) {
336                 s->rx_tail_pos = 0;
337                 s->rx_cnt = 0;
338                 s->rx_frame_rem = 0;
339                 s->rx_status_rx_settings.s.rxfrc = 0;
340             }
341             if (command.s.txfcrst) {
342                 s->tx_fr_ctr.s.tx_fr_ctr_val = 0;
343             }
344             if (command.s.rxfcrst) {
345                 s->rx_fr_ctr.s.rx_fr_ctr_val = 0;
346             }
347             break;
348         }
349         case CTU_CAN_FD_INT_STAT:
350             s->int_stat.u32 &= ~(uint32_t)val;
351             break;
352         case CTU_CAN_FD_INT_ENA_SET:
353             s->int_ena.u32 |= (uint32_t)val;
354             break;
355         case CTU_CAN_FD_INT_ENA_CLR:
356             s->int_ena.u32 &= ~(uint32_t)val;
357             break;
358         case CTU_CAN_FD_INT_MASK_SET:
359             s->int_mask.u32 |= (uint32_t)val;
360             break;
361         case CTU_CAN_FD_INT_MASK_CLR:
362             s->int_mask.u32 &= ~(uint32_t)val;
363             break;
364         case CTU_CAN_FD_TX_COMMAND:
365             if (s->mode_settings.s.ena) {
366                 union ctu_can_fd_tx_command tx_command;
367                 union ctu_can_fd_tx_command mask;
368                 unsigned int buff_st;
369                 uint32_t buff_st_mask;
370 
371                 tx_command.u32 = (uint32_t)val;
372                 mask.u32 = 0;
373                 mask.s.txb1 = 1;
374 
375                 for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
376                     if (!(tx_command.u32 & (mask.u32 << i))) {
377                         continue;
378                     }
379                     buff_st_mask = 0xf << (i * 4);
380                     buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
381                     if (tx_command.s.txca) {
382                         if (buff_st == TXT_RDY) {
383                             buff_st = TXT_ABT;
384                         }
385                     }
386                     if (tx_command.s.txcr) {
387                         if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
388                             (buff_st == TXT_ABT) || (buff_st == TXT_ETY))
389                             buff_st = TXT_RDY;
390                     }
391                     if (tx_command.s.txce) {
392                         if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
393                             (buff_st == TXT_ABT))
394                             buff_st = TXT_ETY;
395                     }
396                     s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
397                                         (buff_st << (i * 4));
398                 }
399 
400                 ctucan_send_ready_buffers(s);
401                 ctucan_update_txnf(s);
402             }
403             break;
404         case CTU_CAN_FD_TX_PRIORITY:
405             s->tx_priority.u32 = (uint32_t)val;
406             break;
407         }
408 
409         ctucan_update_irq(s);
410     }
411 
412     return;
413 }
414 
415 uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size)
416 {
417     uint32_t val = 0;
418 
419     DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr);
420 
421     if (addr > CTUCAN_CORE_MEM_SIZE) {
422         return 0;
423     }
424 
425     switch (addr & ~3) {
426     case CTU_CAN_FD_DEVICE_ID:
427         {
428             union ctu_can_fd_device_id_version idver;
429             idver.u32 = 0;
430             idver.s.device_id = CTU_CAN_FD_ID;
431             idver.s.ver_major = 2;
432             idver.s.ver_minor = 2;
433             val = idver.u32;
434         }
435         break;
436     case CTU_CAN_FD_MODE:
437         val = s->mode_settings.u32;
438         break;
439     case CTU_CAN_FD_STATUS:
440         val = s->status.u32;
441         break;
442     case CTU_CAN_FD_INT_STAT:
443         val = s->int_stat.u32;
444         break;
445     case CTU_CAN_FD_INT_ENA_SET:
446     case CTU_CAN_FD_INT_ENA_CLR:
447         val = s->int_ena.u32;
448         break;
449     case CTU_CAN_FD_INT_MASK_SET:
450     case CTU_CAN_FD_INT_MASK_CLR:
451         val = s->int_mask.u32;
452         break;
453     case CTU_CAN_FD_RX_MEM_INFO:
454         s->rx_mem_info.u32 = 0;
455         s->rx_mem_info.s.rx_buff_size = CTUCAN_RCV_BUF_LEN >> 2;
456         s->rx_mem_info.s.rx_mem_free = (CTUCAN_RCV_BUF_LEN -
457                                         s->rx_cnt) >> 2;
458         val = s->rx_mem_info.u32;
459         break;
460     case CTU_CAN_FD_RX_POINTERS:
461     {
462         uint32_t rx_head_pos = s->rx_tail_pos + s->rx_cnt;
463         rx_head_pos %= CTUCAN_RCV_BUF_LEN;
464         s->rx_pointers.s.rx_wpp = rx_head_pos;
465         s->rx_pointers.s.rx_rpp = s->rx_tail_pos;
466         val = s->rx_pointers.u32;
467         break;
468     }
469     case CTU_CAN_FD_RX_STATUS:
470     case CTU_CAN_FD_RX_SETTINGS:
471         if (!s->rx_status_rx_settings.s.rxfrc) {
472             s->rx_status_rx_settings.s.rxe = 1;
473         } else {
474             s->rx_status_rx_settings.s.rxe = 0;
475         }
476         if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
477             s->rx_status_rx_settings.s.rxf = 1;
478         } else {
479             s->rx_status_rx_settings.s.rxf = 0;
480         }
481         val = s->rx_status_rx_settings.u32;
482         break;
483     case CTU_CAN_FD_RX_DATA:
484         if (s->rx_cnt) {
485             memcpy(&val, s->rx_buff + s->rx_tail_pos, 4);
486             val = le32_to_cpu(val);
487             if (!s->rx_frame_rem) {
488                 union ctu_can_fd_frame_form_w frame_form_w;
489                 frame_form_w.u32 = val;
490                 s->rx_frame_rem = frame_form_w.s.rwcnt * 4 + 4;
491             }
492             s->rx_cnt -= 4;
493             s->rx_frame_rem -= 4;
494             if (!s->rx_frame_rem) {
495                 s->rx_status_rx_settings.s.rxfrc--;
496                 if (!s->rx_status_rx_settings.s.rxfrc) {
497                     s->status.s.rxne = 0;
498                     s->status.s.idle = 1;
499                     s->status.s.rxs = 0;
500                 }
501             }
502             s->rx_tail_pos = (s->rx_tail_pos + 4) % CTUCAN_RCV_BUF_LEN;
503         } else {
504             val = 0;
505         }
506         break;
507     case CTU_CAN_FD_TX_STATUS:
508         val = s->tx_status.u32;
509         break;
510     case CTU_CAN_FD_TX_PRIORITY:
511         val = s->tx_priority.u32;
512         break;
513     case CTU_CAN_FD_RX_FR_CTR:
514         val = s->rx_fr_ctr.s.rx_fr_ctr_val;
515         break;
516     case CTU_CAN_FD_TX_FR_CTR:
517         val = s->tx_fr_ctr.s.tx_fr_ctr_val;
518         break;
519     case CTU_CAN_FD_YOLO_REG:
520         val = s->yolo_reg.s.yolo_val;
521         break;
522     }
523 
524     val >>= ((addr & 3) << 3);
525     if (size < 8) {
526         val &= ((uint64_t)1 << (size << 3)) - 1;
527     }
528 
529     return val;
530 }
531 
532 bool ctucan_can_receive(CanBusClientState *client)
533 {
534     CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
535 
536     if (!s->mode_settings.s.ena) {
537         return false;
538     }
539 
540     return true; /* always return true, when operation mode */
541 }
542 
543 ssize_t ctucan_receive(CanBusClientState *client, const qemu_can_frame *frames,
544                         size_t frames_cnt)
545 {
546     CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
547     static uint8_t rcv[CTUCAN_MSG_MAX_LEN];
548     int i;
549     int ret = -1;
550     const qemu_can_frame *frame = frames;
551     union ctu_can_fd_int_stat int_stat;
552     int_stat.u32 = 0;
553 
554     if (frames_cnt <= 0) {
555         return 0;
556     }
557 
558     ret = ctucan_frame2buff(frame, rcv);
559 
560     if (s->rx_cnt + ret > CTUCAN_RCV_BUF_LEN) { /* Data overrun. */
561         s->status.s.dor = 1;
562         int_stat.s.doi = 1;
563         s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
564         ctucan_update_irq(s);
565         DPRINTF("Receive FIFO overrun\n");
566         return ret;
567     }
568     s->status.s.idle = 0;
569     s->status.s.rxs = 1;
570     int_stat.s.rxi = 1;
571     if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
572         int_stat.s.rxfi = 1;
573     }
574     s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
575     s->rx_fr_ctr.s.rx_fr_ctr_val++;
576     s->rx_status_rx_settings.s.rxfrc++;
577     for (i = 0; i < ret; i++) {
578         s->rx_buff[(s->rx_tail_pos + s->rx_cnt) % CTUCAN_RCV_BUF_LEN] = rcv[i];
579         s->rx_cnt++;
580     }
581     s->status.s.rxne = 1;
582 
583     ctucan_update_irq(s);
584 
585     return 1;
586 }
587 
588 static CanBusClientInfo ctucan_bus_client_info = {
589     .can_receive = ctucan_can_receive,
590     .receive = ctucan_receive,
591 };
592 
593 
594 int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus)
595 {
596     s->bus_client.info = &ctucan_bus_client_info;
597 
598     if (!bus) {
599         return -EINVAL;
600     }
601 
602     if (can_bus_insert_client(bus, &s->bus_client) < 0) {
603         return -1;
604     }
605 
606     return 0;
607 }
608 
609 void ctucan_disconnect(CtuCanCoreState *s)
610 {
611     can_bus_remove_client(&s->bus_client);
612 }
613 
614 int ctucan_init(CtuCanCoreState *s, qemu_irq irq)
615 {
616     s->irq = irq;
617 
618     qemu_irq_lower(s->irq);
619 
620     ctucan_hardware_reset(s);
621 
622     return 0;
623 }
624 
625 const VMStateDescription vmstate_qemu_ctucan_tx_buffer = {
626     .name = "qemu_ctucan_tx_buffer",
627     .version_id = 1,
628     .minimum_version_id = 1,
629     .minimum_version_id_old = 1,
630     .fields = (VMStateField[]) {
631         VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
632         VMSTATE_END_OF_LIST()
633     }
634 };
635 
636 static int ctucan_post_load(void *opaque, int version_id)
637 {
638     CtuCanCoreState *s = opaque;
639     ctucan_update_irq(s);
640     return 0;
641 }
642 
643 /* VMState is needed for live migration of QEMU images */
644 const VMStateDescription vmstate_ctucan = {
645     .name = "ctucan",
646     .version_id = 1,
647     .minimum_version_id = 1,
648     .minimum_version_id_old = 1,
649     .post_load = ctucan_post_load,
650     .fields = (VMStateField[]) {
651         VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState),
652         VMSTATE_UINT32(status.u32, CtuCanCoreState),
653         VMSTATE_UINT32(int_stat.u32, CtuCanCoreState),
654         VMSTATE_UINT32(int_ena.u32, CtuCanCoreState),
655         VMSTATE_UINT32(int_mask.u32, CtuCanCoreState),
656         VMSTATE_UINT32(brt.u32, CtuCanCoreState),
657         VMSTATE_UINT32(brt_fd.u32, CtuCanCoreState),
658         VMSTATE_UINT32(ewl_erp_fault_state.u32, CtuCanCoreState),
659         VMSTATE_UINT32(rec_tec.u32, CtuCanCoreState),
660         VMSTATE_UINT32(err_norm_err_fd.u32, CtuCanCoreState),
661         VMSTATE_UINT32(ctr_pres.u32, CtuCanCoreState),
662         VMSTATE_UINT32(filter_a_mask.u32, CtuCanCoreState),
663         VMSTATE_UINT32(filter_a_val.u32, CtuCanCoreState),
664         VMSTATE_UINT32(filter_b_mask.u32, CtuCanCoreState),
665         VMSTATE_UINT32(filter_b_val.u32, CtuCanCoreState),
666         VMSTATE_UINT32(filter_c_mask.u32, CtuCanCoreState),
667         VMSTATE_UINT32(filter_c_val.u32, CtuCanCoreState),
668         VMSTATE_UINT32(filter_ran_low.u32, CtuCanCoreState),
669         VMSTATE_UINT32(filter_ran_high.u32, CtuCanCoreState),
670         VMSTATE_UINT32(filter_control_filter_status.u32, CtuCanCoreState),
671         VMSTATE_UINT32(rx_mem_info.u32, CtuCanCoreState),
672         VMSTATE_UINT32(rx_pointers.u32, CtuCanCoreState),
673         VMSTATE_UINT32(rx_status_rx_settings.u32, CtuCanCoreState),
674         VMSTATE_UINT32(tx_status.u32, CtuCanCoreState),
675         VMSTATE_UINT32(tx_priority.u32, CtuCanCoreState),
676         VMSTATE_UINT32(err_capt_alc.u32, CtuCanCoreState),
677         VMSTATE_UINT32(trv_delay_ssp_cfg.u32, CtuCanCoreState),
678         VMSTATE_UINT32(rx_fr_ctr.u32, CtuCanCoreState),
679         VMSTATE_UINT32(tx_fr_ctr.u32, CtuCanCoreState),
680         VMSTATE_UINT32(debug_register.u32, CtuCanCoreState),
681         VMSTATE_UINT32(yolo_reg.u32, CtuCanCoreState),
682         VMSTATE_UINT32(timestamp_low.u32, CtuCanCoreState),
683         VMSTATE_UINT32(timestamp_high.u32, CtuCanCoreState),
684 
685         VMSTATE_STRUCT_ARRAY(tx_buffer, CtuCanCoreState,
686                 CTUCAN_CORE_TXBUF_NUM, 0, vmstate_qemu_ctucan_tx_buffer,
687                 CtuCanCoreMsgBuffer),
688 
689         VMSTATE_BUFFER(rx_buff, CtuCanCoreState),
690         VMSTATE_UINT32(rx_tail_pos, CtuCanCoreState),
691         VMSTATE_UINT32(rx_cnt, CtuCanCoreState),
692         VMSTATE_UINT32(rx_frame_rem, CtuCanCoreState),
693 
694         VMSTATE_END_OF_LIST()
695     }
696 };
697