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