Statistics
| Branch: | Revision:

root / hw / net / smc91c111.c @ 216db403

History | View | Annotate | Download (22.2 kB)

1 5fafdf24 ths
/*
2 80337b66 bellard
 * SMSC 91C111 Ethernet interface emulation
3 80337b66 bellard
 *
4 80337b66 bellard
 * Copyright (c) 2005 CodeSourcery, LLC.
5 80337b66 bellard
 * Written by Paul Brook
6 80337b66 bellard
 *
7 8e31bf38 Matthew Fernandez
 * This code is licensed under the GPL
8 80337b66 bellard
 */
9 80337b66 bellard
10 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
11 1422e32d Paolo Bonzini
#include "net/net.h"
12 bd2be150 Peter Maydell
#include "hw/devices.h"
13 80337b66 bellard
/* For crc32 */
14 80337b66 bellard
#include <zlib.h>
15 80337b66 bellard
16 80337b66 bellard
/* Number of 2k memory pages available.  */
17 80337b66 bellard
#define NUM_PACKETS 4
18 80337b66 bellard
19 926d152e Andreas Färber
#define TYPE_SMC91C111 "smc91c111"
20 926d152e Andreas Färber
#define SMC91C111(obj) OBJECT_CHECK(smc91c111_state, (obj), TYPE_SMC91C111)
21 926d152e Andreas Färber
22 80337b66 bellard
typedef struct {
23 926d152e Andreas Färber
    SysBusDevice parent_obj;
24 926d152e Andreas Färber
25 42a4260f Mark McLoughlin
    NICState *nic;
26 50132156 Gerd Hoffmann
    NICConf conf;
27 80337b66 bellard
    uint16_t tcr;
28 80337b66 bellard
    uint16_t rcr;
29 80337b66 bellard
    uint16_t cr;
30 80337b66 bellard
    uint16_t ctr;
31 80337b66 bellard
    uint16_t gpr;
32 80337b66 bellard
    uint16_t ptr;
33 80337b66 bellard
    uint16_t ercv;
34 d537cf6c pbrook
    qemu_irq irq;
35 80337b66 bellard
    int bank;
36 80337b66 bellard
    int packet_num;
37 80337b66 bellard
    int tx_alloc;
38 80337b66 bellard
    /* Bitmask of allocated packets.  */
39 80337b66 bellard
    int allocated;
40 80337b66 bellard
    int tx_fifo_len;
41 80337b66 bellard
    int tx_fifo[NUM_PACKETS];
42 80337b66 bellard
    int rx_fifo_len;
43 80337b66 bellard
    int rx_fifo[NUM_PACKETS];
44 5198cfd9 bellard
    int tx_fifo_done_len;
45 5198cfd9 bellard
    int tx_fifo_done[NUM_PACKETS];
46 80337b66 bellard
    /* Packet buffer memory.  */
47 5198cfd9 bellard
    uint8_t data[NUM_PACKETS][2048];
48 80337b66 bellard
    uint8_t int_level;
49 80337b66 bellard
    uint8_t int_mask;
50 5a95b51d Peter Maydell
    MemoryRegion mmio;
51 80337b66 bellard
} smc91c111_state;
52 80337b66 bellard
53 3ac59434 Peter Maydell
static const VMStateDescription vmstate_smc91c111 = {
54 3ac59434 Peter Maydell
    .name = "smc91c111",
55 3ac59434 Peter Maydell
    .version_id = 1,
56 3ac59434 Peter Maydell
    .minimum_version_id = 1,
57 3ac59434 Peter Maydell
    .fields      = (VMStateField []) {
58 3ac59434 Peter Maydell
        VMSTATE_UINT16(tcr, smc91c111_state),
59 3ac59434 Peter Maydell
        VMSTATE_UINT16(rcr, smc91c111_state),
60 3ac59434 Peter Maydell
        VMSTATE_UINT16(cr, smc91c111_state),
61 3ac59434 Peter Maydell
        VMSTATE_UINT16(ctr, smc91c111_state),
62 3ac59434 Peter Maydell
        VMSTATE_UINT16(gpr, smc91c111_state),
63 3ac59434 Peter Maydell
        VMSTATE_UINT16(ptr, smc91c111_state),
64 3ac59434 Peter Maydell
        VMSTATE_UINT16(ercv, smc91c111_state),
65 3ac59434 Peter Maydell
        VMSTATE_INT32(bank, smc91c111_state),
66 3ac59434 Peter Maydell
        VMSTATE_INT32(packet_num, smc91c111_state),
67 3ac59434 Peter Maydell
        VMSTATE_INT32(tx_alloc, smc91c111_state),
68 3ac59434 Peter Maydell
        VMSTATE_INT32(allocated, smc91c111_state),
69 3ac59434 Peter Maydell
        VMSTATE_INT32(tx_fifo_len, smc91c111_state),
70 3ac59434 Peter Maydell
        VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
71 3ac59434 Peter Maydell
        VMSTATE_INT32(rx_fifo_len, smc91c111_state),
72 3ac59434 Peter Maydell
        VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
73 3ac59434 Peter Maydell
        VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
74 3ac59434 Peter Maydell
        VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
75 3ac59434 Peter Maydell
        VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
76 3ac59434 Peter Maydell
        VMSTATE_UINT8(int_level, smc91c111_state),
77 3ac59434 Peter Maydell
        VMSTATE_UINT8(int_mask, smc91c111_state),
78 3ac59434 Peter Maydell
        VMSTATE_END_OF_LIST()
79 3ac59434 Peter Maydell
    }
80 3ac59434 Peter Maydell
};
81 3ac59434 Peter Maydell
82 80337b66 bellard
#define RCR_SOFT_RST  0x8000
83 80337b66 bellard
#define RCR_STRIP_CRC 0x0200
84 80337b66 bellard
#define RCR_RXEN      0x0100
85 80337b66 bellard
86 80337b66 bellard
#define TCR_EPH_LOOP  0x2000
87 80337b66 bellard
#define TCR_NOCRC     0x0100
88 80337b66 bellard
#define TCR_PAD_EN    0x0080
89 80337b66 bellard
#define TCR_FORCOL    0x0004
90 80337b66 bellard
#define TCR_LOOP      0x0002
91 80337b66 bellard
#define TCR_TXEN      0x0001
92 80337b66 bellard
93 80337b66 bellard
#define INT_MD        0x80
94 80337b66 bellard
#define INT_ERCV      0x40
95 80337b66 bellard
#define INT_EPH       0x20
96 80337b66 bellard
#define INT_RX_OVRN   0x10
97 80337b66 bellard
#define INT_ALLOC     0x08
98 80337b66 bellard
#define INT_TX_EMPTY  0x04
99 80337b66 bellard
#define INT_TX        0x02
100 80337b66 bellard
#define INT_RCV       0x01
101 80337b66 bellard
102 80337b66 bellard
#define CTR_AUTO_RELEASE  0x0800
103 80337b66 bellard
#define CTR_RELOAD        0x0002
104 80337b66 bellard
#define CTR_STORE         0x0001
105 80337b66 bellard
106 80337b66 bellard
#define RS_ALGNERR      0x8000
107 80337b66 bellard
#define RS_BRODCAST     0x4000
108 80337b66 bellard
#define RS_BADCRC       0x2000
109 80337b66 bellard
#define RS_ODDFRAME     0x1000
110 80337b66 bellard
#define RS_TOOLONG      0x0800
111 80337b66 bellard
#define RS_TOOSHORT     0x0400
112 80337b66 bellard
#define RS_MULTICAST    0x0001
113 80337b66 bellard
114 80337b66 bellard
/* Update interrupt status.  */
115 80337b66 bellard
static void smc91c111_update(smc91c111_state *s)
116 80337b66 bellard
{
117 80337b66 bellard
    int level;
118 80337b66 bellard
119 80337b66 bellard
    if (s->tx_fifo_len == 0)
120 80337b66 bellard
        s->int_level |= INT_TX_EMPTY;
121 5198cfd9 bellard
    if (s->tx_fifo_done_len != 0)
122 5198cfd9 bellard
        s->int_level |= INT_TX;
123 80337b66 bellard
    level = (s->int_level & s->int_mask) != 0;
124 d537cf6c pbrook
    qemu_set_irq(s->irq, level);
125 80337b66 bellard
}
126 80337b66 bellard
127 80337b66 bellard
/* Try to allocate a packet.  Returns 0x80 on failure.  */
128 80337b66 bellard
static int smc91c111_allocate_packet(smc91c111_state *s)
129 80337b66 bellard
{
130 80337b66 bellard
    int i;
131 80337b66 bellard
    if (s->allocated == (1 << NUM_PACKETS) - 1) {
132 80337b66 bellard
        return 0x80;
133 80337b66 bellard
    }
134 80337b66 bellard
135 80337b66 bellard
    for (i = 0; i < NUM_PACKETS; i++) {
136 80337b66 bellard
        if ((s->allocated & (1 << i)) == 0)
137 80337b66 bellard
            break;
138 80337b66 bellard
    }
139 80337b66 bellard
    s->allocated |= 1 << i;
140 80337b66 bellard
    return i;
141 80337b66 bellard
}
142 80337b66 bellard
143 80337b66 bellard
144 80337b66 bellard
/* Process a pending TX allocate.  */
145 80337b66 bellard
static void smc91c111_tx_alloc(smc91c111_state *s)
146 80337b66 bellard
{
147 80337b66 bellard
    s->tx_alloc = smc91c111_allocate_packet(s);
148 80337b66 bellard
    if (s->tx_alloc == 0x80)
149 80337b66 bellard
        return;
150 80337b66 bellard
    s->int_level |= INT_ALLOC;
151 80337b66 bellard
    smc91c111_update(s);
152 80337b66 bellard
}
153 80337b66 bellard
154 80337b66 bellard
/* Remove and item from the RX FIFO.  */
155 80337b66 bellard
static void smc91c111_pop_rx_fifo(smc91c111_state *s)
156 80337b66 bellard
{
157 80337b66 bellard
    int i;
158 80337b66 bellard
159 80337b66 bellard
    s->rx_fifo_len--;
160 80337b66 bellard
    if (s->rx_fifo_len) {
161 80337b66 bellard
        for (i = 0; i < s->rx_fifo_len; i++)
162 80337b66 bellard
            s->rx_fifo[i] = s->rx_fifo[i + 1];
163 80337b66 bellard
        s->int_level |= INT_RCV;
164 80337b66 bellard
    } else {
165 80337b66 bellard
        s->int_level &= ~INT_RCV;
166 80337b66 bellard
    }
167 80337b66 bellard
    smc91c111_update(s);
168 80337b66 bellard
}
169 80337b66 bellard
170 5198cfd9 bellard
/* Remove an item from the TX completion FIFO.  */
171 5198cfd9 bellard
static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
172 5198cfd9 bellard
{
173 5198cfd9 bellard
    int i;
174 5198cfd9 bellard
175 5198cfd9 bellard
    if (s->tx_fifo_done_len == 0)
176 5198cfd9 bellard
        return;
177 5198cfd9 bellard
    s->tx_fifo_done_len--;
178 5198cfd9 bellard
    for (i = 0; i < s->tx_fifo_done_len; i++)
179 5198cfd9 bellard
        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
180 5198cfd9 bellard
}
181 5198cfd9 bellard
182 80337b66 bellard
/* Release the memory allocated to a packet.  */
183 80337b66 bellard
static void smc91c111_release_packet(smc91c111_state *s, int packet)
184 80337b66 bellard
{
185 80337b66 bellard
    s->allocated &= ~(1 << packet);
186 80337b66 bellard
    if (s->tx_alloc == 0x80)
187 80337b66 bellard
        smc91c111_tx_alloc(s);
188 8b7acc79 Sebastian Huber
    qemu_flush_queued_packets(qemu_get_queue(s->nic));
189 80337b66 bellard
}
190 80337b66 bellard
191 80337b66 bellard
/* Flush the TX FIFO.  */
192 80337b66 bellard
static void smc91c111_do_tx(smc91c111_state *s)
193 80337b66 bellard
{
194 80337b66 bellard
    int i;
195 80337b66 bellard
    int len;
196 80337b66 bellard
    int control;
197 80337b66 bellard
    int packetnum;
198 80337b66 bellard
    uint8_t *p;
199 80337b66 bellard
200 80337b66 bellard
    if ((s->tcr & TCR_TXEN) == 0)
201 80337b66 bellard
        return;
202 80337b66 bellard
    if (s->tx_fifo_len == 0)
203 80337b66 bellard
        return;
204 80337b66 bellard
    for (i = 0; i < s->tx_fifo_len; i++) {
205 80337b66 bellard
        packetnum = s->tx_fifo[i];
206 80337b66 bellard
        p = &s->data[packetnum][0];
207 80337b66 bellard
        /* Set status word.  */
208 80337b66 bellard
        *(p++) = 0x01;
209 80337b66 bellard
        *(p++) = 0x40;
210 80337b66 bellard
        len = *(p++);
211 80337b66 bellard
        len |= ((int)*(p++)) << 8;
212 80337b66 bellard
        len -= 6;
213 80337b66 bellard
        control = p[len + 1];
214 80337b66 bellard
        if (control & 0x20)
215 80337b66 bellard
            len++;
216 80337b66 bellard
        /* ??? This overwrites the data following the buffer.
217 80337b66 bellard
           Don't know what real hardware does.  */
218 80337b66 bellard
        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
219 80337b66 bellard
            memset(p + len, 0, 64 - len);
220 80337b66 bellard
            len = 64;
221 80337b66 bellard
        }
222 80337b66 bellard
#if 0
223 22ed1d34 Blue Swirl
        {
224 22ed1d34 Blue Swirl
            int add_crc;
225 22ed1d34 Blue Swirl

226 22ed1d34 Blue Swirl
            /* The card is supposed to append the CRC to the frame.
227 22ed1d34 Blue Swirl
               However none of the other network traffic has the CRC
228 22ed1d34 Blue Swirl
               appended.  Suspect this is low level ethernet detail we
229 22ed1d34 Blue Swirl
               don't need to worry about.  */
230 22ed1d34 Blue Swirl
            add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
231 22ed1d34 Blue Swirl
            if (add_crc) {
232 22ed1d34 Blue Swirl
                uint32_t crc;
233 22ed1d34 Blue Swirl

234 22ed1d34 Blue Swirl
                crc = crc32(~0, p, len);
235 22ed1d34 Blue Swirl
                memcpy(p + len, &crc, 4);
236 22ed1d34 Blue Swirl
                len += 4;
237 22ed1d34 Blue Swirl
            }
238 80337b66 bellard
        }
239 80337b66 bellard
#endif
240 80337b66 bellard
        if (s->ctr & CTR_AUTO_RELEASE)
241 5198cfd9 bellard
            /* Race?  */
242 80337b66 bellard
            smc91c111_release_packet(s, packetnum);
243 5198cfd9 bellard
        else if (s->tx_fifo_done_len < NUM_PACKETS)
244 5198cfd9 bellard
            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
245 b356f76d Jason Wang
        qemu_send_packet(qemu_get_queue(s->nic), p, len);
246 80337b66 bellard
    }
