qemu/hw/net/mipsnet.c
<<
>>
Prefs
   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"
  28OBJECT_DECLARE_SIMPLE_TYPE(MIPSnetState, MIPS_NET)
  29
  30struct 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
  47static 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
  59static 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
  66static 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
  74static 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
  84static 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
 114static 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
 163static 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
 217static 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
 234static NetClientInfo net_mipsnet_info = {
 235    .type = NET_CLIENT_DRIVER_NIC,
 236    .size = sizeof(NICState),
 237    .receive = mipsnet_receive,
 238};
 239
 240static 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
 247static 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
 262static void mipsnet_sysbus_reset(DeviceState *dev)
 263{
 264    MIPSnetState *s = MIPS_NET(dev);
 265    mipsnet_reset(s);
 266}
 267
 268static Property mipsnet_properties[] = {
 269    DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
 270    DEFINE_PROP_END_OF_LIST(),
 271};
 272
 273static 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
 285static 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
 292static void mipsnet_register_types(void)
 293{
 294    type_register_static(&mipsnet_info);
 295}
 296
 297type_init(mipsnet_register_types)
 298