|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.