247 80337b66 bellard
    s->tx_fifo_len = 0;
248 80337b66 bellard
    smc91c111_update(s);
249 80337b66 bellard
}
250 80337b66 bellard
251 80337b66 bellard
/* Add a packet to the TX FIFO.  */
252 80337b66 bellard
static void smc91c111_queue_tx(smc91c111_state *s, int packet)
253 80337b66 bellard
{
254 80337b66 bellard
    if (s->tx_fifo_len == NUM_PACKETS)
255 80337b66 bellard
        return;
256 80337b66 bellard
    s->tx_fifo[s->tx_fifo_len++] = packet;
257 80337b66 bellard
    smc91c111_do_tx(s);
258 80337b66 bellard
}
259 80337b66 bellard
260 1e36f6a5 Juha Riihimäki
static void smc91c111_reset(DeviceState *dev)
261 80337b66 bellard
{
262 926d152e Andreas Färber
    smc91c111_state *s = SMC91C111(dev);
263 926d152e Andreas Färber
264 80337b66 bellard
    s->bank = 0;
265 80337b66 bellard
    s->tx_fifo_len = 0;
266 5198cfd9 bellard
    s->tx_fifo_done_len = 0;
267 80337b66 bellard
    s->rx_fifo_len = 0;
268 80337b66 bellard
    s->allocated = 0;
269 80337b66 bellard
    s->packet_num = 0;
270 80337b66 bellard
    s->tx_alloc = 0;
271 80337b66 bellard
    s->tcr = 0;
272 80337b66 bellard
    s->rcr = 0;
273 80337b66 bellard
    s->cr = 0xa0b1;
274 80337b66 bellard
    s->ctr = 0x1210;
275 80337b66 bellard
    s->ptr = 0;
276 80337b66 bellard
    s->ercv = 0x1f;
277 80337b66 bellard
    s->int_level = INT_TX_EMPTY;
278 80337b66 bellard
    s->int_mask = 0;
279 80337b66 bellard
    smc91c111_update(s);
280 80337b66 bellard
}
281 80337b66 bellard
282 80337b66 bellard
#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
283 80337b66 bellard
#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
284 80337b66 bellard
285 a8170e5e Avi Kivity
static void smc91c111_writeb(void *opaque, hwaddr offset,
286 80337b66 bellard
                             uint32_t value)
