qemu

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

ctucan_pci.c (8444B)


      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/event_notifier.h"
     31 #include "qemu/module.h"
     32 #include "qemu/thread.h"
     33 #include "qemu/sockets.h"
     34 #include "qapi/error.h"
     35 #include "chardev/char.h"
     36 #include "hw/irq.h"
     37 #include "hw/pci/pci.h"
     38 #include "hw/qdev-properties.h"
     39 #include "migration/vmstate.h"
     40 #include "net/can_emu.h"
     41 
     42 #include "ctucan_core.h"
     43 
     44 #define TYPE_CTUCAN_PCI_DEV "ctucan_pci"
     45 
     46 typedef struct CtuCanPCIState CtuCanPCIState;
     47 DECLARE_INSTANCE_CHECKER(CtuCanPCIState, CTUCAN_PCI_DEV,
     48                          TYPE_CTUCAN_PCI_DEV)
     49 
     50 #define CTUCAN_PCI_CORE_COUNT     2
     51 #define CTUCAN_PCI_CORE_RANGE     0x10000
     52 
     53 #define CTUCAN_PCI_BAR_COUNT      2
     54 
     55 #define CTUCAN_PCI_BYTES_PER_CORE 0x4000
     56 
     57 #ifndef PCI_VENDOR_ID_TEDIA
     58 #define PCI_VENDOR_ID_TEDIA 0x1760
     59 #endif
     60 
     61 #define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00
     62 
     63 #define CTUCAN_BAR0_RANGE 0x8000
     64 #define CTUCAN_BAR0_CTUCAN_ID 0x0000
     65 #define CTUCAN_BAR0_CRA_BASE  0x4000
     66 #define CYCLONE_IV_CRA_A2P_IE (0x0050)
     67 
     68 #define CTUCAN_WITHOUT_CTUCAN_ID  0
     69 #define CTUCAN_WITH_CTUCAN_ID     1
     70 
     71 struct CtuCanPCIState {
     72     /*< private >*/
     73     PCIDevice       dev;
     74     /*< public >*/
     75     MemoryRegion    ctucan_io[CTUCAN_PCI_BAR_COUNT];
     76 
     77     CtuCanCoreState ctucan_state[CTUCAN_PCI_CORE_COUNT];
     78     qemu_irq        irq;
     79 
     80     char            *model; /* The model that support, only SJA1000 now. */
     81     CanBusState     *canbus[CTUCAN_PCI_CORE_COUNT];
     82 };
     83 
     84 static void ctucan_pci_reset(DeviceState *dev)
     85 {
     86     CtuCanPCIState *d = CTUCAN_PCI_DEV(dev);
     87     int i;
     88 
     89     for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
     90         ctucan_hardware_reset(&d->ctucan_state[i]);
     91     }
     92 }
     93 
     94 static uint64_t ctucan_pci_id_cra_io_read(void *opaque, hwaddr addr,
     95                                           unsigned size)
     96 {
     97     if (addr >= 4) {
     98         return 0;
     99     }
    100 
    101     uint64_t tmp = 0xC0000000 + CTUCAN_PCI_CORE_COUNT;
    102     tmp >>= ((addr & 3) << 3);
    103     if (size < 8) {
    104         tmp &= ((uint64_t)1 << (size << 3)) - 1;
    105     }
    106     return tmp;
    107 }
    108 
    109 static void ctucan_pci_id_cra_io_write(void *opaque, hwaddr addr, uint64_t data,
    110                              unsigned size)
    111 {
    112 
    113 }
    114 
    115 static uint64_t ctucan_pci_cores_io_read(void *opaque, hwaddr addr,
    116                                           unsigned size)
    117 {
    118     CtuCanPCIState *d = opaque;
    119     CtuCanCoreState *s;
    120     hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE;
    121 
    122     if (core_num >= CTUCAN_PCI_CORE_COUNT) {
    123         return 0;
    124     }
    125 
    126     s = &d->ctucan_state[core_num];
    127 
    128     return ctucan_mem_read(s, addr % CTUCAN_PCI_BYTES_PER_CORE, size);
    129 }
    130 
    131 static void ctucan_pci_cores_io_write(void *opaque, hwaddr addr, uint64_t data,
    132                              unsigned size)
    133 {
    134     CtuCanPCIState *d = opaque;
    135     CtuCanCoreState *s;
    136     hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE;
    137 
    138     if (core_num >= CTUCAN_PCI_CORE_COUNT) {
    139         return;
    140     }
    141 
    142     s = &d->ctucan_state[core_num];
    143 
    144     return ctucan_mem_write(s, addr % CTUCAN_PCI_BYTES_PER_CORE, data, size);
    145 }
    146 
    147 static const MemoryRegionOps ctucan_pci_id_cra_io_ops = {
    148     .read = ctucan_pci_id_cra_io_read,
    149     .write = ctucan_pci_id_cra_io_write,
    150     .endianness = DEVICE_LITTLE_ENDIAN,
    151     .impl.min_access_size = 1,
    152     .impl.max_access_size = 4,
    153     .valid.min_access_size = 1,
    154     .valid.max_access_size = 4,
    155 };
    156 
    157 static const MemoryRegionOps ctucan_pci_cores_io_ops = {
    158     .read = ctucan_pci_cores_io_read,
    159     .write = ctucan_pci_cores_io_write,
    160     .endianness = DEVICE_LITTLE_ENDIAN,
    161     .impl.min_access_size = 1,
    162     .impl.max_access_size = 4,
    163     .valid.min_access_size = 1,
    164     .valid.max_access_size = 4,
    165 };
    166 
    167 static void ctucan_pci_realize(PCIDevice *pci_dev, Error **errp)
    168 {
    169     CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev);
    170     uint8_t *pci_conf;
    171     int i;
    172 
    173     pci_conf = pci_dev->config;
    174     pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
    175 
    176     d->irq = pci_allocate_irq(&d->dev);
    177 
    178     for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
    179         ctucan_init(&d->ctucan_state[i], d->irq);
    180     }
    181 
    182     for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
    183         if (ctucan_connect_to_bus(&d->ctucan_state[i], d->canbus[i]) < 0) {
    184             error_setg(errp, "ctucan_connect_to_bus failed");
    185             return;
    186         }
    187     }
    188 
    189     memory_region_init_io(&d->ctucan_io[0], OBJECT(d),
    190                           &ctucan_pci_id_cra_io_ops, d,
    191                           "ctucan_pci-core0", CTUCAN_BAR0_RANGE);
    192     memory_region_init_io(&d->ctucan_io[1], OBJECT(d),
    193                           &ctucan_pci_cores_io_ops, d,
    194                           "ctucan_pci-core1", CTUCAN_PCI_CORE_RANGE);
    195 
    196     for (i = 0 ; i < CTUCAN_PCI_BAR_COUNT; i++) {
    197         pci_register_bar(&d->dev, i, PCI_BASE_ADDRESS_MEM_MASK & 0,
    198                          &d->ctucan_io[i]);
    199     }
    200 }
    201 
    202 static void ctucan_pci_exit(PCIDevice *pci_dev)
    203 {
    204     CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev);
    205     int i;
    206 
    207     for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) {
    208         ctucan_disconnect(&d->ctucan_state[i]);
    209     }
    210 
    211     qemu_free_irq(d->irq);
    212 }
    213 
    214 static const VMStateDescription vmstate_ctucan_pci = {
    215     .name = "ctucan_pci",
    216     .version_id = 1,
    217     .minimum_version_id = 1,
    218     .fields = (VMStateField[]) {
    219         VMSTATE_PCI_DEVICE(dev, CtuCanPCIState),
    220         VMSTATE_STRUCT(ctucan_state[0], CtuCanPCIState, 0, vmstate_ctucan,
    221                        CtuCanCoreState),
    222 #if CTUCAN_PCI_CORE_COUNT >= 2
    223         VMSTATE_STRUCT(ctucan_state[1], CtuCanPCIState, 0, vmstate_ctucan,
    224                        CtuCanCoreState),
    225 #endif
    226         VMSTATE_END_OF_LIST()
    227     }
    228 };
    229 
    230 static void ctucan_pci_instance_init(Object *obj)
    231 {
    232     CtuCanPCIState *d = CTUCAN_PCI_DEV(obj);
    233 
    234     object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
    235                              (Object **)&d->canbus[0],
    236                              qdev_prop_allow_set_link_before_realize, 0);
    237 #if CTUCAN_PCI_CORE_COUNT >= 2
    238     object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
    239                              (Object **)&d->canbus[1],
    240                              qdev_prop_allow_set_link_before_realize, 0);
    241 #endif
    242 }
    243 
    244 static void ctucan_pci_class_init(ObjectClass *klass, void *data)
    245 {
    246     DeviceClass *dc = DEVICE_CLASS(klass);
    247     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    248 
    249     k->realize = ctucan_pci_realize;
    250     k->exit = ctucan_pci_exit;
    251     k->vendor_id = PCI_VENDOR_ID_TEDIA;
    252     k->device_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21;
    253     k->revision = 0x00;
    254     k->class_id = 0x000c09;
    255     k->subsystem_vendor_id = PCI_VENDOR_ID_TEDIA;
    256     k->subsystem_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21;
    257     dc->desc = "CTU CAN PCI";
    258     dc->vmsd = &vmstate_ctucan_pci;
    259     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    260     dc->reset = ctucan_pci_reset;
    261 }
    262 
    263 static const TypeInfo ctucan_pci_info = {
    264     .name          = TYPE_CTUCAN_PCI_DEV,
    265     .parent        = TYPE_PCI_DEVICE,
    266     .instance_size = sizeof(CtuCanPCIState),
    267     .class_init    = ctucan_pci_class_init,
    268     .instance_init = ctucan_pci_instance_init,
    269     .interfaces = (InterfaceInfo[]) {
    270         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    271         { },
    272     },
    273 };
    274 
    275 static void ctucan_pci_register_types(void)
    276 {
    277     type_register_static(&ctucan_pci_info);
    278 }
    279 
    280 type_init(ctucan_pci_register_types)