xref: /qemu/hw/net/can/ctucan_core.c (revision 019fbfa4bcd2d3a835c241295e22ab2b5b56129b)
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 
ctucan_buff2frame(const uint8_t * buff,qemu_can_frame * frame)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 
ctucan_frame2buff(const qemu_can_frame * frame,uint8_t * buff)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 
ctucan_update_irq(CtuCanCoreState * s)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 
ctucan_update_txnf(CtuCanCoreState * s)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 
ctucan_hardware_reset(CtuCanCoreState * s)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 
ctucan_send_ready_buffers(CtuCanCoreState * s)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 
ctucan_mem_write(CtuCanCoreState * s,hwaddr addr,uint64_t val,unsigned size)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 
ctucan_mem_read(CtuCanCoreState * s,hwaddr addr,unsigned size)405 uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size)
406 {
407     uint32_t val = 0;
408 
409     DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr);
410 
411     if (addr > CTUCAN_CORE_MEM_SIZE) {
412         return 0;
413     }
414 
415     switch (addr & ~3) {
416     case CTU_CAN_FD_DEVICE_ID:
417         {
418             union ctu_can_fd_device_id_version idver;
419             idver.u32 = 0;
420             idver.s.device_id = CTU_CAN_FD_ID;
421             idver.s.ver_major = 2;
422             idver.s.ver_minor = 2;
423             val = idver.u32;
424         }
425         break;
426     case CTU_CAN_FD_MODE:
427         val = s->mode_settings.u32;
428         break;
429     case CTU_CAN_FD_STATUS:
430         val = s->status.u32;
431         break;
432     case CTU_CAN_FD_INT_STAT:
433         val = s->int_stat.u32;
434         break;
435     case CTU_CAN_FD_INT_ENA_SET:
436     case CTU_CAN_FD_INT_ENA_CLR:
437         val = s->int_ena.u32;
438         break;
439     case CTU_CAN_FD_INT_MASK_SET:
440     case CTU_CAN_FD_INT_MASK_CLR:
441         val = s->int_mask.u32;
442         break;
443     case CTU_CAN_FD_RX_MEM_INFO:
444         s->rx_mem_info.u32 = 0;
445         s->rx_mem_info.s.rx_buff_size = CTUCAN_RCV_BUF_LEN >> 2;
446         s->rx_mem_info.s.rx_mem_free = (CTUCAN_RCV_BUF_LEN -
447                                         s->rx_cnt) >> 2;
448         val = s->rx_mem_info.u32;
449         break;
450     case CTU_CAN_FD_RX_POINTERS:
451     {
452         uint32_t rx_head_pos = s->rx_tail_pos + s->rx_cnt;
453         rx_head_pos %= CTUCAN_RCV_BUF_LEN;
454         s->rx_pointers.s.rx_wpp = rx_head_pos;
455         s->rx_pointers.s.rx_rpp = s->rx_tail_pos;
456         val = s->rx_pointers.u32;
457         break;
458     }
459     case CTU_CAN_FD_RX_STATUS:
460     case CTU_CAN_FD_RX_SETTINGS:
461         if (!s->rx_status_rx_settings.s.rxfrc) {
462             s->rx_status_rx_settings.s.rxe = 1;
463         } else {
464             s->rx_status_rx_settings.s.rxe = 0;
465         }
466         if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
467             s->rx_status_rx_settings.s.rxf = 1;
468         } else {
469             s->rx_status_rx_settings.s.rxf = 0;
470         }
471         val = s->rx_status_rx_settings.u32;
472         break;
473     case CTU_CAN_FD_RX_DATA:
474         if (s->rx_cnt) {
475             memcpy(&val, s->rx_buff + s->rx_tail_pos, 4);
476             val = le32_to_cpu(val);
477             if (!s->rx_frame_rem) {
478                 union ctu_can_fd_frame_form_w frame_form_w;
479                 frame_form_w.u32 = val;
480                 s->rx_frame_rem = frame_form_w.s.rwcnt * 4 + 4;
481             }
482             s->rx_cnt -= 4;
483             s->rx_frame_rem -= 4;
484             if (!s->rx_frame_rem) {
485                 s->rx_status_rx_settings.s.rxfrc--;
486                 if (!s->rx_status_rx_settings.s.rxfrc) {
487                     s->status.s.rxne = 0;
488                     s->status.s.idle = 1;
489                     s->status.s.rxs = 0;
490                 }
491             }
492             s->rx_tail_pos = (s->rx_tail_pos + 4) % CTUCAN_RCV_BUF_LEN;
493         } else {
494             val = 0;
495         }
496         break;
497     case CTU_CAN_FD_TX_STATUS:
498         val = s->tx_status.u32;
499         break;
500     case CTU_CAN_FD_TX_PRIORITY:
501         val = s->tx_priority.u32;
502         break;
503     case CTU_CAN_FD_RX_FR_CTR:
504         val = s->rx_fr_ctr.s.rx_fr_ctr_val;
505         break;
506     case CTU_CAN_FD_TX_FR_CTR:
507         val = s->tx_fr_ctr.s.tx_fr_ctr_val;
508         break;
509     case CTU_CAN_FD_YOLO_REG:
510         val = s->yolo_reg.s.yolo_val;
511         break;
512     }
513 
514     val >>= ((addr & 3) << 3);
515     if (size < 8) {
516         val &= ((uint64_t)1 << (size << 3)) - 1;
517     }
518 
519     return val;
520 }
521 
ctucan_can_receive(CanBusClientState * client)522 bool ctucan_can_receive(CanBusClientState *client)
523 {
524     CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
525 
526     if (!s->mode_settings.s.ena) {
527         return false;
528     }
529 
530     return true; /* always return true, when operation mode */
531 }
532 
ctucan_receive(CanBusClientState * client,const qemu_can_frame * frames,size_t frames_cnt)533 ssize_t ctucan_receive(CanBusClientState *client, const qemu_can_frame *frames,
534                         size_t frames_cnt)
535 {
536     CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
537     static uint8_t rcv[CTUCAN_MSG_MAX_LEN];
538     int i;
539     int ret = -1;
540     const qemu_can_frame *frame = frames;
541     union ctu_can_fd_int_stat int_stat;
542     int_stat.u32 = 0;
543 
544     if (frames_cnt <= 0) {
545         return 0;
546     }
547 
548     ret = ctucan_frame2buff(frame, rcv);
549 
550     if (s->rx_cnt + ret > CTUCAN_RCV_BUF_LEN) { /* Data overrun. */
551         s->status.s.dor = 1;
552         int_stat.s.doi = 1;
553         s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
554         ctucan_update_irq(s);
555         DPRINTF("Receive FIFO overrun\n");
556         return ret;
557     }
558     s->status.s.idle = 0;
559     s->status.s.rxs = 1;
560     int_stat.s.rxi = 1;
561     if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
562         int_stat.s.rxfi = 1;
563     }
564     s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
565     s->rx_fr_ctr.s.rx_fr_ctr_val++;
566     s->rx_status_rx_settings.s.rxfrc++;
567     for (i = 0; i < ret; i++) {
568         s->rx_buff[(s->rx_tail_pos + s->rx_cnt) % CTUCAN_RCV_BUF_LEN] = rcv[i];
569         s->rx_cnt++;
570     }
571     s->status.s.rxne = 1;
572 
573     ctucan_update_irq(s);
574 
575     return 1;
576 }
577 
578 static CanBusClientInfo ctucan_bus_client_info = {
579     .can_receive = ctucan_can_receive,
580     .receive = ctucan_receive,
581 };
582 
583 
ctucan_connect_to_bus(CtuCanCoreState * s,CanBusState * bus)584 int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus)
585 {
586     s->bus_client.info = &ctucan_bus_client_info;
587 
588     if (!bus) {
589         return -EINVAL;
590     }
591 
592     if (can_bus_insert_client(bus, &s->bus_client) < 0) {
593         return -1;
594     }
595 
596     return 0;
597 }
598 
ctucan_disconnect(CtuCanCoreState * s)599 void ctucan_disconnect(CtuCanCoreState *s)
600 {
601     can_bus_remove_client(&s->bus_client);
602 }
603 
ctucan_init(CtuCanCoreState * s,qemu_irq irq)604 int ctucan_init(CtuCanCoreState *s, qemu_irq irq)
605 {
606     s->irq = irq;
607 
608     qemu_irq_lower(s->irq);
609 
610     ctucan_hardware_reset(s);
611 
612     return 0;
613 }
614 
615 const VMStateDescription vmstate_qemu_ctucan_tx_buffer = {
616     .name = "qemu_ctucan_tx_buffer",
617     .version_id = 1,
618     .minimum_version_id = 1,
619     .fields = (const VMStateField[]) {
620         VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
621         VMSTATE_END_OF_LIST()
622     }
623 };
624 
ctucan_post_load(void * opaque,int version_id)625 static int ctucan_post_load(void *opaque, int version_id)
626 {
627     CtuCanCoreState *s = opaque;
628     ctucan_update_irq(s);
629     return 0;
630 }
631 
632 /* VMState is needed for live migration of QEMU images */
633 const VMStateDescription vmstate_ctucan = {
634     .name = "ctucan",
635     .version_id = 1,
636     .minimum_version_id = 1,
637     .post_load = ctucan_post_load,
638     .fields = (const VMStateField[]) {
639         VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState),
640         VMSTATE_UINT32(status.u32, CtuCanCoreState),
641         VMSTATE_UINT32(int_stat.u32, CtuCanCoreState),
642         VMSTATE_UINT32(int_ena.u32, CtuCanCoreState),
643         VMSTATE_UINT32(int_mask.u32, CtuCanCoreState),
644         VMSTATE_UINT32(brt.u32, CtuCanCoreState),
645         VMSTATE_UINT32(brt_fd.u32, CtuCanCoreState),
646         VMSTATE_UINT32(ewl_erp_fault_state.u32, CtuCanCoreState),
647         VMSTATE_UINT32(rec_tec.u32, CtuCanCoreState),
648         VMSTATE_UINT32(err_norm_err_fd.u32, CtuCanCoreState),
649         VMSTATE_UINT32(ctr_pres.u32, CtuCanCoreState),
650         VMSTATE_UINT32(filter_a_mask.u32, CtuCanCoreState),
651         VMSTATE_UINT32(filter_a_val.u32, CtuCanCoreState),
652         VMSTATE_UINT32(filter_b_mask.u32, CtuCanCoreState),
653         VMSTATE_UINT32(filter_b_val.u32, CtuCanCoreState),
654         VMSTATE_UINT32(filter_c_mask.u32, CtuCanCoreState),
655         VMSTATE_UINT32(filter_c_val.u32, CtuCanCoreState),
656         VMSTATE_UINT32(filter_ran_low.u32, CtuCanCoreState),
657         VMSTATE_UINT32(filter_ran_high.u32, CtuCanCoreState),
658         VMSTATE_UINT32(filter_control_filter_status.u32, CtuCanCoreState),
659         VMSTATE_UINT32(rx_mem_info.u32, CtuCanCoreState),
660         VMSTATE_UINT32(rx_pointers.u32, CtuCanCoreState),
661         VMSTATE_UINT32(rx_status_rx_settings.u32, CtuCanCoreState),
662         VMSTATE_UINT32(tx_status.u32, CtuCanCoreState),
663         VMSTATE_UINT32(tx_priority.u32, CtuCanCoreState),
664         VMSTATE_UINT32(err_capt_alc.u32, CtuCanCoreState),
665         VMSTATE_UINT32(trv_delay_ssp_cfg.u32, CtuCanCoreState),
666         VMSTATE_UINT32(rx_fr_ctr.u32, CtuCanCoreState),
667         VMSTATE_UINT32(tx_fr_ctr.u32, CtuCanCoreState),
668         VMSTATE_UINT32(debug_register.u32, CtuCanCoreState),
669         VMSTATE_UINT32(yolo_reg.u32, CtuCanCoreState),
670         VMSTATE_UINT32(timestamp_low.u32, CtuCanCoreState),
671         VMSTATE_UINT32(timestamp_high.u32, CtuCanCoreState),
672 
673         VMSTATE_STRUCT_ARRAY(tx_buffer, CtuCanCoreState,
674                 CTUCAN_CORE_TXBUF_NUM, 0, vmstate_qemu_ctucan_tx_buffer,
675                 CtuCanCoreMsgBuffer),
676 
677         VMSTATE_BUFFER(rx_buff, CtuCanCoreState),
678         VMSTATE_UINT32(rx_tail_pos, CtuCanCoreState),
679         VMSTATE_UINT32(rx_cnt, CtuCanCoreState),
680         VMSTATE_UINT32(rx_frame_rem, CtuCanCoreState),
681 
682         VMSTATE_END_OF_LIST()
683     }
684 };
685