287 80337b66 bellard
{
288 80337b66 bellard
    smc91c111_state *s = (smc91c111_state *)opaque;
289 80337b66 bellard
290 3b4b86aa Lars Munch
    offset = offset & 0xf;
291 80337b66 bellard
    if (offset == 14) {
292 80337b66 bellard
        s->bank = value;
293 80337b66 bellard
        return;
294 80337b66 bellard
    }
295 80337b66 bellard
    if (offset == 15)
296 80337b66 bellard
        return;
297 80337b66 bellard
    switch (s->bank) {
298 80337b66 bellard
    case 0:
299 80337b66 bellard
        switch (offset) {
300 80337b66 bellard
        case 0: /* TCR */
301 80337b66 bellard
            SET_LOW(tcr, value);
302 80337b66 bellard
            return;
303 80337b66 bellard
        case 1:
304 80337b66 bellard
            SET_HIGH(tcr, value);
305 80337b66 bellard
            return;
306 80337b66 bellard
        case 4: /* RCR */
307 80337b66 bellard
            SET_LOW(rcr, value);
308 80337b66 bellard
            return;
309 80337b66 bellard
        case 5:
310 80337b66 bellard
            SET_HIGH(rcr, value);
311 926d152e Andreas Färber
            if (s->rcr & RCR_SOFT_RST) {
312 926d152e Andreas Färber
                smc91c111_reset(DEVICE(s));
313 926d152e Andreas Färber
            }
314 80337b66 bellard
            return;
315 80337b66 bellard
        case 10: case 11: /* RPCR */
316 80337b66 bellard
            /* Ignored */
317 80337b66 bellard
            return;
318 14da5616 Lars Munch
        case 12: case 13: /* Reserved */
319 14da5616 Lars Munch
            return;
320 80337b66 bellard
        }
321 80337b66 bellard
        break;
322 80337b66 bellard
323 80337b66 bellard
    case 1:
324 80337b66 bellard
        switch (offset) {
325 80337b66 bellard
        case 0: /* CONFIG */
326 80337b66 bellard
            SET_LOW(cr, value);
327 80337b66 bellard
            return;
328 80337b66 bellard
        case 1:
329 80337b66 bellard
            SET_HIGH(cr,value);
330 80337b66 bellard
            return;
331 80337b66 bellard
        case 2: case 3: /* BASE */
332 80337b66 bellard
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
333 80337b66 bellard
            /* Not implemented.  */
334 80337b66 bellard
            return;
335 80337b66 bellard
        case 10: /* Genral Purpose */
336 80337b66 bellard
            SET_LOW(gpr, value);
337 80337b66 bellard
            return;
338 80337b66 bellard
        case 11:
339 80337b66 bellard
            SET_HIGH(gpr, value);
340 80337b66 bellard
            return;
341 80337b66 bellard
        case 12: /* Control */
342 80337b66 bellard
            if (value & 1)
343 80337b66 bellard
                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
344 80337b66 bellard
            if (value & 2)
345 80337b66 bellard
                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
346 80337b66 bellard
            value &= ~3;
347 80337b66 bellard
            SET_LOW(ctr, value);
348 80337b66 bellard
            return;
349 80337b66 bellard
        case 13:
350 80337b66 bellard
            SET_HIGH(ctr, value);
351 80337b66 bellard
            return;
352 80337b66 bellard
        }
353 80337b66 bellard
        break;
354 80337b66 bellard
355 80337b66 bellard
    case 2:
356 80337b66 bellard
        switch (offset) {
357 80337b66 bellard
        case 0: /* MMU Command */
358 80337b66 bellard
            switch (value >> 5) {
359 80337b66 bellard
            case 0: /* no-op */
360 80337b66 bellard
                break;
361 80337b66 bellard
            case 1: /* Allocate for TX.  */
362 80337b66 bellard
                s->tx_alloc = 0x80;
363 80337b66 bellard
                s->int_level &= ~INT_ALLOC;
364 80337b66 bellard
                smc91c111_update(s);
365 80337b66 bellard
                smc91c111_tx_alloc(s);
366 80337b66 bellard
                break;
367 80337b66 bellard
            case 2: /* Reset MMU.  */
368 80337b66 bellard
                s->allocated = 0;
369 80337b66 bellard
                s->tx_fifo_len = 0;
370 5198cfd9 bellard
                s->tx_fifo_done_len = 0;
371 80337b66 bellard
                s->rx_fifo_len = 0;
372 80337b66 bellard
                s->tx_alloc = 0;
373 80337b66 bellard
                break;
374 80337b66 bellard
            case 3: /* Remove from RX FIFO.  */
375 80337b66 bellard
                smc91c111_pop_rx_fifo(s);
376 80337b66 bellard
                break;
377 80337b66 bellard
            case 4: /* Remove from RX FIFO and release.  */
378 80337b66 bellard
                if (s->rx_fifo_len > 0) {
379 80337b66 bellard
                    smc91c111_release_packet(s, s->rx_fifo[0]);
380 80337b66 bellard
                }
381 80337b66 bellard
                smc91c111_pop_rx_fifo(s);
382 80337b66 bellard
                break;
383 80337b66 bellard
            case 5: /* Release.  */
384 80337b66 bellard
                smc91c111_release_packet(s, s->packet_num);
385 80337b66 bellard
                break;
386 80337b66 bellard
            case 6: /* Add to TX FIFO.  */
387 80337b66 bellard
                smc91c111_queue_tx(s, s->packet_num);
388 80337b66 bellard
                break;
389 80337b66 bellard
            case 7: /* Reset TX FIFO.  */
390 80337b66 bellard
                s->tx_fifo_len = 0;
391 5198cfd9 bellard
                s->tx_fifo_done_len = 0;
392 80337b66 bellard
                break;
393 80337b66 bellard
            }
394 80337b66 bellard
            return;
395 80337b66 bellard
        case 1:
396 80337b66 bellard
            /* Ignore.  */
397 80337b66 bellard
            return;
398 80337b66 bellard
        case 2: /* Packet Number Register */
399 80337b66 bellard
            s->packet_num = value;
400 80337b66 bellard
            return;
401 80337b66 bellard
        case 3: case 4: case 5:
402 80337b66 bellard
            /* Should be readonly, but linux writes to them anyway. Ignore.  */
403 80337b66 bellard
            return;
404 80337b66 bellard
        case 6: /* Pointer */
405 80337b66 bellard
            SET_LOW(ptr, value);
406 80337b66 bellard
            return;
407 80337b66 bellard
        case 7:
408 80337b66 bellard
            SET_HIGH(ptr, value);
409 80337b66 bellard
            return;
410 80337b66 bellard
        case 8: case 9: case 10: case 11: /* Data */
411 80337b66 bellard
            {
412 80337b66 bellard
                int p;
413 80337b66 bellard
                int n;
414 80337b66 bellard
415 80337b66 bellard
                if (s->ptr & 0x8000)
416 80337b66 bellard
                    n = s->rx_fifo[0];
417 80337b66 bellard
                else
418 80337b66 bellard
                    n = s->packet_num;
419 80337b66 bellard
                p = s->ptr & 0x07ff;
420 80337b66 bellard
                if (s->ptr & 0x4000) {
421 80337b66 bellard
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
422 80337b66 bellard
                } else {
423 80337b66 bellard
                    p += (offset & 3);
424 80337b66 bellard
                }
425 80337b66 bellard
                s->data[n][p] = value;
426 80337b66 bellard
            }
427 80337b66 bellard
            return;
428 80337b66 bellard
        case 12: /* Interrupt ACK.  */
429 80337b66 bellard
            s->int_level &= ~(value & 0xd6);
430 5198cfd9 bellard
            if (value & INT_TX)
431 5198cfd9 bellard
                smc91c111_pop_tx_fifo_done(s);
432 80337b66 bellard
            smc91c111_update(s);
433 80337b66 bellard
            return;
434 80337b66 bellard
        case 13: /* Interrupt mask.  */
435 80337b66 bellard
            s->int_mask = value;
436 80337b66 bellard
            smc91c111_update(s);
437 80337b66 bellard
            return;
438 80337b66 bellard
        }
439 3a93113a Dong Xu Wang
        break;
440 80337b66 bellard
441 80337b66 bellard
    case 3:
442 80337b66 bellard
        switch (offset) {
443 80337b66 bellard
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
444 80337b66 bellard
            /* Multicast table.  */
445 80337b66 bellard
            /* Not implemented.  */
446 80337b66 bellard
            return;
447 80337b66 bellard
        case 8: case 9: /* Management Interface.  */
448 80337b66 bellard
            /* Not implemented.  */
449 80337b66 bellard
            return;
450 80337b66 bellard
        case 12: /* Early receive.  */
451 80337b66 bellard
            s->ercv = value & 0x1f;
452 89556d17 Peter Maydell
            return;
453 80337b66 bellard
        case 13:
454 80337b66 bellard
            /* Ignore.  */
455 80337b66 bellard
            return;
456 80337b66 bellard
        }
457 80337b66 bellard
        break;
458 80337b66 bellard
    }
459 2ac71179 Paul Brook
    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
460 80337b66 bellard
}
461 80337b66 bellard
462 a8170e5e Avi Kivity
static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
463 80337b66 bellard
{
464 80337b66 bellard
    smc91c111_state *s = (smc91c111_state *)opaque;
465 80337b66 bellard
466 3b4b86aa Lars Munch
    offset = offset & 0xf;
467 80337b66 bellard
    if (offset == 14) {
468 80337b66 bellard
        return s->bank;
469 80337b66 bellard
    }
470 80337b66 bellard
    if (offset == 15)
471 80337b66 bellard
        return 0x33;
472 80337b66 bellard
    switch (s->bank) {
473 80337b66 bellard
    case 0:
474 80337b66 bellard
        switch (offset) {
475 80337b66 bellard
        case 0: /* TCR */
476 80337b66 bellard
            return s->tcr & 0xff;
477 80337b66 bellard
        case 1:
478 80337b66 bellard
            return s->tcr >> 8;
479 80337b66 bellard
        case 2: /* EPH Status */
480 80337b66 bellard
            return 0;
481 80337b66 bellard
        case 3:
482 80337b66 bellard
            return 0x40;
483 80337b66 bellard
        case 4: /* RCR */
484 80337b66 bellard
            return s->rcr & 0xff;
485 80337b66 bellard
        case 5:
486 80337b66 bellard
            return s->rcr >> 8;
487 80337b66 bellard
        case 6: /* Counter */
488 80337b66 bellard
        case 7:
489 80337b66 bellard
            /* Not implemented.  */
490 80337b66 bellard
            return 0;
491 687fa640 ths
        case 8: /* Memory size.  */
492 687fa640 ths
            return NUM_PACKETS;
493 687fa640 ths
        case 9: /* Free memory available.  */
494 80337b66 bellard
            {
495 80337b66 bellard
                int i;
496 80337b66 bellard
                int n;
497 80337b66 bellard
                n = 0;
498 80337b66 bellard
                for (i = 0; i < NUM_PACKETS; i++) {
499 80337b66 bellard
                    if (s->allocated & (1 << i))
500 80337b66 bellard
                        n++;
501 80337b66 bellard
                }
502 80337b66 bellard
                return n;
503 80337b66 bellard
            }
504 80337b66 bellard
        case 10: case 11: /* RPCR */
505 80337b66 bellard
            /* Not implemented.  */
506 80337b66 bellard
            return 0;
507 14da5616 Lars Munch
        case 12: case 13: /* Reserved */
508 14da5616 Lars Munch
            return 0;
509 80337b66 bellard
        }
510 80337b66 bellard
        break;
511 80337b66 bellard
512 80337b66 bellard
    case 1:
513 80337b66 bellard
        switch (offset) {
514 80337b66 bellard
        case 0: /* CONFIG */
515 80337b66 bellard
            return s->cr & 0xff;
516 80337b66 bellard
        case 1:
517 80337b66 bellard
            return s->cr >> 8;
518 80337b66 bellard
        case 2: case 3: /* BASE */
519 80337b66 bellard
            /* Not implemented.  */
520 80337b66 bellard
            return 0;
521 80337b66 bellard
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
522 50132156 Gerd Hoffmann
            return s->conf.macaddr.a[offset - 4];
523 80337b66 bellard
        case 10: /* General Purpose */
524 80337b66 bellard
            return s->gpr & 0xff;
525 80337b66 bellard
        case 11:
526 80337b66 bellard
            return s->gpr >> 8;
527 80337b66 bellard
        case 12: /* Control */
528 80337b66 bellard
            return s->ctr & 0xff;
529 80337b66 bellard
        case 13:
530 80337b66 bellard
            return s->ctr >> 8;
531 80337b66 bellard
        }
532 80337b66 bellard
        break;
533 80337b66 bellard
534 80337b66 bellard
    case 2:
535 80337b66 bellard
        switch (offset) {
536 80337b66 bellard
        case 0: case 1: /* MMUCR Busy bit.  */
537 80337b66 bellard
            return 0;
538 80337b66 bellard
        case 2: /* Packet Number.  */
539 80337b66 bellard
            return s->packet_num;
540 80337b66 bellard
        case 3: /* Allocation Result.  */
541 80337b66 bellard
            return s->tx_alloc;
542 80337b66 bellard
        case 4: /* TX FIFO */
543 5198cfd9 bellard
            if (s->tx_fifo_done_len == 0)
544 80337b66 bellard
                return 0x80;
545 80337b66 bellard
            else
546 5198cfd9 bellard
                return s->tx_fifo_done[0];
547 80337b66 bellard
        case 5: /* RX FIFO */
548 80337b66 bellard
            if (s->rx_fifo_len == 0)
549 80337b66 bellard
                return 0x80;
550 80337b66 bellard
            else
551 80337b66 bellard
                return s->rx_fifo[0];
552 80337b66 bellard
        case 6: /* Pointer */
553 80337b66 bellard
            return s->ptr & 0xff;
554 80337b66 bellard
        case 7:
555 80337b66 bellard
            return (s->ptr >> 8) & 0xf7;
556 80337b66 bellard
        case 8: case 9: case 10: case 11: /* Data */
557 80337b66 bellard
            {
558 80337b66 bellard
                int p;
559 80337b66 bellard
                int n;
560 80337b66 bellard
561 80337b66 bellard
                if (s->ptr & 0x8000)
562 80337b66 bellard
                    n = s->rx_fifo[0];
563 80337b66 bellard
                else
564 80337b66 bellard
                    n = s->packet_num;
565 80337b66 bellard
                p = s->ptr & 0x07ff;
566 80337b66 bellard
                if (s->ptr & 0x4000) {
567 80337b66 bellard
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
568 80337b66 bellard
                } else {
569 80337b66 bellard
                    p += (offset & 3);
570 80337b66 bellard
                }
571 80337b66 bellard
                return s->data[n][p];
572 80337b66 bellard
            }
573 80337b66 bellard
        case 12: /* Interrupt status.  */
574 80337b66 bellard
            return s->int_level;
575 80337b66 bellard
        case 13: /* Interrupt mask.  */
576 80337b66 bellard
            return s->int_mask;
577 80337b66 bellard
        }
578 80337b66 bellard
        break;
579 80337b66 bellard
580 80337b66 bellard
    case 3:
581 80337b66 bellard
        switch (offset) {
582 80337b66 bellard
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
583 80337b66 bellard
            /* Multicast table.  */
584 80337b66 bellard
            /* Not implemented.  */
585 80337b66 bellard
            return 0;
586 80337b66 bellard
        case 8: /* Management Interface.  */
587 80337b66 bellard
            /* Not implemented.  */
588 80337b66 bellard
            return 0x30;
589 80337b66 bellard
        case 9:
590 80337b66 bellard
            return 0x33;
591 80337b66 bellard
        case 10: /* Revision.  */
592 80337b66 bellard
            return 0x91;
593 80337b66 bellard
        case 11:
594 80337b66 bellard
            return 0x33;
595 80337b66 bellard
        case 12:
596 80337b66 bellard
            return s->ercv;
597 80337b66 bellard
        case 13:
598 80337b66 bellard
            return 0;
599 80337b66 bellard
        }
600 80337b66 bellard
        break;
601 80337b66 bellard
    }
602 2ac71179 Paul Brook
    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
603 80337b66 bellard
    return 0;
604 80337b66 bellard
}
605 80337b66 bellard
606 a8170e5e Avi Kivity
static void smc91c111_writew(void *opaque, hwaddr offset,
607 80337b66 bellard
                             uint32_t value)
