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
ctucan_buff2frame(const uint8_t * buff,qemu_can_frame * frame)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
ctucan_frame2buff(const qemu_can_frame * frame,uint8_t * buff)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
ctucan_update_irq(CtuCanCoreState * s)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
ctucan_update_txnf(CtuCanCoreState * s)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
ctucan_hardware_reset(CtuCanCoreState * s)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
ctucan_send_ready_buffers(CtuCanCoreState * s)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
244 if (!s->mode_settings.s.ena) {
245 return;
246 }
247
248 do {
249 union ctu_can_fd_int_stat int_stat;
250 int i;
251 buff2tx_idx = -1;
252 tx_prio_max = 0;
253
254 for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
255 uint32_t prio;
256
257 if (extract32(s->tx_status.u32, i * 4, 4) != TXT_RDY) {
258 continue;
259 }
260 prio = (s->tx_priority.u32 >> (i * 4)) & 0x7;
261 if (tx_prio_max < prio) {
262 tx_prio_max = prio;
263 buff2tx_idx = i;
264 }
265 }
266 if (buff2tx_idx == -1) {
267 break;
268 }
269 int_stat.u32 = 0;
270 pf = s->tx_buffer[buff2tx_idx].data;
271 ctucan_buff2frame(pf, &frame);
272 s->status.s.idle = 0;
273 s->status.s.txs = 1;
274 can_bus_client_send(&s->bus_client, &frame, 1);
275 s->status.s.idle = 1;
276 s->status.s.txs = 0;
277 s->tx_fr_ctr.s.tx_fr_ctr_val++;
278 int_stat.s.txi = 1;
279 int_stat.s.txbhci = 1;
280 s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
281 s->tx_status.u32 = deposit32(s->tx_status.u32,
282 buff2tx_idx * 4, 4, TXT_TOK);
283 } while (1);
284 }
285
286 #define CTUCAN_CORE_TXBUFF_SPAN \
287 (CTU_CAN_FD_TXTB2_DATA_1 - CTU_CAN_FD_TXTB1_DATA_1)
288
ctucan_mem_write(CtuCanCoreState * s,hwaddr addr,uint64_t val,unsigned size)289 void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val,
290 unsigned size)
291 {
292 int i;
293
294 DPRINTF("write 0x%02llx addr 0x%02x\n",
295 (unsigned long long)val, (unsigned int)addr);
296
297 if (addr >= CTUCAN_CORE_MEM_SIZE) {
298 return;
299 }
300
301 if (addr >= CTU_CAN_FD_TXTB1_DATA_1) {
302 int buff_num;
303 addr -= CTU_CAN_FD_TXTB1_DATA_1;
304 buff_num = addr / CTUCAN_CORE_TXBUFF_SPAN;
305 addr %= CTUCAN_CORE_TXBUFF_SPAN;
306 if ((buff_num < CTUCAN_CORE_TXBUF_NUM) &&
307 ((addr + size) <= sizeof(s->tx_buffer[buff_num].data))) {
308 stn_le_p(s->tx_buffer[buff_num].data + addr, size, val);
309 }
310 } else {
311 switch (addr & ~3) {
312 case CTU_CAN_FD_MODE:
313 s->mode_settings.u32 = (uint32_t)val;
314 if (s->mode_settings.s.rst) {
315 ctucan_hardware_reset(s);
316 s->mode_settings.s.rst = 0;
317 }
318 break;
319 case CTU_CAN_FD_COMMAND:
320 {
321 union ctu_can_fd_command command;
322 command.u32 = (uint32_t)val;
323 if (command.s.cdo) {
324 s->status.s.dor = 0;
325 }
326 if (command.s.rrb) {
327 s->rx_tail_pos = 0;
328 s->rx_cnt = 0;
329 s->rx_frame_rem = 0;
330 s->rx_status_rx_settings.s.rxfrc = 0;
331 }
332 if (command.s.txfcrst) {
333 s->tx_fr_ctr.s.tx_fr_ctr_val = 0;
334 }
335 if (command.s.rxfcrst) {
336 s->rx_fr_ctr.s.rx_fr_ctr_val = 0;
337 }
338 break;
339 }
340 case CTU_CAN_FD_INT_STAT:
341 s->int_stat.u32 &= ~(uint32_t)val;
342 break;
343 case CTU_CAN_FD_INT_ENA_SET:
344 s->int_ena.u32 |= (uint32_t)val;
345 break;
346 case CTU_CAN_FD_INT_ENA_CLR:
347 s->int_ena.u32 &= ~(uint32_t)val;
348 break;
349 case CTU_CAN_FD_INT_MASK_SET:
350 s->int_mask.u32 |= (uint32_t)val;
351 break;
352 case CTU_CAN_FD_INT_MASK_CLR:
353 s->int_mask.u32 &= ~(uint32_t)val;
354 break;
355 case CTU_CAN_FD_TX_COMMAND:
356 if (s->mode_settings.s.ena) {
357 union ctu_can_fd_tx_command tx_command;
358 union ctu_can_fd_tx_command mask;
359 unsigned int buff_st;
360 uint32_t buff_st_mask;
361
362 tx_command.u32 = (uint32_t)val;
363 mask.u32 = 0;
364 mask.s.txb1 = 1;
365
366 for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) {
367 if (!(tx_command.u32 & (mask.u32 << i))) {
368 continue;
369 }
370 buff_st_mask = 0xf << (i * 4);
371 buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf;
372 if (tx_command.s.txca) {
373 if (buff_st == TXT_RDY) {
374 buff_st = TXT_ABT;
375 }
376 }
377 if (tx_command.s.txcr) {
378 if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
379 (buff_st == TXT_ABT) || (buff_st == TXT_ETY))
380 buff_st = TXT_RDY;
381 }
382 if (tx_command.s.txce) {
383 if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) ||
384 (buff_st == TXT_ABT))
385 buff_st = TXT_ETY;
386 }
387 s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) |
388 (buff_st << (i * 4));
389 }
390
391 ctucan_send_ready_buffers(s);
392 ctucan_update_txnf(s);
393 }
394 break;
395 case CTU_CAN_FD_TX_PRIORITY:
396 s->tx_priority.u32 = (uint32_t)val;
397 break;
398 }
399
400 ctucan_update_irq(s);
401 }
402
403 return;
404 }
405
ctucan_mem_read(CtuCanCoreState * s,hwaddr addr,unsigned size)406 uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size)
407 {
408 uint32_t val = 0;
409
410 DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr);
411
412 if (addr > CTUCAN_CORE_MEM_SIZE) {
413 return 0;
414 }
415
416 switch (addr & ~3) {
417 case CTU_CAN_FD_DEVICE_ID:
418 {
419 union ctu_can_fd_device_id_version idver;
420 idver.u32 = 0;
421 idver.s.device_id = CTU_CAN_FD_ID;
422 idver.s.ver_major = 2;
423 idver.s.ver_minor = 2;
424 val = idver.u32;
425 }
426 break;
427 case CTU_CAN_FD_MODE:
428 val = s->mode_settings.u32;
429 break;
430 case CTU_CAN_FD_STATUS:
431 val = s->status.u32;
432 break;
433 case CTU_CAN_FD_INT_STAT:
434 val = s->int_stat.u32;
435 break;
436 case CTU_CAN_FD_INT_ENA_SET:
437 case CTU_CAN_FD_INT_ENA_CLR:
438 val = s->int_ena.u32;
439 break;
440 case CTU_CAN_FD_INT_MASK_SET:
441 case CTU_CAN_FD_INT_MASK_CLR:
442 val = s->int_mask.u32;
443 break;
444 case CTU_CAN_FD_RX_MEM_INFO:
445 s->rx_mem_info.u32 = 0;
446 s->rx_mem_info.s.rx_buff_size = CTUCAN_RCV_BUF_LEN >> 2;
447 s->rx_mem_info.s.rx_mem_free = (CTUCAN_RCV_BUF_LEN -
448 s->rx_cnt) >> 2;
449 val = s->rx_mem_info.u32;
450 break;
451 case CTU_CAN_FD_RX_POINTERS:
452 {
453 uint32_t rx_head_pos = s->rx_tail_pos + s->rx_cnt;
454 rx_head_pos %= CTUCAN_RCV_BUF_LEN;
455 s->rx_pointers.s.rx_wpp = rx_head_pos;
456 s->rx_pointers.s.rx_rpp = s->rx_tail_pos;
457 val = s->rx_pointers.u32;
458 break;
459 }
460 case CTU_CAN_FD_RX_STATUS:
461 case CTU_CAN_FD_RX_SETTINGS:
462 if (!s->rx_status_rx_settings.s.rxfrc) {
463 s->rx_status_rx_settings.s.rxe = 1;
464 } else {
465 s->rx_status_rx_settings.s.rxe = 0;
466 }
467 if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
468 s->rx_status_rx_settings.s.rxf = 1;
469 } else {
470 s->rx_status_rx_settings.s.rxf = 0;
471 }
472 val = s->rx_status_rx_settings.u32;
473 break;
474 case CTU_CAN_FD_RX_DATA:
475 if (s->rx_cnt) {
476 memcpy(&val, s->rx_buff + s->rx_tail_pos, 4);
477 val = le32_to_cpu(val);
478 if (!s->rx_frame_rem) {
479 union ctu_can_fd_frame_form_w frame_form_w;
480 frame_form_w.u32 = val;
481 s->rx_frame_rem = frame_form_w.s.rwcnt * 4 + 4;
482 }
483 s->rx_cnt -= 4;
484 s->rx_frame_rem -= 4;
485 if (!s->rx_frame_rem) {
486 s->rx_status_rx_settings.s.rxfrc--;
487 if (!s->rx_status_rx_settings.s.rxfrc) {
488 s->status.s.rxne = 0;
489 s->status.s.idle = 1;
490 s->status.s.rxs = 0;
491 }
492 }
493 s->rx_tail_pos = (s->rx_tail_pos + 4) % CTUCAN_RCV_BUF_LEN;
494 } else {
495 val = 0;
496 }
497 break;
498 case CTU_CAN_FD_TX_STATUS:
499 val = s->tx_status.u32;
500 break;
501 case CTU_CAN_FD_TX_PRIORITY:
502 val = s->tx_priority.u32;
503 break;
504 case CTU_CAN_FD_RX_FR_CTR:
505 val = s->rx_fr_ctr.s.rx_fr_ctr_val;
506 break;
507 case CTU_CAN_FD_TX_FR_CTR:
508 val = s->tx_fr_ctr.s.tx_fr_ctr_val;
509 break;
510 case CTU_CAN_FD_YOLO_REG:
511 val = s->yolo_reg.s.yolo_val;
512 break;
513 }
514
515 val >>= ((addr & 3) << 3);
516 if (size < 8) {
517 val &= ((uint64_t)1 << (size << 3)) - 1;
518 }
519
520 return val;
521 }
522
ctucan_can_receive(CanBusClientState * client)523 bool ctucan_can_receive(CanBusClientState *client)
524 {
525 CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
526
527 if (!s->mode_settings.s.ena) {
528 return false;
529 }
530
531 return true; /* always return true, when operation mode */
532 }
533
ctucan_receive(CanBusClientState * client,const qemu_can_frame * frames,size_t frames_cnt)534 ssize_t ctucan_receive(CanBusClientState *client, const qemu_can_frame *frames,
535 size_t frames_cnt)
536 {
537 CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client);
538 static uint8_t rcv[CTUCAN_MSG_MAX_LEN];
539 int i;
540 int ret = -1;
541 const qemu_can_frame *frame = frames;
542 union ctu_can_fd_int_stat int_stat;
543 int_stat.u32 = 0;
544
545 if (frames_cnt <= 0) {
546 return 0;
547 }
548
549 ret = ctucan_frame2buff(frame, rcv);
550
551 if (s->rx_cnt + ret > CTUCAN_RCV_BUF_LEN) { /* Data overrun. */
552 s->status.s.dor = 1;
553 int_stat.s.doi = 1;
554 s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
555 ctucan_update_irq(s);
556 DPRINTF("Receive FIFO overrun\n");
557 return ret;
558 }
559 s->status.s.idle = 0;
560 s->status.s.rxs = 1;
561 int_stat.s.rxi = 1;
562 if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) {
563 int_stat.s.rxfi = 1;
564 }
565 s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32;
566 s->rx_fr_ctr.s.rx_fr_ctr_val++;
567 s->rx_status_rx_settings.s.rxfrc++;
568 for (i = 0; i < ret; i++) {
569 s->rx_buff[(s->rx_tail_pos + s->rx_cnt) % CTUCAN_RCV_BUF_LEN] = rcv[i];
570 s->rx_cnt++;
571 }
572 s->status.s.rxne = 1;
573
574 ctucan_update_irq(s);
575
576 return 1;
577 }
578
579 static CanBusClientInfo ctucan_bus_client_info = {
580 .can_receive = ctucan_can_receive,
581 .receive = ctucan_receive,
582 };
583
584
ctucan_connect_to_bus(CtuCanCoreState * s,CanBusState * bus)585 int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus)
586 {
587 s->bus_client.info = &ctucan_bus_client_info;
588
589 if (!bus) {
590 return -EINVAL;
591 }
592
593 if (can_bus_insert_client(bus, &s->bus_client) < 0) {
594 return -1;
595 }
596
597 return 0;
598 }
599
ctucan_disconnect(CtuCanCoreState * s)600 void ctucan_disconnect(CtuCanCoreState *s)
601 {
602 can_bus_remove_client(&s->bus_client);
603 }
604
ctucan_init(CtuCanCoreState * s,qemu_irq irq)605 int ctucan_init(CtuCanCoreState *s, qemu_irq irq)
606 {
607 s->irq = irq;
608
609 qemu_irq_lower(s->irq);
610
611 ctucan_hardware_reset(s);
612
613 return 0;
614 }
615
616 const VMStateDescription vmstate_qemu_ctucan_tx_buffer = {
617 .name = "qemu_ctucan_tx_buffer",
618 .version_id = 1,
619 .minimum_version_id = 1,
620 .fields = (const VMStateField[]) {
621 VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
622 VMSTATE_END_OF_LIST()
623 }
624 };
625
ctucan_post_load(void * opaque,int version_id)626 static int ctucan_post_load(void *opaque, int version_id)
627 {
628 CtuCanCoreState *s = opaque;
629 ctucan_update_irq(s);
630 return 0;
631 }
632
633 /* VMState is needed for live migration of QEMU images */
634 const VMStateDescription vmstate_ctucan = {
635 .name = "ctucan",
636 .version_id = 1,
637 .minimum_version_id = 1,
638 .post_load = ctucan_post_load,
639 .fields = (const VMStateField[]) {
640 VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState),
641 VMSTATE_UINT32(status.u32, CtuCanCoreState),
642 VMSTATE_UINT32(int_stat.u32, CtuCanCoreState),
643 VMSTATE_UINT32(int_ena.u32, CtuCanCoreState),
644 VMSTATE_UINT32(int_mask.u32, CtuCanCoreState),
645 VMSTATE_UINT32(brt.u32, CtuCanCoreState),
646 VMSTATE_UINT32(brt_fd.u32, CtuCanCoreState),
647 VMSTATE_UINT32(ewl_erp_fault_state.u32, CtuCanCoreState),
648 VMSTATE_UINT32(rec_tec.u32, CtuCanCoreState),
649 VMSTATE_UINT32(err_norm_err_fd.u32, CtuCanCoreState),
650 VMSTATE_UINT32(ctr_pres.u32, CtuCanCoreState),
651 VMSTATE_UINT32(filter_a_mask.u32, CtuCanCoreState),
652 VMSTATE_UINT32(filter_a_val.u32, CtuCanCoreState),
653 VMSTATE_UINT32(filter_b_mask.u32, CtuCanCoreState),
654 VMSTATE_UINT32(filter_b_val.u32, CtuCanCoreState),
655 VMSTATE_UINT32(filter_c_mask.u32, CtuCanCoreState),
656 VMSTATE_UINT32(filter_c_val.u32, CtuCanCoreState),
657 VMSTATE_UINT32(filter_ran_low.u32, CtuCanCoreState),
658 VMSTATE_UINT32(filter_ran_high.u32, CtuCanCoreState),
659 VMSTATE_UINT32(filter_control_filter_status.u32, CtuCanCoreState),
660 VMSTATE_UINT32(rx_mem_info.u32, CtuCanCoreState),
661 VMSTATE_UINT32(rx_pointers.u32, CtuCanCoreState),
662 VMSTATE_UINT32(rx_status_rx_settings.u32, CtuCanCoreState),
663 VMSTATE_UINT32(tx_status.u32, CtuCanCoreState),
664 VMSTATE_UINT32(tx_priority.u32, CtuCanCoreState),
665 VMSTATE_UINT32(err_capt_alc.u32, CtuCanCoreState),
666 VMSTATE_UINT32(trv_delay_ssp_cfg.u32, CtuCanCoreState),
667 VMSTATE_UINT32(rx_fr_ctr.u32, CtuCanCoreState),
668 VMSTATE_UINT32(tx_fr_ctr.u32, CtuCanCoreState),
669 VMSTATE_UINT32(debug_register.u32, CtuCanCoreState),
670 VMSTATE_UINT32(yolo_reg.u32, CtuCanCoreState),
671 VMSTATE_UINT32(timestamp_low.u32, CtuCanCoreState),
672 VMSTATE_UINT32(timestamp_high.u32, CtuCanCoreState),
673
674 VMSTATE_STRUCT_ARRAY(tx_buffer, CtuCanCoreState,
675 CTUCAN_CORE_TXBUF_NUM, 0, vmstate_qemu_ctucan_tx_buffer,
676 CtuCanCoreMsgBuffer),
677
678 VMSTATE_BUFFER(rx_buff, CtuCanCoreState),
679 VMSTATE_UINT32(rx_tail_pos, CtuCanCoreState),
680 VMSTATE_UINT32(rx_cnt, CtuCanCoreState),
681 VMSTATE_UINT32(rx_frame_rem, CtuCanCoreState),
682
683 VMSTATE_END_OF_LIST()
684 }
685 };
686