Statistics
| Branch: | Revision:

root / hw / mipsnet.c @ 0be71e32

History | View | Annotate | Download (7.3 kB)

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=%d\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 void mipsnet_save(QEMUFile *f, void *opaque)
206
{
207
    MIPSnetState *s = opaque;
208

    
209
    qemu_put_be32s(f, &s->busy);
210
    qemu_put_be32s(f, &s->rx_count);
211
    qemu_put_be32s(f, &s->rx_read);
212
    qemu_put_be32s(f, &s->tx_count);
213
    qemu_put_be32s(f, &s->tx_written);
214
    qemu_put_be32s(f, &s->intctl);
215
    qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
216
    qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
217
}
218

    
219
static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
220
{
221
    MIPSnetState *s = opaque;
222

    
223
    if (version_id > 0)
224
        return -EINVAL;
225

    
226
    qemu_get_be32s(f, &s->busy);
227
    qemu_get_be32s(f, &s->rx_count);
228
    qemu_get_be32s(f, &s->rx_read);
229
    qemu_get_be32s(f, &s->tx_count);
230
    qemu_get_be32s(f, &s->tx_written);
231
    qemu_get_be32s(f, &s->intctl);
232
    qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
233
    qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
234

    
235
    return 0;
236
}
237

    
238
static void mipsnet_cleanup(VLANClientState *nc)
239
{
240
    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
241

    
242
    unregister_savevm(NULL, "mipsnet", s);
243

    
244
    isa_unassign_ioport(s->io_base, 36);
245

    
246
    qemu_free(s);
247
}
248

    
249
static NetClientInfo net_mipsnet_info = {
250
    .type = NET_CLIENT_TYPE_NIC,
251
    .size = sizeof(NICState),
252
    .can_receive = mipsnet_can_receive,
253
    .receive = mipsnet_receive,
254
    .cleanup = mipsnet_cleanup,
255
};
256

    
257
void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
258
{
259
    MIPSnetState *s;
260

    
261
    qemu_check_nic_model(nd, "mipsnet");
262

    
263
    s = qemu_mallocz(sizeof(MIPSnetState));
264

    
265
    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
266
    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
267
    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
268
    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
269
    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
270
    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
271

    
272
    s->io_base = base;
273
    s->irq = irq;
274

    
275
    if (nd) {
276
        memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
277
        s->conf.vlan = nd->vlan;
278
        s->conf.peer = nd->netdev;
279

    
280
        s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
281
                              nd->model, nd->name, s);
282

    
283
        qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
284
    }
285

    
286
    mipsnet_reset(s);
287
    register_savevm(NULL, "mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
288
}