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