(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/mipsnet.c

    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_DEV_ID_STRING  "MIPSNET0"
   15: #define MIPSNET_BUSY            0x08
   16: #define MIPSNET_RX_DATA_COUNT   0x0c
   17: #define MIPSNET_TX_DATA_COUNT   0x10
   18: #define MIPSNET_INT_CTL         0x14
   19: # define MIPSNET_INTCTL_TXDONE          0x00000001
   20: # define MIPSNET_INTCTL_RXDONE          0x00000002
   21: # define MIPSNET_INTCTL_TESTBIT         0x80000000
   22: #define MIPSNET_INTERRUPT_INFO  0x18
   23: #define MIPSNET_RX_DATA_BUFFER  0x1c
   24: #define MIPSNET_TX_DATA_BUFFER  0x20
   25: 
   26: #define MAX_ETH_FRAME_SIZE      1514
   27: 
   28: typedef struct MIPSnetState {
   29:     uint32_t busy;
   30:     uint32_t rx_count;
   31:     uint32_t rx_read;
   32:     uint32_t tx_count;
   33:     uint32_t tx_written;
   34:     uint32_t intctl;
   35:     uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
   36:     uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
   37:     qemu_irq irq;
   38:     VLANClientState *vc;
   39:     NICInfo *nd;
   40: } MIPSnetState;
   41: 
   42: static 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: 
   54: static 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: 
   63: static int mipsnet_buffer_full(MIPSnetState *s)
   64: {
   65:     if (s->rx_count >= MAX_ETH_FRAME_SIZE)
   66:         return 1;
   67:     return 0;
   68: }
   69: 
   70: static int mipsnet_can_receive(void *opaque)
   71: {
   72:     MIPSnetState *s = opaque;
   73: 
   74:     if (s->busy)
   75:         return 0;
   76:     return !mipsnet_buffer_full(s);
   77: }
   78: 
   79: static void mipsnet_receive(void *opaque, const uint8_t *buf, int size)
   80: {
   81:     MIPSnetState *s = opaque;
   82: 
   83: #ifdef DEBUG_MIPSNET_RECEIVE
   84:     printf("mipsnet: receiving len=%d\n", size);
   85: #endif
   86:     if (!mipsnet_can_receive(opaque))
   87:         return;
   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: 
  104: static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
  105: {
  106:     MIPSnetState *s = opaque;
  107:     int ret = 0;
  108:     const char *devid = MIPSNET_DEV_ID_STRING;
  109: 
  110:     addr &= 0x3f;
  111:     switch (addr) {
  112:     case MIPSNET_DEV_ID:
  113:         ret = *((uint32_t *)&devid);
  114:         break;
  115:     case MIPSNET_DEV_ID + 4:
  116:         ret = *((uint32_t *)(&devid + 4));
  117:         break;
  118:     case MIPSNET_BUSY:
  119:         ret = s->busy;
  120:         break;
  121:     case MIPSNET_RX_DATA_COUNT:
  122:         ret = s->rx_count;
  123:         break;
  124:     case MIPSNET_TX_DATA_COUNT:
  125:         ret = s->tx_count;
  126:         break;
  127:     case MIPSNET_INT_CTL:
  128:         ret = s->intctl;
  129:         s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
  130:         break;
  131:     case MIPSNET_INTERRUPT_INFO:
  132:         /* XXX: This seems to be a per-VPE interrupt number. */
  133:         ret = 0;
  134:         break;
  135:     case MIPSNET_RX_DATA_BUFFER:
  136:         if (s->rx_count) {
  137:             s->rx_count--;
  138:             ret = s->rx_buffer[s->rx_read++];
  139:         }
  140:         break;
  141:     /* Reads as zero. */
  142:     case MIPSNET_TX_DATA_BUFFER:
  143:     default:
  144:         break;
  145:     }
  146: #ifdef DEBUG_MIPSNET_DATA
  147:     printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
  148: #endif
  149:     return ret;
  150: }
  151: 
  152: static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  153: {
  154:     MIPSnetState *s = opaque;
  155: 
  156:     addr &= 0x3f;
  157: #ifdef DEBUG_MIPSNET_DATA
  158:     printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
  159: #endif
  160:     switch (addr) {
  161:     case MIPSNET_TX_DATA_COUNT:
  162:         s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
  163:         s->tx_written = 0;
  164:         break;
  165:     case MIPSNET_INT_CTL:
  166:         if (val & MIPSNET_INTCTL_TXDONE) {
  167:             s->intctl &= ~MIPSNET_INTCTL_TXDONE;
  168:         } else if (val & MIPSNET_INTCTL_RXDONE) {
  169:             s->intctl &= ~MIPSNET_INTCTL_RXDONE;
  170:         } else if (val & MIPSNET_INTCTL_TESTBIT) {
  171:             mipsnet_reset(s);
  172:             s->intctl |= MIPSNET_INTCTL_TESTBIT;
  173:         } else if (!val) {
  174:             /* ACK testbit interrupt, flag was cleared on read. */
  175:         }
  176:         s->busy = !!s->intctl;
  177:         mipsnet_update_irq(s);
  178:         break;
  179:     case MIPSNET_TX_DATA_BUFFER:
  180:         s->tx_buffer[s->tx_written++] = val;
  181:         if (s->tx_written == s->tx_count) {
  182:             /* Send buffer. */
  183: #ifdef DEBUG_MIPSNET_SEND
  184:             printf("mipsnet: sending len=%d\n", s->tx_count);
  185: #endif
  186:             qemu_send_packet(s->vc, s->tx_buffer, s->tx_count);
  187:             s->tx_count = s->tx_written = 0;
  188:             s->intctl |= MIPSNET_INTCTL_TXDONE;
  189:             s->busy = 1;
  190:             mipsnet_update_irq(s);
  191:         }
  192:         break;
  193:     /* Read-only registers */
  194:     case MIPSNET_DEV_ID:
  195:     case MIPSNET_BUSY:
  196:     case MIPSNET_RX_DATA_COUNT:
  197:     case MIPSNET_INTERRUPT_INFO:
  198:     case MIPSNET_RX_DATA_BUFFER:
  199:     default:
  200:         break;
  201:     }
  202: }
  203: 
  204: static void mipsnet_save(QEMUFile *f, void *opaque)
  205: {
  206:     MIPSnetState *s = opaque;
  207: 
  208:     qemu_put_be32s(f, &s->busy);
  209:     qemu_put_be32s(f, &s->rx_count);
  210:     qemu_put_be32s(f, &s->rx_read);
  211:     qemu_put_be32s(f, &s->tx_count);
  212:     qemu_put_be32s(f, &s->tx_written);
  213:     qemu_put_be32s(f, &s->intctl);
  214:     qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
  215:     qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
  216: }
  217: 
  218: static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
  219: {
  220:     MIPSnetState *s = opaque;
  221: 
  222:     if (version_id > 0)
  223:         return -EINVAL;
  224: 
  225:     qemu_get_be32s(f, &s->busy);
  226:     qemu_get_be32s(f, &s->rx_count);
  227:     qemu_get_be32s(f, &s->rx_read);
  228:     qemu_get_be32s(f, &s->tx_count);
  229:     qemu_get_be32s(f, &s->tx_written);
  230:     qemu_get_be32s(f, &s->intctl);
  231:     qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
  232:     qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
  233: 
  234:     return 0;
  235: }
  236: 
  237: void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
  238: {
  239:     MIPSnetState *s;
  240: 
  241:     s = qemu_mallocz(sizeof(MIPSnetState));
  242:     if (!s)
  243:         return;
  244: 
  245:     register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
  246:     register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
  247:     register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
  248:     register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
  249:     register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
  250:     register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
  251: 
  252:     s->irq = irq;
  253:     s->nd = nd;
  254:     if (nd && nd->vlan) {
  255:         s->vc = qemu_new_vlan_client(nd->vlan, mipsnet_receive,
  256:                                      mipsnet_can_receive, s);
  257:     } else {
  258:         s->vc = NULL;
  259:     }
  260: 
  261:     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
  262:              "mipsnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
  263:               s->nd->macaddr[0],
  264:               s->nd->macaddr[1],
  265:               s->nd->macaddr[2],
  266:               s->nd->macaddr[3],
  267:               s->nd->macaddr[4],
  268:               s->nd->macaddr[5]);
  269: 
  270:     mipsnet_reset(s);
  271:     register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
  272: }
Syntax (Markdown)