symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/mipsnet.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 
       
    27 typedef 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 
       
    41 static 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 
       
    53 static 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 
       
    62 static int mipsnet_buffer_full(MIPSnetState *s)
       
    63 {
       
    64     if (s->rx_count >= MAX_ETH_FRAME_SIZE)
       
    65         return 1;
       
    66     return 0;
       
    67 }
       
    68 
       
    69 static 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 
       
    78 static 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 
       
   103 static 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 
       
   150 static 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 
       
   202 static 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 
       
   216 static 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 
       
   235 void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
       
   236 {
       
   237     MIPSnetState *s;
       
   238 
       
   239     s = qemu_mallocz(sizeof(MIPSnetState));
       
   240     if (!s)
       
   241         return;
       
   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, mipsnet_receive,
       
   254                                      mipsnet_can_receive, s);
       
   255     } else {
       
   256         s->vc = NULL;
       
   257     }
       
   258 
       
   259     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
       
   260              "mipsnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
       
   261               s->nd->macaddr[0],
       
   262               s->nd->macaddr[1],
       
   263               s->nd->macaddr[2],
       
   264               s->nd->macaddr[3],
       
   265               s->nd->macaddr[4],
       
   266               s->nd->macaddr[5]);
       
   267 
       
   268     mipsnet_reset(s);
       
   269     register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
       
   270 }