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