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