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