Statistics
| Branch: | Revision:

root / hw / mipsnet.c @ f0fc6f8f

History | View | Annotate | Download (6.9 kB)

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