smc91c111.c revision 55f4e4a5ec657a017e3bf75299ad71fd1c968dd3
1/*
2 * SMSC 91C111 Ethernet interface emulation
3 *
4 * Copyright (c) 2005 CodeSourcery, LLC.
5 * Written by Paul Brook
6 *
7 * This code is licenced under the GPL
8 */
9
10#include "vl.h"
11#include "irq.h"
12/* For crc32 */
13#include <zlib.h>
14
15/* Number of 2k memory pages available.  */
16#define NUM_PACKETS 4
17
18typedef struct {
19    uint32_t base;
20    VLANClientState *vc;
21    uint16_t tcr;
22    uint16_t rcr;
23    uint16_t cr;
24    uint16_t ctr;
25    uint16_t gpr;
26    uint16_t ptr;
27    uint16_t ercv;
28    qemu_irq irq;
29    int bank;
30    int packet_num;
31    int tx_alloc;
32    /* Bitmask of allocated packets.  */
33    int allocated;
34    int tx_fifo_len;
35    int tx_fifo[NUM_PACKETS];
36    int rx_fifo_len;
37    int rx_fifo[NUM_PACKETS];
38    int tx_fifo_done_len;
39    int tx_fifo_done[NUM_PACKETS];
40    /* Packet buffer memory.  */
41    uint8_t data[NUM_PACKETS][2048];
42    uint8_t int_level;
43    uint8_t int_mask;
44    uint8_t macaddr[6];
45} smc91c111_state;
46
47#define RCR_SOFT_RST  0x8000
48#define RCR_STRIP_CRC 0x0200
49#define RCR_RXEN      0x0100
50
51#define TCR_EPH_LOOP  0x2000
52#define TCR_NOCRC     0x0100
53#define TCR_PAD_EN    0x0080
54#define TCR_FORCOL    0x0004
55#define TCR_LOOP      0x0002
56#define TCR_TXEN      0x0001
57
58#define INT_MD        0x80
59#define INT_ERCV      0x40
60#define INT_EPH       0x20
61#define INT_RX_OVRN   0x10
62#define INT_ALLOC     0x08
63#define INT_TX_EMPTY  0x04
64#define INT_TX        0x02
65#define INT_RCV       0x01
66
67#define CTR_AUTO_RELEASE  0x0800
68#define CTR_RELOAD        0x0002
69#define CTR_STORE         0x0001
70
71#define RS_ALGNERR      0x8000
72#define RS_BRODCAST     0x4000
73#define RS_BADCRC       0x2000
74#define RS_ODDFRAME     0x1000
75#define RS_TOOLONG      0x0800
76#define RS_TOOSHORT     0x0400
77#define RS_MULTICAST    0x0001
78
79/* Update interrupt status.  */
80static void smc91c111_update(smc91c111_state *s)
81{
82    int level;
83
84    if (s->tx_fifo_len == 0)
85        s->int_level |= INT_TX_EMPTY;
86    if (s->tx_fifo_done_len != 0)
87        s->int_level |= INT_TX;
88    level = (s->int_level & s->int_mask) != 0;
89    qemu_set_irq(s->irq, level);
90}
91
92/* Try to allocate a packet.  Returns 0x80 on failure.  */
93static int smc91c111_allocate_packet(smc91c111_state *s)
94{
95    int i;
96    if (s->allocated == (1 << NUM_PACKETS) - 1) {
97        return 0x80;
98    }
99
100    for (i = 0; i < NUM_PACKETS; i++) {
101        if ((s->allocated & (1 << i)) == 0)
102            break;
103    }
104    s->allocated |= 1 << i;
105    return i;
106}
107
108
109/* Process a pending TX allocate.  */
110static void smc91c111_tx_alloc(smc91c111_state *s)
111{
112    s->tx_alloc = smc91c111_allocate_packet(s);
113    if (s->tx_alloc == 0x80)
114        return;
115    s->int_level |= INT_ALLOC;
116    smc91c111_update(s);
117}
118
119/* Remove and item from the RX FIFO.  */
120static void smc91c111_pop_rx_fifo(smc91c111_state *s)
121{
122    int i;
123
124    s->rx_fifo_len--;
125    if (s->rx_fifo_len) {
126        for (i = 0; i < s->rx_fifo_len; i++)
127            s->rx_fifo[i] = s->rx_fifo[i + 1];
128        s->int_level |= INT_RCV;
129    } else {
130        s->int_level &= ~INT_RCV;
131    }
132    smc91c111_update(s);
133}
134
135/* Remove an item from the TX completion FIFO.  */
136static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
137{
138    int i;
139
140    if (s->tx_fifo_done_len == 0)
141        return;
142    s->tx_fifo_done_len--;
143    for (i = 0; i < s->tx_fifo_done_len; i++)
144        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
145}
146
147/* Release the memory allocated to a packet.  */
148static void smc91c111_release_packet(smc91c111_state *s, int packet)
149{
150    s->allocated &= ~(1 << packet);
151    if (s->tx_alloc == 0x80)
152        smc91c111_tx_alloc(s);
153}
154
155/* Flush the TX FIFO.  */
156static void smc91c111_do_tx(smc91c111_state *s)
157{
158    int i;
159    int len;
160    int control;
161    int add_crc;
162    int packetnum;
163    uint8_t *p;
164
165    if ((s->tcr & TCR_TXEN) == 0)
166        return;
167    if (s->tx_fifo_len == 0)
168        return;
169    for (i = 0; i < s->tx_fifo_len; i++) {
170        packetnum = s->tx_fifo[i];
171        p = &s->data[packetnum][0];
172        /* Set status word.  */
173        *(p++) = 0x01;
174        *(p++) = 0x40;
175        len = *(p++);
176        len |= ((int)*(p++)) << 8;
177        len -= 6;
178        control = p[len + 1];
179        if (control & 0x20)
180            len++;
181        /* ??? This overwrites the data following the buffer.
182           Don't know what real hardware does.  */
183        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
184            memset(p + len, 0, 64 - len);
185            len = 64;
186        }
187#if 0
188        /* The card is supposed to append the CRC to the frame.  However
189           none of the other network traffic has the CRC appended.
190           Suspect this is low level ethernet detail we don't need to worry
191           about.  */
192        add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
193        if (add_crc) {
194            uint32_t crc = crc32(~0, p, len);
195            memcpy(p + len, &crc, 4);
196            len += 4;
197        }
198#else
199        add_crc = 0;
200#endif
201        if (s->ctr & CTR_AUTO_RELEASE)
202            /* Race?  */
203            smc91c111_release_packet(s, packetnum);
204        else if (s->tx_fifo_done_len < NUM_PACKETS)
205            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
206        qemu_send_packet(s->vc, p, len);
207    }
208    s->tx_fifo_len = 0;
209    smc91c111_update(s);
210}
211
212/* Add a packet to the TX FIFO.  */
213static void smc91c111_queue_tx(smc91c111_state *s, int packet)
214{
215    if (s->tx_fifo_len == NUM_PACKETS)
216        return;
217    s->tx_fifo[s->tx_fifo_len++] = packet;
218    smc91c111_do_tx(s);
219}
220
221static void smc91c111_reset(smc91c111_state *s)
222{
223    s->bank = 0;
224    s->tx_fifo_len = 0;
225    s->tx_fifo_done_len = 0;
226    s->rx_fifo_len = 0;
227    s->allocated = 0;
228    s->packet_num = 0;
229    s->tx_alloc = 0;
230    s->tcr = 0;
231    s->rcr = 0;
232    s->cr = 0xa0b1;
233    s->ctr = 0x1210;
234    s->ptr = 0;
235    s->ercv = 0x1f;
236    s->int_level = INT_TX_EMPTY;
237    s->int_mask = 0;
238    smc91c111_update(s);
239}
240
241#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
242#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
243
244static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
245                             uint32_t value)
246{
247    smc91c111_state *s = (smc91c111_state *)opaque;
248
249    offset -= s->base;
250    if (offset == 14) {
251        s->bank = value;
252        return;
253    }
254    if (offset == 15)
255        return;
256    switch (s->bank) {
257    case 0:
258        switch (offset) {
259        case 0: /* TCR */
260            SET_LOW(tcr, value);
261            return;
262        case 1:
263            SET_HIGH(tcr, value);
264            return;
265        case 4: /* RCR */
266            SET_LOW(rcr, value);
267            return;
268        case 5:
269            SET_HIGH(rcr, value);
270            if (s->rcr & RCR_SOFT_RST)
271                smc91c111_reset(s);
272            return;
273        case 10: case 11: /* RPCR */
274            /* Ignored */
275            return;
276        }
277        break;
278
279    case 1:
280        switch (offset) {
281        case 0: /* CONFIG */
282            SET_LOW(cr, value);
283            return;
284        case 1:
285            SET_HIGH(cr,value);
286            return;
287        case 2: case 3: /* BASE */
288        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
289            /* Not implemented.  */
290            return;
291        case 10: /* Genral Purpose */
292            SET_LOW(gpr, value);
293            return;
294        case 11:
295            SET_HIGH(gpr, value);
296            return;
297        case 12: /* Control */
298            if (value & 1)
299                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
300            if (value & 2)
301                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
302            value &= ~3;
303            SET_LOW(ctr, value);
304            return;
305        case 13:
306            SET_HIGH(ctr, value);
307            return;
308        }
309        break;
310
311    case 2:
312        switch (offset) {
313        case 0: /* MMU Command */
314            switch (value >> 5) {
315            case 0: /* no-op */
316                break;
317            case 1: /* Allocate for TX.  */
318                s->tx_alloc = 0x80;
319                s->int_level &= ~INT_ALLOC;
320                smc91c111_update(s);
321                smc91c111_tx_alloc(s);
322                break;
323            case 2: /* Reset MMU.  */
324                s->allocated = 0;
325                s->tx_fifo_len = 0;
326                s->tx_fifo_done_len = 0;
327                s->rx_fifo_len = 0;
328                s->tx_alloc = 0;
329                break;
330            case 3: /* Remove from RX FIFO.  */
331                smc91c111_pop_rx_fifo(s);
332                break;
333            case 4: /* Remove from RX FIFO and release.  */
334                if (s->rx_fifo_len > 0) {
335                    smc91c111_release_packet(s, s->rx_fifo[0]);
336                }
337                smc91c111_pop_rx_fifo(s);
338                break;
339            case 5: /* Release.  */
340                smc91c111_release_packet(s, s->packet_num);
341                break;
342            case 6: /* Add to TX FIFO.  */
343                smc91c111_queue_tx(s, s->packet_num);
344                break;
345            case 7: /* Reset TX FIFO.  */
346                s->tx_fifo_len = 0;
347                s->tx_fifo_done_len = 0;
348                break;
349            }
350            return;
351        case 1:
352            /* Ignore.  */
353            return;
354        case 2: /* Packet Number Register */
355            s->packet_num = value;
356            return;
357        case 3: case 4: case 5:
358            /* Should be readonly, but linux writes to them anyway. Ignore.  */
359            return;
360        case 6: /* Pointer */
361            SET_LOW(ptr, value);
362            return;
363        case 7:
364            SET_HIGH(ptr, value);
365            return;
366        case 8: case 9: case 10: case 11: /* Data */
367            {
368                int p;
369                int n;
370
371                if (s->ptr & 0x8000)
372                    n = s->rx_fifo[0];
373                else
374                    n = s->packet_num;
375                p = s->ptr & 0x07ff;
376                if (s->ptr & 0x4000) {
377                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
378                } else {
379                    p += (offset & 3);
380                }
381                s->data[n][p] = value;
382            }
383            return;
384        case 12: /* Interrupt ACK.  */
385            s->int_level &= ~(value & 0xd6);
386            if (value & INT_TX)
387                smc91c111_pop_tx_fifo_done(s);
388            smc91c111_update(s);
389            return;
390        case 13: /* Interrupt mask.  */
391            s->int_mask = value;
392            smc91c111_update(s);
393            return;
394        }
395        break;;
396
397    case 3:
398        switch (offset) {
399        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
400            /* Multicast table.  */
401            /* Not implemented.  */
402            return;
403        case 8: case 9: /* Management Interface.  */
404            /* Not implemented.  */
405            return;
406        case 12: /* Early receive.  */
407            s->ercv = value & 0x1f;
408        case 13:
409            /* Ignore.  */
410            return;
411        }
412        break;
413    }
414    cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n",
415               s->bank, offset);
416}
417
418static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
419{
420    smc91c111_state *s = (smc91c111_state *)opaque;
421
422    offset -= s->base;
423    if (offset == 14) {
424        return s->bank;
425    }
426    if (offset == 15)
427        return 0x33;
428    switch (s->bank) {
429    case 0:
430        switch (offset) {
431        case 0: /* TCR */
432            return s->tcr & 0xff;
433        case 1:
434            return s->tcr >> 8;
435        case 2: /* EPH Status */
436            return 0;
437        case 3:
438            return 0x40;
439        case 4: /* RCR */
440            return s->rcr & 0xff;
441        case 5:
442            return s->rcr >> 8;
443        case 6: /* Counter */
444        case 7:
445            /* Not implemented.  */
446            return 0;
447        case 8: /* Free memory available.  */
448            {
449                int i;
450                int n;
451                n = 0;
452                for (i = 0; i < NUM_PACKETS; i++) {
453                    if (s->allocated & (1 << i))
454                        n++;
455                }
456                return n;
457            }
458        case 9: /* Memory size.  */
459            return NUM_PACKETS;
460        case 10: case 11: /* RPCR */
461            /* Not implemented.  */
462            return 0;
463        }
464        break;
465
466    case 1:
467        switch (offset) {
468        case 0: /* CONFIG */
469            return s->cr & 0xff;
470        case 1:
471            return s->cr >> 8;
472        case 2: case 3: /* BASE */
473            /* Not implemented.  */
474            return 0;
475        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
476            return s->macaddr[offset - 4];
477        case 10: /* General Purpose */
478            return s->gpr & 0xff;
479        case 11:
480            return s->gpr >> 8;
481        case 12: /* Control */
482            return s->ctr & 0xff;
483        case 13:
484            return s->ctr >> 8;
485        }
486        break;
487
488    case 2:
489        switch (offset) {
490        case 0: case 1: /* MMUCR Busy bit.  */
491            return 0;
492        case 2: /* Packet Number.  */
493            return s->packet_num;
494        case 3: /* Allocation Result.  */
495            return s->tx_alloc;
496        case 4: /* TX FIFO */
497            if (s->tx_fifo_done_len == 0)
498                return 0x80;
499            else
500                return s->tx_fifo_done[0];
501        case 5: /* RX FIFO */
502            if (s->rx_fifo_len == 0)
503                return 0x80;
504            else
505                return s->rx_fifo[0];
506        case 6: /* Pointer */
507            return s->ptr & 0xff;
508        case 7:
509            return (s->ptr >> 8) & 0xf7;
510        case 8: case 9: case 10: case 11: /* Data */
511            {
512                int p;
513                int n;
514
515                if (s->ptr & 0x8000)
516                    n = s->rx_fifo[0];
517                else
518                    n = s->packet_num;
519                p = s->ptr & 0x07ff;
520                if (s->ptr & 0x4000) {
521                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
522                } else {
523                    p += (offset & 3);
524                }
525                return s->data[n][p];
526            }
527        case 12: /* Interrupt status.  */
528            return s->int_level;
529        case 13: /* Interrupt mask.  */
530            return s->int_mask;
531        }
532        break;
533
534    case 3:
535        switch (offset) {
536        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
537            /* Multicast table.  */
538            /* Not implemented.  */
539            return 0;
540        case 8: /* Management Interface.  */
541            /* Not implemented.  */
542            return 0x30;
543        case 9:
544            return 0x33;
545        case 10: /* Revision.  */
546            return 0x91;
547        case 11:
548            return 0x33;
549        case 12:
550            return s->ercv;
551        case 13:
552            return 0;
553        }
554        break;
555    }
556    cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n",
557               s->bank, offset);
558    return 0;
559}
560
561static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
562                             uint32_t value)
563{
564    smc91c111_writeb(opaque, offset, value & 0xff);
565    smc91c111_writeb(opaque, offset + 1, value >> 8);
566}
567
568static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
569                             uint32_t value)
570{
571    smc91c111_state *s = (smc91c111_state *)opaque;
572    /* 32-bit writes to offset 0xc only actually write to the bank select
573       register (offset 0xe)  */
574    if (offset != s->base + 0xc)
575        smc91c111_writew(opaque, offset, value & 0xffff);
576    smc91c111_writew(opaque, offset + 2, value >> 16);
577}
578
579static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
580{
581    uint32_t val;
582    val = smc91c111_readb(opaque, offset);
583    val |= smc91c111_readb(opaque, offset + 1) << 8;
584    return val;
585}
586
587static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
588{
589    uint32_t val;
590    val = smc91c111_readw(opaque, offset);
591    val |= smc91c111_readw(opaque, offset + 2) << 16;
592    return val;
593}
594
595static int smc91c111_can_receive(void *opaque)
596{
597    smc91c111_state *s = (smc91c111_state *)opaque;
598
599    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
600        return 1;
601    if (s->allocated == (1 << NUM_PACKETS) - 1)
602        return 0;
603    return 1;
604}
605
606static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
607{
608    smc91c111_state *s = (smc91c111_state *)opaque;
609    int status;
610    int packetsize;
611    uint32_t crc;
612    int packetnum;
613    uint8_t *p;
614
615    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
616        return;
617    /* Short packets are padded with zeros.  Recieveing a packet
618       < 64 bytes long is considered an error condition.  */
619    if (size < 64)
620        packetsize = 64;
621    else
622        packetsize = (size & ~1);
623    packetsize += 6;
624    crc = (s->rcr & RCR_STRIP_CRC) == 0;
625    if (crc)
626        packetsize += 4;
627    /* TODO: Flag overrun and receive errors.  */
628    if (packetsize > 2048)
629        return;
630    packetnum = smc91c111_allocate_packet(s);
631    if (packetnum == 0x80)
632        return;
633    s->rx_fifo[s->rx_fifo_len++] = packetnum;
634
635    p = &s->data[packetnum][0];
636    /* ??? Multicast packets?  */
637    status = 0;
638    if (size > 1518)
639        status |= RS_TOOLONG;
640    if (size & 1)
641        status |= RS_ODDFRAME;
642    *(p++) = status & 0xff;
643    *(p++) = status >> 8;
644    *(p++) = packetsize & 0xff;
645    *(p++) = packetsize >> 8;
646    memcpy(p, buf, size & ~1);
647    p += (size & ~1);
648    /* Pad short packets.  */
649    if (size < 64) {
650        int pad;
651
652        if (size & 1)
653            *(p++) = buf[size - 1];
654        pad = 64 - size;
655        memset(p, 0, pad);
656        p += pad;
657        size = 64;
658    }
659    /* It's not clear if the CRC should go before or after the last byte in
660       odd sized packets.  Linux disables the CRC, so that's no help.
661       The pictures in the documentation show the CRC aligned on a 16-bit
662       boundary before the last odd byte, so that's what we do.  */
663    if (crc) {
664        crc = crc32(~0, buf, size);
665        *(p++) = crc & 0xff; crc >>= 8;
666        *(p++) = crc & 0xff; crc >>= 8;
667        *(p++) = crc & 0xff; crc >>= 8;
668        *(p++) = crc & 0xff; crc >>= 8;
669    }
670    if (size & 1) {
671        *(p++) = buf[size - 1];
672        *(p++) = 0x60;
673    } else {
674        *(p++) = 0;
675        *(p++) = 0x40;
676    }
677    /* TODO: Raise early RX interrupt?  */
678    s->int_level |= INT_RCV;
679    smc91c111_update(s);
680}
681
682static CPUReadMemoryFunc *smc91c111_readfn[] = {
683    smc91c111_readb,
684    smc91c111_readw,
685    smc91c111_readl
686};
687
688static CPUWriteMemoryFunc *smc91c111_writefn[] = {
689    smc91c111_writeb,
690    smc91c111_writew,
691    smc91c111_writel
692};
693
694void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
695{
696    smc91c111_state *s;
697    int iomemtype;
698
699    s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
700    iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
701                                       smc91c111_writefn, s);
702    cpu_register_physical_memory(base, 16, iomemtype);
703    s->base = base;
704    s->irq = irq;
705    memcpy(s->macaddr, nd->macaddr, 6);
706
707    smc91c111_reset(s);
708
709    s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive,
710                                 smc91c111_can_receive, s);
711    /* ??? Save/restore.  */
712}
713