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