608 80337b66 bellard
{
609 80337b66 bellard
    smc91c111_writeb(opaque, offset, value & 0xff);
610 80337b66 bellard
    smc91c111_writeb(opaque, offset + 1, value >> 8);
611 80337b66 bellard
}
612 80337b66 bellard
613 a8170e5e Avi Kivity
static void smc91c111_writel(void *opaque, hwaddr offset,
614 80337b66 bellard
                             uint32_t value)
615 80337b66 bellard
{
616 80337b66 bellard
    /* 32-bit writes to offset 0xc only actually write to the bank select
617 80337b66 bellard
       register (offset 0xe)  */
618 8da3ff18 pbrook
    if (offset != 0xc)
619 80337b66 bellard
        smc91c111_writew(opaque, offset, value & 0xffff);
620 80337b66 bellard
    smc91c111_writew(opaque, offset + 2, value >> 16);
621 80337b66 bellard
}
622 80337b66 bellard
623 a8170e5e Avi Kivity
static uint32_t smc91c111_readw(void *opaque, hwaddr offset)
624 80337b66 bellard
{
625 80337b66 bellard
    uint32_t val;
626 80337b66 bellard
    val = smc91c111_readb(opaque, offset);
627 80337b66 bellard
    val |= smc91c111_readb(opaque, offset + 1) << 8;
628 80337b66 bellard
    return val;
629 80337b66 bellard
}
630 80337b66 bellard
631 a8170e5e Avi Kivity
static uint32_t smc91c111_readl(void *opaque, hwaddr offset)
632 80337b66 bellard
{
633 80337b66 bellard
    uint32_t val;
634 80337b66 bellard
    val = smc91c111_readw(opaque, offset);
635 80337b66 bellard
    val |= smc91c111_readw(opaque, offset + 2) << 16;
636 80337b66 bellard
    return val;
637 80337b66 bellard
}
638 80337b66 bellard
639 4e68f7a0 Stefan Hajnoczi
static int smc91c111_can_receive(NetClientState *nc)
640 d861b05e pbrook
{
641 cc1f0f45 Jason Wang
    smc91c111_state *s = qemu_get_nic_opaque(nc);
642 d861b05e pbrook
643 d861b05e pbrook
    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
644 d861b05e pbrook
        return 1;
645 d861b05e pbrook
    if (s->allocated == (1 << NUM_PACKETS) - 1)
646 d861b05e pbrook
        return 0;
647 d861b05e pbrook
    return 1;
648 d861b05e pbrook
}
649 d861b05e pbrook
650 4e68f7a0 Stefan Hajnoczi
static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
651 80337b66 bellard
{
652 cc1f0f45 Jason Wang
    smc91c111_state *s = qemu_get_nic_opaque(nc);
653 80337b66 bellard
    int status;
654 80337b66 bellard
    int packetsize;
655 80337b66 bellard
    uint32_t crc;
656 80337b66 bellard
    int packetnum;
657 80337b66 bellard
    uint8_t *p;
658 80337b66 bellard
659 80337b66 bellard
    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
660 4f1c942b Mark McLoughlin
        return -1;
661 9f083493 ths
    /* Short packets are padded with zeros.  Receiving a packet
662 80337b66 bellard
       < 64 bytes long is considered an error condition.  */
663 80337b66 bellard
    if (size < 64)
664 80337b66 bellard
        packetsize = 64;
665 80337b66 bellard
    else
666 80337b66 bellard
        packetsize = (size & ~1);
667 80337b66 bellard
    packetsize += 6;
668 80337b66 bellard
    crc = (s->rcr & RCR_STRIP_CRC) == 0;
669 80337b66 bellard
    if (crc)
670 80337b66 bellard
        packetsize += 4;
671 80337b66 bellard
    /* TODO: Flag overrun and receive errors.  */
672 80337b66 bellard
    if (packetsize > 2048)
673 4f1c942b Mark McLoughlin
        return -1;
674 80337b66 bellard
    packetnum = smc91c111_allocate_packet(s);
675 80337b66 bellard
    if (packetnum == 0x80)
676 4f1c942b Mark McLoughlin
        return -1;
677 80337b66 bellard
    s->rx_fifo[s->rx_fifo_len++] = packetnum;
678 80337b66 bellard
679 80337b66 bellard
    p = &s->data[packetnum][0];
680 80337b66 bellard
    /* ??? Multicast packets?  */
681 80337b66 bellard
    status = 0;
682 80337b66 bellard
    if (size > 1518)
683 80337b66 bellard
        status |= RS_TOOLONG;
684 80337b66 bellard
    if (size & 1)
685 80337b66 bellard
        status |= RS_ODDFRAME;
686 80337b66 bellard
    *(p++) = status & 0xff;
687 80337b66 bellard
    *(p++) = status >> 8;
688 80337b66 bellard
    *(p++) = packetsize & 0xff;
689 80337b66 bellard
    *(p++) = packetsize >> 8;
690 80337b66 bellard
    memcpy(p, buf, size & ~1);
691 80337b66 bellard
    p += (size & ~1);
692 80337b66 bellard
    /* Pad short packets.  */
693 80337b66 bellard
    if (size < 64) {
694 80337b66 bellard
        int pad;
695 3b46e624 ths
696 80337b66 bellard
        if (size & 1)
697 80337b66 bellard
            *(p++) = buf[size - 1];
698 80337b66 bellard
        pad = 64 - size;
699 80337b66 bellard
        memset(p, 0, pad);
700 80337b66 bellard
        p += pad;
701 80337b66 bellard
        size = 64;
702 80337b66 bellard
    }
703 80337b66 bellard
    /* It's not clear if the CRC should go before or after the last byte in
704 80337b66 bellard
       odd sized packets.  Linux disables the CRC, so that's no help.
705 80337b66 bellard
       The pictures in the documentation show the CRC aligned on a 16-bit
706 80337b66 bellard
       boundary before the last odd byte, so that's what we do.  */
707 80337b66 bellard
    if (crc) {
708 80337b66 bellard
        crc = crc32(~0, buf, size);
709 80337b66 bellard
        *(p++) = crc & 0xff; crc >>= 8;
710 80337b66 bellard
        *(p++) = crc & 0xff; crc >>= 8;
711 80337b66 bellard
        *(p++) = crc & 0xff; crc >>= 8;
712 22ed1d34 Blue Swirl
        *(p++) = crc & 0xff;
713 80337b66 bellard
    }
714 80337b66 bellard
    if (size & 1) {
715 80337b66 bellard
        *(p++) = buf[size - 1];
716 22ed1d34 Blue Swirl
        *p = 0x60;
717 80337b66 bellard
    } else {
718 80337b66 bellard
        *(p++) = 0;
719 22ed1d34 Blue Swirl
        *p = 0x40;
720 80337b66 bellard
    }
721 80337b66 bellard
    /* TODO: Raise early RX interrupt?  */
722 80337b66 bellard
    s->int_level |= INT_RCV;
723 80337b66 bellard
    smc91c111_update(s);
724 4f1c942b Mark McLoughlin
725 4f1c942b Mark McLoughlin
    return size;
726 80337b66 bellard
}
727 80337b66 bellard
728 5a95b51d Peter Maydell
static const MemoryRegionOps smc91c111_mem_ops = {
729 5a95b51d Peter Maydell
    /* The special case for 32 bit writes to 0xc means we can't just
730 5a95b51d Peter Maydell
     * set .impl.min/max_access_size to 1, unfortunately
731 5a95b51d Peter Maydell
     */
732 5a95b51d Peter Maydell
    .old_mmio = {
733 5a95b51d Peter Maydell
        .read = { smc91c111_readb, smc91c111_readw, smc91c111_readl, },
734 5a95b51d Peter Maydell
        .write = { smc91c111_writeb, smc91c111_writew, smc91c111_writel, },
735 5a95b51d Peter Maydell
    },
736 5a95b51d Peter Maydell
    .endianness = DEVICE_NATIVE_ENDIAN,
737 80337b66 bellard
};
738 80337b66 bellard
739 4e68f7a0 Stefan Hajnoczi
static void smc91c111_cleanup(NetClientState *nc)
740 b946a153 aliguori
{
741 cc1f0f45 Jason Wang
    smc91c111_state *s = qemu_get_nic_opaque(nc);
742 b946a153 aliguori
743 42a4260f Mark McLoughlin
    s->nic = NULL;
744 b946a153 aliguori
}
745 b946a153 aliguori
746 42a4260f Mark McLoughlin
static NetClientInfo net_smc91c111_info = {
747 2be64a68 Laszlo Ersek
    .type = NET_CLIENT_OPTIONS_KIND_NIC,
748 42a4260f Mark McLoughlin
    .size = sizeof(NICState),
749 42a4260f Mark McLoughlin
    .can_receive = smc91c111_can_receive,
750 42a4260f Mark McLoughlin
    .receive = smc91c111_receive,
751 42a4260f Mark McLoughlin
    .cleanup = smc91c111_cleanup,
752 42a4260f Mark McLoughlin
};
753 42a4260f Mark McLoughlin
754 926d152e Andreas Färber
static int smc91c111_init1(SysBusDevice *sbd)
755 80337b66 bellard
{
756 926d152e Andreas Färber
    DeviceState *dev = DEVICE(sbd);
757 926d152e Andreas Färber
    smc91c111_state *s = SMC91C111(dev);
758 926d152e Andreas Färber
759 eedfac6f Paolo Bonzini
    memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s,
760 5a95b51d Peter Maydell
                          "smc91c111-mmio", 16);
