qemu

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

mipsnet.c (7996B)


      1 #include "qemu/osdep.h"
      2 #include "hw/irq.h"
      3 #include "hw/qdev-properties.h"
      4 #include "net/net.h"
      5 #include "qemu/module.h"
      6 #include "trace.h"
      7 #include "hw/sysbus.h"
      8 #include "migration/vmstate.h"
      9 #include "qom/object.h"
     10 
     11 /* MIPSnet register offsets */
     12 
     13 #define MIPSNET_DEV_ID          0x00
     14 #define MIPSNET_BUSY            0x08
     15 #define MIPSNET_RX_DATA_COUNT   0x0c
     16 #define MIPSNET_TX_DATA_COUNT   0x10
     17 #define MIPSNET_INT_CTL         0x14
     18 # define MIPSNET_INTCTL_TXDONE          0x00000001
     19 # define MIPSNET_INTCTL_RXDONE          0x00000002
     20 # define MIPSNET_INTCTL_TESTBIT         0x80000000
     21 #define MIPSNET_INTERRUPT_INFO  0x18
     22 #define MIPSNET_RX_DATA_BUFFER  0x1c
     23 #define MIPSNET_TX_DATA_BUFFER  0x20
     24 
     25 #define MAX_ETH_FRAME_SIZE      1514
     26 
     27 #define TYPE_MIPS_NET "mipsnet"
     28 OBJECT_DECLARE_SIMPLE_TYPE(MIPSnetState, MIPS_NET)
     29 
     30 struct MIPSnetState {
     31     SysBusDevice parent_obj;
     32 
     33     uint32_t busy;
     34     uint32_t rx_count;
     35     uint32_t rx_read;
     36     uint32_t tx_count;
     37     uint32_t tx_written;
     38     uint32_t intctl;
     39     uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
     40     uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
     41     MemoryRegion io;
     42     qemu_irq irq;
     43     NICState *nic;
     44     NICConf conf;
     45 };
     46 
     47 static void mipsnet_reset(MIPSnetState *s)
     48 {
     49     s->busy = 1;
     50     s->rx_count = 0;
     51     s->rx_read = 0;
     52     s->tx_count = 0;
     53     s->tx_written = 0;
     54     s->intctl = 0;
     55     memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
     56     memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
     57 }
     58 
     59 static void mipsnet_update_irq(MIPSnetState *s)
     60 {
     61     int isr = !!s->intctl;
     62     trace_mipsnet_irq(isr, s->intctl);
     63     qemu_set_irq(s->irq, isr);
     64 }
     65 
     66 static int mipsnet_buffer_full(MIPSnetState *s)
     67 {
     68     if (s->rx_count >= MAX_ETH_FRAME_SIZE) {
     69         return 1;
     70     }
     71     return 0;
     72 }
     73 
     74 static int mipsnet_can_receive(NetClientState *nc)
     75 {
     76     MIPSnetState *s = qemu_get_nic_opaque(nc);
     77 
     78     if (s->busy) {
     79         return 0;
     80     }
     81     return !mipsnet_buffer_full(s);
     82 }
     83 
     84 static ssize_t mipsnet_receive(NetClientState *nc,
     85                                const uint8_t *buf, size_t size)
     86 {
     87     MIPSnetState *s = qemu_get_nic_opaque(nc);
     88 
     89     trace_mipsnet_receive(size);
     90     if (!mipsnet_can_receive(nc)) {
     91         return 0;
     92     }
     93 
     94     if (size >= sizeof(s->rx_buffer)) {
     95         return 0;
     96     }
     97     s->busy = 1;
     98 
     99     /* Just accept everything. */
    100 
    101     /* Write packet data. */
    102     memcpy(s->rx_buffer, buf, size);
    103 
    104     s->rx_count = size;
    105     s->rx_read = 0;
    106 
    107     /* Now we can signal we have received something. */
    108     s->intctl |= MIPSNET_INTCTL_RXDONE;
    109     mipsnet_update_irq(s);
    110 
    111     return size;
    112 }
    113 
    114 static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
    115                                     unsigned int size)
    116 {
    117     MIPSnetState *s = opaque;
    118     int ret = 0;
    119 
    120     addr &= 0x3f;
    121     switch (addr) {
    122     case MIPSNET_DEV_ID:
    123         ret = be32_to_cpu(0x4d495053);          /* MIPS */
    124         break;
    125     case MIPSNET_DEV_ID + 4:
    126         ret = be32_to_cpu(0x4e455430);          /* NET0 */
    127         break;
    128     case MIPSNET_BUSY:
    129         ret = s->busy;
    130         break;
    131     case MIPSNET_RX_DATA_COUNT:
    132         ret = s->rx_count;
    133         break;
    134     case MIPSNET_TX_DATA_COUNT:
    135         ret = s->tx_count;
    136         break;
    137     case MIPSNET_INT_CTL:
    138         ret = s->intctl;
    139         s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
    140         break;
    141     case MIPSNET_INTERRUPT_INFO:
    142         /* XXX: This seems to be a per-VPE interrupt number. */
    143         ret = 0;
    144         break;
    145     case MIPSNET_RX_DATA_BUFFER:
    146         if (s->rx_count) {
    147             s->rx_count--;
    148             ret = s->rx_buffer[s->rx_read++];
    149             if (mipsnet_can_receive(s->nic->ncs)) {
    150                 qemu_flush_queued_packets(qemu_get_queue(s->nic));
    151             }
    152         }
    153         break;
    154     /* Reads as zero. */
    155     case MIPSNET_TX_DATA_BUFFER:
    156     default:
    157         break;
    158     }
    159     trace_mipsnet_read(addr, ret);
    160     return ret;
    161 }
    162 
    163 static void mipsnet_ioport_write(void *opaque, hwaddr addr,
    164                                  uint64_t val, unsigned int size)
    165 {
    166     MIPSnetState *s = opaque;
    167 
    168     addr &= 0x3f;
    169     trace_mipsnet_write(addr, val);
    170     switch (addr) {
    171     case MIPSNET_TX_DATA_COUNT:
    172         s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
    173         s->tx_written = 0;
    174         break;
    175     case MIPSNET_INT_CTL:
    176         if (val & MIPSNET_INTCTL_TXDONE) {
    177             s->intctl &= ~MIPSNET_INTCTL_TXDONE;
    178         } else if (val & MIPSNET_INTCTL_RXDONE) {
    179             s->intctl &= ~MIPSNET_INTCTL_RXDONE;
    180         } else if (val & MIPSNET_INTCTL_TESTBIT) {
    181             mipsnet_reset(s);
    182             s->intctl |= MIPSNET_INTCTL_TESTBIT;
    183         } else if (!val) {
    184             /* ACK testbit interrupt, flag was cleared on read. */
    185         }
    186         s->busy = !!s->intctl;
    187         mipsnet_update_irq(s);
    188         if (mipsnet_can_receive(s->nic->ncs)) {
    189             qemu_flush_queued_packets(qemu_get_queue(s->nic));
    190         }
    191         break;
    192     case MIPSNET_TX_DATA_BUFFER:
    193         s->tx_buffer[s->tx_written++] = val;
    194         if ((s->tx_written >= MAX_ETH_FRAME_SIZE)
    195             || (s->tx_written == s->tx_count)) {
    196             /* Send buffer. */
    197             trace_mipsnet_send(s->tx_written);
    198             qemu_send_packet(qemu_get_queue(s->nic),
    199                                 s->tx_buffer, s->tx_written);
    200             s->tx_count = s->tx_written = 0;
    201             s->intctl |= MIPSNET_INTCTL_TXDONE;
    202             s->busy = 1;
    203             mipsnet_update_irq(s);
    204         }
    205         break;
    206     /* Read-only registers */
    207     case MIPSNET_DEV_ID:
    208     case MIPSNET_BUSY:
    209     case MIPSNET_RX_DATA_COUNT:
    210     case MIPSNET_INTERRUPT_INFO:
    211     case MIPSNET_RX_DATA_BUFFER:
    212     default:
    213         break;
    214     }
    215 }
    216 
    217 static const VMStateDescription vmstate_mipsnet = {
    218     .name = "mipsnet",
    219     .version_id = 0,
    220     .minimum_version_id = 0,
    221     .fields = (VMStateField[]) {
    222         VMSTATE_UINT32(busy, MIPSnetState),
    223         VMSTATE_UINT32(rx_count, MIPSnetState),
    224         VMSTATE_UINT32(rx_read, MIPSnetState),
    225         VMSTATE_UINT32(tx_count, MIPSnetState),
    226         VMSTATE_UINT32(tx_written, MIPSnetState),
    227         VMSTATE_UINT32(intctl, MIPSnetState),
    228         VMSTATE_BUFFER(rx_buffer, MIPSnetState),
    229         VMSTATE_BUFFER(tx_buffer, MIPSnetState),
    230         VMSTATE_END_OF_LIST()
    231     }
    232 };
    233 
    234 static NetClientInfo net_mipsnet_info = {
    235     .type = NET_CLIENT_DRIVER_NIC,
    236     .size = sizeof(NICState),
    237     .receive = mipsnet_receive,
    238 };
    239 
    240 static const MemoryRegionOps mipsnet_ioport_ops = {
    241     .read = mipsnet_ioport_read,
    242     .write = mipsnet_ioport_write,
    243     .impl.min_access_size = 1,
    244     .impl.max_access_size = 4,
    245 };
    246 
    247 static void mipsnet_realize(DeviceState *dev, Error **errp)
    248 {
    249     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    250     MIPSnetState *s = MIPS_NET(dev);
    251 
    252     memory_region_init_io(&s->io, OBJECT(dev), &mipsnet_ioport_ops, s,
    253                           "mipsnet-io", 36);
    254     sysbus_init_mmio(sbd, &s->io);
    255     sysbus_init_irq(sbd, &s->irq);
    256 
    257     s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
    258                           object_get_typename(OBJECT(dev)), dev->id, s);
    259     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
    260 }
    261 
    262 static void mipsnet_sysbus_reset(DeviceState *dev)
    263 {
    264     MIPSnetState *s = MIPS_NET(dev);
    265     mipsnet_reset(s);
    266 }
    267 
    268 static Property mipsnet_properties[] = {
    269     DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
    270     DEFINE_PROP_END_OF_LIST(),
    271 };
    272 
    273 static void mipsnet_class_init(ObjectClass *klass, void *data)
    274 {
    275     DeviceClass *dc = DEVICE_CLASS(klass);
    276 
    277     dc->realize = mipsnet_realize;
    278     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
    279     dc->desc = "MIPS Simulator network device";
    280     dc->reset = mipsnet_sysbus_reset;
    281     dc->vmsd = &vmstate_mipsnet;
    282     device_class_set_props(dc, mipsnet_properties);
    283 }
    284 
    285 static const TypeInfo mipsnet_info = {
    286     .name          = TYPE_MIPS_NET,
    287     .parent        = TYPE_SYS_BUS_DEVICE,
    288     .instance_size = sizeof(MIPSnetState),
    289     .class_init    = mipsnet_class_init,
    290 };
    291 
    292 static void mipsnet_register_types(void)
    293 {
    294     type_register_static(&mipsnet_info);
    295 }
    296 
    297 type_init(mipsnet_register_types)