qemu/hw/mipsnet.c
<<
>>
Prefs
   1#include "hw.h"
   2#include "mips.h"
   3#include "net.h"
   4#include "isa.h"
   5
   6//#define DEBUG_MIPSNET_SEND
   7//#define DEBUG_MIPSNET_RECEIVE
   8//#define DEBUG_MIPSNET_DATA
   9//#define DEBUG_MIPSNET_IRQ
  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
  27typedef struct MIPSnetState {
  28    uint32_t busy;
  29    uint32_t rx_count;
  30    uint32_t rx_read;
  31    uint32_t tx_count;
  32    uint32_t tx_written;
  33    uint32_t intctl;
  34    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
  35    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
  36    int io_base;
  37    qemu_irq irq;
  38    NICState *nic;
  39    NICConf conf;
  40} MIPSnetState;
  41
  42static void mipsnet_reset(MIPSnetState *s)
  43{
  44    s->busy = 1;
  45    s->rx_count = 0;
  46    s->rx_read = 0;
  47    s->tx_count = 0;
  48    s->tx_written = 0;
  49    s->intctl = 0;
  50    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
  51    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
  52}
  53
  54static void mipsnet_update_irq(MIPSnetState *s)
  55{
  56    int isr = !!s->intctl;
  57#ifdef DEBUG_MIPSNET_IRQ
  58    printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
  59#endif
  60    qemu_set_irq(s->irq, isr);
  61}
  62
  63static int mipsnet_buffer_full(MIPSnetState *s)
  64{
  65    if (s->rx_count >= MAX_ETH_FRAME_SIZE)
  66        return 1;
  67    return 0;
  68}
  69
  70static int mipsnet_can_receive(VLANClientState *nc)
  71{
  72    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
  73
  74    if (s->busy)
  75        return 0;
  76    return !mipsnet_buffer_full(s);
  77}
  78
  79static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
  80{
  81    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
  82
  83#ifdef DEBUG_MIPSNET_RECEIVE
  84    printf("mipsnet: receiving len=%d\n", size);
  85#endif
  86    if (!mipsnet_can_receive(nc))
  87        return -1;
  88
  89    s->busy = 1;
  90
  91    /* Just accept everything. */
  92
  93    /* Write packet data. */
  94    memcpy(s->rx_buffer, buf, size);
  95
  96    s->rx_count = size;
  97    s->rx_read = 0;
  98
  99    /* Now we can signal we have received something. */
 100    s->intctl |= MIPSNET_INTCTL_RXDONE;
 101    mipsnet_update_irq(s);
 102
 103    return size;
 104}
 105
 106static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
 107{
 108    MIPSnetState *s = opaque;
 109    int ret = 0;
 110
 111    addr &= 0x3f;
 112    switch (addr) {
 113    case MIPSNET_DEV_ID:
 114        ret = be32_to_cpu(0x4d495053);          /* MIPS */
 115        break;
 116    case MIPSNET_DEV_ID + 4:
 117        ret = be32_to_cpu(0x4e455430);          /* NET0 */
 118        break;
 119    case MIPSNET_BUSY:
 120        ret = s->busy;
 121        break;
 122    case MIPSNET_RX_DATA_COUNT:
 123        ret = s->rx_count;
 124        break;
 125    case MIPSNET_TX_DATA_COUNT:
 126        ret = s->tx_count;
 127        break;
 128    case MIPSNET_INT_CTL:
 129        ret = s->intctl;
 130        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
 131        break;
 132    case MIPSNET_INTERRUPT_INFO:
 133        /* XXX: This seems to be a per-VPE interrupt number. */
 134        ret = 0;
 135        break;
 136    case MIPSNET_RX_DATA_BUFFER:
 137        if (s->rx_count) {
 138            s->rx_count--;
 139            ret = s->rx_buffer[s->rx_read++];
 140        }
 141        break;
 142    /* Reads as zero. */
 143    case MIPSNET_TX_DATA_BUFFER:
 144    default:
 145        break;
 146    }
 147#ifdef DEBUG_MIPSNET_DATA
 148    printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
 149#endif
 150    return ret;
 151}
 152
 153static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 154{
 155    MIPSnetState *s = opaque;
 156
 157    addr &= 0x3f;
 158#ifdef DEBUG_MIPSNET_DATA
 159    printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
 160#endif
 161    switch (addr) {
 162    case MIPSNET_TX_DATA_COUNT:
 163        s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
 164        s->tx_written = 0;
 165        break;
 166    case MIPSNET_INT_CTL:
 167        if (val & MIPSNET_INTCTL_TXDONE) {
 168            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
 169        } else if (val & MIPSNET_INTCTL_RXDONE) {
 170            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
 171        } else if (val & MIPSNET_INTCTL_TESTBIT) {
 172            mipsnet_reset(s);
 173            s->intctl |= MIPSNET_INTCTL_TESTBIT;
 174        } else if (!val) {
 175            /* ACK testbit interrupt, flag was cleared on read. */
 176        }
 177        s->busy = !!s->intctl;
 178        mipsnet_update_irq(s);
 179        break;
 180    case MIPSNET_TX_DATA_BUFFER:
 181        s->tx_buffer[s->tx_written++] = val;
 182        if (s->tx_written == s->tx_count) {
 183            /* Send buffer. */
 184#ifdef DEBUG_MIPSNET_SEND
 185            printf("mipsnet: sending len=%d\n", s->tx_count);
 186#endif
 187            qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
 188            s->tx_count = s->tx_written = 0;
 189            s->intctl |= MIPSNET_INTCTL_TXDONE;
 190            s->busy = 1;
 191            mipsnet_update_irq(s);
 192        }
 193        break;
 194    /* Read-only registers */
 195    case MIPSNET_DEV_ID:
 196    case MIPSNET_BUSY:
 197    case MIPSNET_RX_DATA_COUNT:
 198    case MIPSNET_INTERRUPT_INFO:
 199    case MIPSNET_RX_DATA_BUFFER:
 200    default:
 201        break;
 202    }
 203}
 204
 205static void mipsnet_save(QEMUFile *f, void *opaque)
 206{
 207    MIPSnetState *s = opaque;
 208
 209    qemu_put_be32s(f, &s->busy);
 210    qemu_put_be32s(f, &s->rx_count);
 211    qemu_put_be32s(f, &s->rx_read);
 212    qemu_put_be32s(f, &s->tx_count);
 213    qemu_put_be32s(f, &s->tx_written);
 214    qemu_put_be32s(f, &s->intctl);
 215    qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
 216    qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
 217}
 218
 219static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
 220{
 221    MIPSnetState *s = opaque;
 222
 223    if (version_id > 0)
 224        return -EINVAL;
 225
 226    qemu_get_be32s(f, &s->busy);
 227    qemu_get_be32s(f, &s->rx_count);
 228    qemu_get_be32s(f, &s->rx_read);
 229    qemu_get_be32s(f, &s->tx_count);
 230    qemu_get_be32s(f, &s->tx_written);
 231    qemu_get_be32s(f, &s->intctl);
 232    qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
 233    qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
 234
 235    return 0;
 236}
 237
 238static void mipsnet_cleanup(VLANClientState *nc)
 239{
 240    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 241
 242    unregister_savevm("mipsnet", s);
 243
 244    isa_unassign_ioport(s->io_base, 36);
 245
 246    qemu_free(s);
 247}
 248
 249static NetClientInfo net_mipsnet_info = {
 250    .type = NET_CLIENT_TYPE_NIC,
 251    .size = sizeof(NICState),
 252    .can_receive = mipsnet_can_receive,
 253    .receive = mipsnet_receive,
 254    .cleanup = mipsnet_cleanup,
 255};
 256
 257void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
 258{
 259    MIPSnetState *s;
 260
 261    qemu_check_nic_model(nd, "mipsnet");
 262
 263    s = qemu_mallocz(sizeof(MIPSnetState));
 264
 265    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
 266    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
 267    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
 268    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
 269    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
 270    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
 271
 272    s->io_base = base;
 273    s->irq = irq;
 274
 275    if (nd) {
 276        memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
 277        s->conf.vlan = nd->vlan;
 278        s->conf.peer = nd->netdev;
 279
 280        s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
 281                              nd->model, nd->name, s);
 282
 283        qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 284    }
 285
 286    mipsnet_reset(s);
 287    register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
 288}
 289