|
|
1.1 root 1: #include "hw.h"
2: #include "net.h"
1.1.1.9 root 3: #include "trace.h"
4: #include "sysbus.h"
1.1 root 5:
6: /* MIPSnet register offsets */
7:
8: #define MIPSNET_DEV_ID 0x00
9: #define MIPSNET_BUSY 0x08
10: #define MIPSNET_RX_DATA_COUNT 0x0c
11: #define MIPSNET_TX_DATA_COUNT 0x10
12: #define MIPSNET_INT_CTL 0x14
13: # define MIPSNET_INTCTL_TXDONE 0x00000001
14: # define MIPSNET_INTCTL_RXDONE 0x00000002
15: # define MIPSNET_INTCTL_TESTBIT 0x80000000
16: #define MIPSNET_INTERRUPT_INFO 0x18
17: #define MIPSNET_RX_DATA_BUFFER 0x1c
18: #define MIPSNET_TX_DATA_BUFFER 0x20
19:
20: #define MAX_ETH_FRAME_SIZE 1514
21:
22: typedef struct MIPSnetState {
1.1.1.9 root 23: SysBusDevice busdev;
24:
1.1 root 25: uint32_t busy;
26: uint32_t rx_count;
27: uint32_t rx_read;
28: uint32_t tx_count;
29: uint32_t tx_written;
30: uint32_t intctl;
31: uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
32: uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
1.1.1.9 root 33: MemoryRegion io;
1.1 root 34: qemu_irq irq;
1.1.1.5 root 35: NICState *nic;
36: NICConf conf;
1.1 root 37: } MIPSnetState;
38:
39: static void mipsnet_reset(MIPSnetState *s)
40: {
41: s->busy = 1;
42: s->rx_count = 0;
43: s->rx_read = 0;
44: s->tx_count = 0;
45: s->tx_written = 0;
46: s->intctl = 0;
47: memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
48: memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
49: }
50:
51: static void mipsnet_update_irq(MIPSnetState *s)
52: {
53: int isr = !!s->intctl;
1.1.1.9 root 54: trace_mipsnet_irq(isr, s->intctl);
1.1 root 55: qemu_set_irq(s->irq, isr);
56: }
57:
58: static int mipsnet_buffer_full(MIPSnetState *s)
59: {
60: if (s->rx_count >= MAX_ETH_FRAME_SIZE)
61: return 1;
62: return 0;
63: }
64:
1.1.1.5 root 65: static int mipsnet_can_receive(VLANClientState *nc)
1.1 root 66: {
1.1.1.5 root 67: MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1 root 68:
69: if (s->busy)
70: return 0;
71: return !mipsnet_buffer_full(s);
72: }
73:
1.1.1.5 root 74: static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
1.1 root 75: {
1.1.1.5 root 76: MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1 root 77:
1.1.1.9 root 78: trace_mipsnet_receive(size);
1.1.1.5 root 79: if (!mipsnet_can_receive(nc))
1.1.1.4 root 80: return -1;
1.1 root 81:
82: s->busy = 1;
83:
84: /* Just accept everything. */
85:
86: /* Write packet data. */
87: memcpy(s->rx_buffer, buf, size);
88:
89: s->rx_count = size;
90: s->rx_read = 0;
91:
92: /* Now we can signal we have received something. */
93: s->intctl |= MIPSNET_INTCTL_RXDONE;
94: mipsnet_update_irq(s);
1.1.1.4 root 95:
96: return size;
1.1 root 97: }
98:
1.1.1.9 root 99: static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr,
100: unsigned int size)
1.1 root 101: {
102: MIPSnetState *s = opaque;
103: int ret = 0;
104:
105: addr &= 0x3f;
106: switch (addr) {
107: case MIPSNET_DEV_ID:
1.1.1.2 root 108: ret = be32_to_cpu(0x4d495053); /* MIPS */
1.1 root 109: break;
110: case MIPSNET_DEV_ID + 4:
1.1.1.2 root 111: ret = be32_to_cpu(0x4e455430); /* NET0 */
1.1 root 112: break;
113: case MIPSNET_BUSY:
114: ret = s->busy;
115: break;
116: case MIPSNET_RX_DATA_COUNT:
117: ret = s->rx_count;
118: break;
119: case MIPSNET_TX_DATA_COUNT:
120: ret = s->tx_count;
121: break;
122: case MIPSNET_INT_CTL:
123: ret = s->intctl;
124: s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
125: break;
126: case MIPSNET_INTERRUPT_INFO:
127: /* XXX: This seems to be a per-VPE interrupt number. */
128: ret = 0;
129: break;
130: case MIPSNET_RX_DATA_BUFFER:
131: if (s->rx_count) {
132: s->rx_count--;
133: ret = s->rx_buffer[s->rx_read++];
134: }
135: break;
136: /* Reads as zero. */
137: case MIPSNET_TX_DATA_BUFFER:
138: default:
139: break;
140: }
1.1.1.9 root 141: trace_mipsnet_read(addr, ret);
1.1 root 142: return ret;
143: }
144:
1.1.1.9 root 145: static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
146: uint64_t val, unsigned int size)
1.1 root 147: {
148: MIPSnetState *s = opaque;
149:
150: addr &= 0x3f;
1.1.1.9 root 151: trace_mipsnet_write(addr, val);
1.1 root 152: switch (addr) {
153: case MIPSNET_TX_DATA_COUNT:
154: s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
155: s->tx_written = 0;
156: break;
157: case MIPSNET_INT_CTL:
158: if (val & MIPSNET_INTCTL_TXDONE) {
159: s->intctl &= ~MIPSNET_INTCTL_TXDONE;
160: } else if (val & MIPSNET_INTCTL_RXDONE) {
161: s->intctl &= ~MIPSNET_INTCTL_RXDONE;
162: } else if (val & MIPSNET_INTCTL_TESTBIT) {
163: mipsnet_reset(s);
164: s->intctl |= MIPSNET_INTCTL_TESTBIT;
165: } else if (!val) {
166: /* ACK testbit interrupt, flag was cleared on read. */
167: }
168: s->busy = !!s->intctl;
169: mipsnet_update_irq(s);
170: break;
171: case MIPSNET_TX_DATA_BUFFER:
172: s->tx_buffer[s->tx_written++] = val;
173: if (s->tx_written == s->tx_count) {
174: /* Send buffer. */
1.1.1.9 root 175: trace_mipsnet_send(s->tx_count);
1.1.1.5 root 176: qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
1.1 root 177: s->tx_count = s->tx_written = 0;
178: s->intctl |= MIPSNET_INTCTL_TXDONE;
179: s->busy = 1;
180: mipsnet_update_irq(s);
181: }
182: break;
183: /* Read-only registers */
184: case MIPSNET_DEV_ID:
185: case MIPSNET_BUSY:
186: case MIPSNET_RX_DATA_COUNT:
187: case MIPSNET_INTERRUPT_INFO:
188: case MIPSNET_RX_DATA_BUFFER:
189: default:
190: break;
191: }
192: }
193:
1.1.1.8 root 194: static const VMStateDescription vmstate_mipsnet = {
195: .name = "mipsnet",
196: .version_id = 0,
197: .minimum_version_id = 0,
198: .minimum_version_id_old = 0,
199: .fields = (VMStateField[]) {
200: VMSTATE_UINT32(busy, MIPSnetState),
201: VMSTATE_UINT32(rx_count, MIPSnetState),
202: VMSTATE_UINT32(rx_read, MIPSnetState),
203: VMSTATE_UINT32(tx_count, MIPSnetState),
204: VMSTATE_UINT32(tx_written, MIPSnetState),
205: VMSTATE_UINT32(intctl, MIPSnetState),
206: VMSTATE_BUFFER(rx_buffer, MIPSnetState),
207: VMSTATE_BUFFER(tx_buffer, MIPSnetState),
208: VMSTATE_END_OF_LIST()
209: }
210: };
1.1 root 211:
1.1.1.5 root 212: static void mipsnet_cleanup(VLANClientState *nc)
1.1.1.3 root 213: {
1.1.1.5 root 214: MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1.1.3 root 215:
1.1.1.9 root 216: s->nic = NULL;
1.1.1.3 root 217: }
218:
1.1.1.5 root 219: static NetClientInfo net_mipsnet_info = {
220: .type = NET_CLIENT_TYPE_NIC,
221: .size = sizeof(NICState),
222: .can_receive = mipsnet_can_receive,
223: .receive = mipsnet_receive,
224: .cleanup = mipsnet_cleanup,
225: };
226:
1.1.1.10! root 227: static const MemoryRegionOps mipsnet_ioport_ops = {
1.1.1.9 root 228: .read = mipsnet_ioport_read,
229: .write = mipsnet_ioport_write,
230: .impl.min_access_size = 1,
231: .impl.max_access_size = 4,
232: };
1.1 root 233:
1.1.1.9 root 234: static int mipsnet_sysbus_init(SysBusDevice *dev)
235: {
236: MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
1.1 root 237:
1.1.1.9 root 238: memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
1.1.1.10! root 239: sysbus_init_mmio(dev, &s->io);
1.1.1.9 root 240: sysbus_init_irq(dev, &s->irq);
241:
242: s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
1.1.1.10! root 243: object_get_typename(OBJECT(dev)), dev->qdev.id, s);
1.1.1.9 root 244: qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
1.1 root 245:
1.1.1.9 root 246: return 0;
247: }
1.1.1.5 root 248:
1.1.1.9 root 249: static void mipsnet_sysbus_reset(DeviceState *dev)
250: {
251: MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
252: mipsnet_reset(s);
253: }
1.1.1.5 root 254:
1.1.1.10! root 255: static Property mipsnet_properties[] = {
! 256: DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
! 257: DEFINE_PROP_END_OF_LIST(),
1.1.1.9 root 258: };
1.1 root 259:
1.1.1.10! root 260: static void mipsnet_class_init(ObjectClass *klass, void *data)
1.1.1.9 root 261: {
1.1.1.10! root 262: DeviceClass *dc = DEVICE_CLASS(klass);
! 263: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
! 264:
! 265: k->init = mipsnet_sysbus_init;
! 266: dc->desc = "MIPS Simulator network device";
! 267: dc->reset = mipsnet_sysbus_reset;
! 268: dc->vmsd = &vmstate_mipsnet;
! 269: dc->props = mipsnet_properties;
! 270: }
! 271:
! 272: static TypeInfo mipsnet_info = {
! 273: .name = "mipsnet",
! 274: .parent = TYPE_SYS_BUS_DEVICE,
! 275: .instance_size = sizeof(MIPSnetState),
! 276: .class_init = mipsnet_class_init,
! 277: };
! 278:
! 279: static void mipsnet_register_types(void)
! 280: {
! 281: type_register_static(&mipsnet_info);
1.1 root 282: }
1.1.1.9 root 283:
1.1.1.10! root 284: type_init(mipsnet_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.