]> Git Repo - qemu.git/blob - hw/mipsnet.c
usb-ehci: drop EXECUTING checks.
[qemu.git] / 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_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     int io_base;
37     qemu_irq irq;
38     NICState *nic;
39     NICConf conf;
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(VLANClientState *nc)
71 {
72     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
73
74     if (s->busy)
75         return 0;
76     return !mipsnet_buffer_full(s);
77 }
78
79 static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
80 {
81     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
82
83 #ifdef DEBUG_MIPSNET_RECEIVE
84     printf("mipsnet: receiving len=%zu\n", size);
85 #endif
86     if (!mipsnet_can_receive(nc))
87         return -1;
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     return size;
104 }
105
106 static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
107 {
108     MIPSnetState *s = opaque;
109     int ret = 0;
110
111     addr &= 0x3f;
112     switch (addr) {
113     case MIPSNET_DEV_ID:
114         ret = be32_to_cpu(0x4d495053);          /* MIPS */
115         break;
116     case MIPSNET_DEV_ID + 4:
117         ret = be32_to_cpu(0x4e455430);          /* NET0 */
118         break;
119     case MIPSNET_BUSY:
120         ret = s->busy;
121         break;
122     case MIPSNET_RX_DATA_COUNT:
123         ret = s->rx_count;
124         break;
125     case MIPSNET_TX_DATA_COUNT:
126         ret = s->tx_count;
127         break;
128     case MIPSNET_INT_CTL:
129         ret = s->intctl;
130         s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
131         break;
132     case MIPSNET_INTERRUPT_INFO:
133         /* XXX: This seems to be a per-VPE interrupt number. */
134         ret = 0;
135         break;
136     case MIPSNET_RX_DATA_BUFFER:
137         if (s->rx_count) {
138             s->rx_count--;
139             ret = s->rx_buffer[s->rx_read++];
140         }
141         break;
142     /* Reads as zero. */
143     case MIPSNET_TX_DATA_BUFFER:
144     default:
145         break;
146     }
147 #ifdef DEBUG_MIPSNET_DATA
148     printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
149 #endif
150     return ret;
151 }
152
153 static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
154 {
155     MIPSnetState *s = opaque;
156
157     addr &= 0x3f;
158 #ifdef DEBUG_MIPSNET_DATA
159     printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
160 #endif
161     switch (addr) {
162     case MIPSNET_TX_DATA_COUNT:
163         s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
164         s->tx_written = 0;
165         break;
166     case MIPSNET_INT_CTL:
167         if (val & MIPSNET_INTCTL_TXDONE) {
168             s->intctl &= ~MIPSNET_INTCTL_TXDONE;
169         } else if (val & MIPSNET_INTCTL_RXDONE) {
170             s->intctl &= ~MIPSNET_INTCTL_RXDONE;
171         } else if (val & MIPSNET_INTCTL_TESTBIT) {
172             mipsnet_reset(s);
173             s->intctl |= MIPSNET_INTCTL_TESTBIT;
174         } else if (!val) {
175             /* ACK testbit interrupt, flag was cleared on read. */
176         }
177         s->busy = !!s->intctl;
178         mipsnet_update_irq(s);
179         break;
180     case MIPSNET_TX_DATA_BUFFER:
181         s->tx_buffer[s->tx_written++] = val;
182         if (s->tx_written == s->tx_count) {
183             /* Send buffer. */
184 #ifdef DEBUG_MIPSNET_SEND
185             printf("mipsnet: sending len=%d\n", s->tx_count);
186 #endif
187             qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
188             s->tx_count = s->tx_written = 0;
189             s->intctl |= MIPSNET_INTCTL_TXDONE;
190             s->busy = 1;
191             mipsnet_update_irq(s);
192         }
193         break;
194     /* Read-only registers */
195     case MIPSNET_DEV_ID:
196     case MIPSNET_BUSY:
197     case MIPSNET_RX_DATA_COUNT:
198     case MIPSNET_INTERRUPT_INFO:
199     case MIPSNET_RX_DATA_BUFFER:
200     default:
201         break;
202     }
203 }
204
205 static const VMStateDescription vmstate_mipsnet = {
206     .name = "mipsnet",
207     .version_id = 0,
208     .minimum_version_id = 0,
209     .minimum_version_id_old = 0,
210     .fields      = (VMStateField[]) {
211         VMSTATE_UINT32(busy, MIPSnetState),
212         VMSTATE_UINT32(rx_count, MIPSnetState),
213         VMSTATE_UINT32(rx_read, MIPSnetState),
214         VMSTATE_UINT32(tx_count, MIPSnetState),
215         VMSTATE_UINT32(tx_written, MIPSnetState),
216         VMSTATE_UINT32(intctl, MIPSnetState),
217         VMSTATE_BUFFER(rx_buffer, MIPSnetState),
218         VMSTATE_BUFFER(tx_buffer, MIPSnetState),
219         VMSTATE_END_OF_LIST()
220     }
221 };
222
223 static void mipsnet_cleanup(VLANClientState *nc)
224 {
225     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
226
227     vmstate_unregister(NULL, &vmstate_mipsnet, s);
228
229     isa_unassign_ioport(s->io_base, 36);
230
231     qemu_free(s);
232 }
233
234 static NetClientInfo net_mipsnet_info = {
235     .type = NET_CLIENT_TYPE_NIC,
236     .size = sizeof(NICState),
237     .can_receive = mipsnet_can_receive,
238     .receive = mipsnet_receive,
239     .cleanup = mipsnet_cleanup,
240 };
241
242 void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
243 {
244     MIPSnetState *s;
245
246     qemu_check_nic_model(nd, "mipsnet");
247
248     s = qemu_mallocz(sizeof(MIPSnetState));
249
250     register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
251     register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
252     register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
253     register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
254     register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
255     register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
256
257     s->io_base = base;
258     s->irq = irq;
259
260     if (nd) {
261         memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
262         s->conf.vlan = nd->vlan;
263         s->conf.peer = nd->netdev;
264
265         s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
266                               nd->model, nd->name, s);
267
268         qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
269     }
270
271     mipsnet_reset(s);
272     vmstate_register(NULL, 0, &vmstate_mipsnet, s);
273 }
This page took 0.037484 seconds and 4 git commands to generate.