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