qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

ctucan_core.c (20533B)


      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    600 void ctucan_disconnect(CtuCanCoreState *s)
    601 {
    602     can_bus_remove_client(&s->bus_client);
    603 }
    604 
    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 = (VMStateField[]) {
    621         VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
    622         VMSTATE_END_OF_LIST()
    623     }
    624 };
    625 
    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 = (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 };