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