761 926d152e Andreas Färber
    sysbus_init_mmio(sbd, &s->mmio);
762 926d152e Andreas Färber
    sysbus_init_irq(sbd, &s->irq);
763 50132156 Gerd Hoffmann
    qemu_macaddr_default_if_unset(&s->conf.macaddr);
764 42a4260f Mark McLoughlin
    s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
765 926d152e Andreas Färber
                          object_get_typename(OBJECT(dev)), dev->id, s);
766 b356f76d Jason Wang
    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
767 80337b66 bellard
    /* ??? Save/restore.  */
768 81a322d4 Gerd Hoffmann
    return 0;
769 80337b66 bellard
}
770 418dcf5b Paul Brook
771 999e12bb Anthony Liguori
static Property smc91c111_properties[] = {
772 999e12bb Anthony Liguori
    DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
773 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
774 999e12bb Anthony Liguori
};
775 999e12bb Anthony Liguori
776 999e12bb Anthony Liguori
static void smc91c111_class_init(ObjectClass *klass, void *data)
777 999e12bb Anthony Liguori
{
778 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
779 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
780 999e12bb Anthony Liguori
781 999e12bb Anthony Liguori
    k->init = smc91c111_init1;
782 39bffca2 Anthony Liguori
    dc->reset = smc91c111_reset;
783 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_smc91c111;
784 39bffca2 Anthony Liguori
    dc->props = smc91c111_properties;
785 999e12bb Anthony Liguori
}
786 999e12bb Anthony Liguori
787 8c43a6f0 Andreas Färber
static const TypeInfo smc91c111_info = {
788 926d152e Andreas Färber
    .name          = TYPE_SMC91C111,
789 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
790 39bffca2 Anthony Liguori
    .instance_size = sizeof(smc91c111_state),
791 39bffca2 Anthony Liguori
    .class_init    = smc91c111_class_init,
792 50132156 Gerd Hoffmann
};
793 50132156 Gerd Hoffmann
794 83f7d43a Andreas Färber
static void smc91c111_register_types(void)
795 418dcf5b Paul Brook
{
796 39bffca2 Anthony Liguori
    type_register_static(&smc91c111_info);
797 418dcf5b Paul Brook
}
798 418dcf5b Paul Brook
799 418dcf5b Paul Brook
/* Legacy helper function.  Should go away when machine config files are
800 418dcf5b Paul Brook
   implemented.  */
801 418dcf5b Paul Brook
void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
802 418dcf5b Paul Brook
{
803 418dcf5b Paul Brook
    DeviceState *dev;
804 418dcf5b Paul Brook
    SysBusDevice *s;
805 418dcf5b Paul Brook
806 418dcf5b Paul Brook
    qemu_check_nic_model(nd, "smc91c111");
807 926d152e Andreas Färber
    dev = qdev_create(NULL, TYPE_SMC91C111);
808 50132156 Gerd Hoffmann
    qdev_set_nic_properties(dev, nd);
809 e23a1b33 Markus Armbruster
    qdev_init_nofail(dev);
810 1356b98d Andreas Färber
    s = SYS_BUS_DEVICE(dev);
811 418dcf5b Paul Brook
    sysbus_mmio_map(s, 0, base);
812 418dcf5b Paul Brook
    sysbus_connect_irq(s, 0, irq);
813 418dcf5b Paul Brook
}
814 418dcf5b Paul Brook
815 83f7d43a Andreas Färber
type_init(smc91c111_register_types)