Statistics
| Branch: | Revision:

root / hw / smc91c111.c @ 80337b66

History | View | Annotate | Download (17.9 kB)

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
/* For crc32 */
12
#include <zlib.h>
13

    
14
/* Number of 2k memory pages available.  */
15
#define NUM_PACKETS 4
16

    
17
typedef struct {
18
    uint32_t base;
19
    VLANClientState *vc;
20
    uint16_t tcr;
21
    uint16_t rcr;
22
    uint16_t cr;
23
    uint16_t ctr;
24
    uint16_t gpr;
25
    uint16_t ptr;
26
    uint16_t ercv;
27
    void *pic;
28
    int 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
    /* Packet buffer memory.  */
39
    uint8_t data[2048][NUM_PACKETS];
40
    uint8_t int_level;
41
    uint8_t int_mask;
42
    uint8_t macaddr[6];
43
} smc91c111_state;
44

    
45
#define RCR_SOFT_RST  0x8000
46
#define RCR_STRIP_CRC 0x0200
47
#define RCR_RXEN      0x0100
48

    
49
#define TCR_EPH_LOOP  0x2000
50
#define TCR_NOCRC     0x0100
51
#define TCR_PAD_EN    0x0080
52
#define TCR_FORCOL    0x0004
53
#define TCR_LOOP      0x0002
54
#define TCR_TXEN      0x0001
55

    
56
#define INT_MD        0x80
57
#define INT_ERCV      0x40
58
#define INT_EPH       0x20
59
#define INT_RX_OVRN   0x10
60
#define INT_ALLOC     0x08
61
#define INT_TX_EMPTY  0x04
62
#define INT_TX        0x02
63
#define INT_RCV       0x01
64

    
65
#define CTR_AUTO_RELEASE  0x0800
66
#define CTR_RELOAD        0x0002
67
#define CTR_STORE         0x0001
68

    
69
#define RS_ALGNERR      0x8000
70
#define RS_BRODCAST     0x4000
71
#define RS_BADCRC       0x2000
72
#define RS_ODDFRAME     0x1000
73
#define RS_TOOLONG      0x0800
74
#define RS_TOOSHORT     0x0400
75
#define RS_MULTICAST    0x0001
76

    
77
/* Update interrupt status.  */
78
static void smc91c111_update(smc91c111_state *s)
79
{
80
    int level;
81

    
82
    if (s->tx_fifo_len == 0)
83
        s->int_level |= INT_TX_EMPTY;
84
    level = (s->int_level & s->int_mask) != 0;
85
    pic_set_irq_new(s->pic, s->irq, level);
86
}
87

    
88
/* Try to allocate a packet.  Returns 0x80 on failure.  */
89
static int smc91c111_allocate_packet(smc91c111_state *s)
90
{
91
    int i;
92
    if (s->allocated == (1 << NUM_PACKETS) - 1) {
93
        return 0x80;
94
    }
95

    
96
    for (i = 0; i < NUM_PACKETS; i++) {
97
        if ((s->allocated & (1 << i)) == 0)
98
            break;
99
    }
100
    s->allocated |= 1 << i;
101
    return i;
102
}
103

    
104

    
105
/* Process a pending TX allocate.  */
106
static void smc91c111_tx_alloc(smc91c111_state *s)
107
{
108
    s->tx_alloc = smc91c111_allocate_packet(s);
109
    if (s->tx_alloc == 0x80)
110
        return;
111
    s->int_level |= INT_ALLOC;
112
    smc91c111_update(s);
113
}
114

    
115
/* Remove and item from the RX FIFO.  */
116
static void smc91c111_pop_rx_fifo(smc91c111_state *s)
117
{
118
    int i;
119

    
120
    s->rx_fifo_len--;
121
    if (s->rx_fifo_len) {
122
        for (i = 0; i < s->rx_fifo_len; i++)
123
            s->rx_fifo[i] = s->rx_fifo[i + 1];
124
        s->int_level |= INT_RCV;
125
    } else {
126
        s->int_level &= ~INT_RCV;
127
    }
128
    smc91c111_update(s);
129
}
130

    
131
/* Release the memory allocated to a packet.  */
132
static void smc91c111_release_packet(smc91c111_state *s, int packet)
133
{
134
    s->allocated &= ~(1 << packet);
135
    if (s->tx_alloc == 0x80)
136
        smc91c111_tx_alloc(s);
137
}
138

    
139
/* Flush the TX FIFO.  */
140
static void smc91c111_do_tx(smc91c111_state *s)
141
{
142
    int i;
143
    int len;
144
    int control;
145
    int add_crc;
146
    uint32_t crc;
147
    int packetnum;
148
    uint8_t *p;
149

    
150
    if ((s->tcr & TCR_TXEN) == 0)
151
        return;
152
    if (s->tx_fifo_len == 0)
153
        return;
154
    for (i = 0; i < s->tx_fifo_len; i++) {
155
        packetnum = s->tx_fifo[i];
156
        p = &s->data[packetnum][0];
157
        /* Set status word.  */
158
        *(p++) = 0x01;
159
        *(p++) = 0x40;
160
        len = *(p++);
161
        len |= ((int)*(p++)) << 8;
162
        len -= 6;
163
        control = p[len + 1];
164
        if (control & 0x20)
165
            len++;
166
        /* ??? This overwrites the data following the buffer.
167
           Don't know what real hardware does.  */
168
        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
169
            memset(p + len, 0, 64 - len);
170
            len = 64;
171
        }
172
#if 0
173
        /* The card is supposed to append the CRC to the frame.  However
174
           none of the other network traffic has the CRC appended.
175
           Suspect this is low level ethernet detail we don't need to worry
176
           about.  */
177
        add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
178
        if (add_crc) {
179
            crc = crc32(~0, p, len);
180
            memcpy(p + len, &crc, 4);
181
            len += 4;
182
        }
183
#else
184
        add_crc = 0;
185
#endif
186
        if (s->ctr & CTR_AUTO_RELEASE)
187
            smc91c111_release_packet(s, packetnum);
188
        qemu_send_packet(s->vc, p, len);
189
    }
190
    s->tx_fifo_len = 0;
191
    if ((s->ctr & CTR_AUTO_RELEASE) == 0)
192
        s->int_level |= INT_TX;
193
    smc91c111_update(s);
194
}
195

    
196
/* Add a packet to the TX FIFO.  */
197
static void smc91c111_queue_tx(smc91c111_state *s, int packet)
198
{
199
    if (s->tx_fifo_len == NUM_PACKETS)
200
        return;
201
    s->tx_fifo[s->tx_fifo_len++] = packet;
202
    smc91c111_do_tx(s);
203
}
204

    
205
static void smc91c111_reset(smc91c111_state *s)
206
{
207
    s->bank = 0;
208
    s->tx_fifo_len = 0;
209
    s->rx_fifo_len = 0;
210
    s->allocated = 0;
211
    s->packet_num = 0;
212
    s->tx_alloc = 0;
213
    s->tcr = 0;
214
    s->rcr = 0;
215
    s->cr = 0xa0b1;
216
    s->ctr = 0x1210;
217
    s->ptr = 0;
218
    s->ercv = 0x1f;
219
    s->int_level = INT_TX_EMPTY;
220
    s->int_mask = 0;
221
    smc91c111_update(s);
222
}
223

    
224
#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
225
#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
226

    
227
static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
228
                             uint32_t value)
229
{
230
    smc91c111_state *s = (smc91c111_state *)opaque;
231

    
232
    offset -= s->base;
233
    if (offset == 14) {
234
        s->bank = value;
235
        return;
236
    }
237
    if (offset == 15)
238
        return;
239
    switch (s->bank) {
240
    case 0:
241
        switch (offset) {
242
        case 0: /* TCR */
243
            SET_LOW(tcr, value);
244
            return;
245
        case 1:
246
            SET_HIGH(tcr, value);
247
            return;
248
        case 4: /* RCR */
249
            SET_LOW(rcr, value);
250
            return;
251
        case 5:
252
            SET_HIGH(rcr, value);
253
            if (s->rcr & RCR_SOFT_RST)
254
                smc91c111_reset(s);
255
            return;
256
        case 10: case 11: /* RPCR */
257
            /* Ignored */
258
            return;
259
        }
260
        break;
261

    
262
    case 1:
263
        switch (offset) {
264
        case 0: /* CONFIG */
265
            SET_LOW(cr, value);
266
            return;
267
        case 1:
268
            SET_HIGH(cr,value);
269
            return;
270
        case 2: case 3: /* BASE */
271
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
272
            /* Not implemented.  */
273
            return;
274
        case 10: /* Genral Purpose */
275
            SET_LOW(gpr, value);
276
            return;
277
        case 11:
278
            SET_HIGH(gpr, value);
279
            return;
280
        case 12: /* Control */
281
            if (value & 1)
282
                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
283
            if (value & 2)
284
                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
285
            value &= ~3;
286
            SET_LOW(ctr, value);
287
            return;
288
        case 13:
289
            SET_HIGH(ctr, value);
290
            return;
291
        }
292
        break;
293

    
294
    case 2:
295
        switch (offset) {
296
        case 0: /* MMU Command */
297
            switch (value >> 5) {
298
            case 0: /* no-op */
299
                break;
300
            case 1: /* Allocate for TX.  */
301
                s->tx_alloc = 0x80;
302
                s->int_level &= ~INT_ALLOC;
303
                smc91c111_update(s);
304
                smc91c111_tx_alloc(s);
305
                break;
306
            case 2: /* Reset MMU.  */
307
                s->allocated = 0;
308
                s->tx_fifo_len = 0;
309
                s->rx_fifo_len = 0;
310
                s->tx_alloc = 0;
311
                break;
312
            case 3: /* Remove from RX FIFO.  */
313
                smc91c111_pop_rx_fifo(s);
314
                break;
315
            case 4: /* Remove from RX FIFO and release.  */
316
                if (s->rx_fifo_len > 0) {
317
                    smc91c111_release_packet(s, s->rx_fifo[0]);
318
                }
319
                smc91c111_pop_rx_fifo(s);
320
                break;
321
            case 5: /* Release.  */
322
                smc91c111_release_packet(s, s->packet_num);
323
                break;
324
            case 6: /* Add to TX FIFO.  */
325
                smc91c111_queue_tx(s, s->packet_num);
326
                break;
327
            case 7: /* Reset TX FIFO.  */
328
                s->tx_fifo_len = 0;
329
                break;
330
            }
331
            return;
332
        case 1:
333
            /* Ignore.  */
334
            return;
335
        case 2: /* Packet Number Register */
336
            s->packet_num = value;
337
            return;
338
        case 3: case 4: case 5:
339
            /* Should be readonly, but linux writes to them anyway. Ignore.  */
340
            return;
341
        case 6: /* Pointer */
342
            SET_LOW(ptr, value);
343
            return;
344
        case 7:
345
            SET_HIGH(ptr, value);
346
            return;
347
        case 8: case 9: case 10: case 11: /* Data */
348
            {
349
                int p;
350
                int n;
351

    
352
                if (s->ptr & 0x8000)
353
                    n = s->rx_fifo[0];
354
                else
355
                    n = s->packet_num;
356
                p = s->ptr & 0x07ff;
357
                if (s->ptr & 0x4000) {
358
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
359
                } else {
360
                    p += (offset & 3);
361
                }
362
                s->data[n][p] = value;
363
            }
364
            return;
365
        case 12: /* Interrupt ACK.  */
366
            s->int_level &= ~(value & 0xd6);
367
            smc91c111_update(s);
368
            return;
369
        case 13: /* Interrupt mask.  */
370
            s->int_mask = value;
371
            smc91c111_update(s);
372
            return;
373
        }
374
        break;;
375

    
376
    case 3:
377
        switch (offset) {
378
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
379
            /* Multicast table.  */
380
            /* Not implemented.  */
381
            return;
382
        case 8: case 9: /* Management Interface.  */
383
            /* Not implemented.  */
384
            return;
385
        case 12: /* Early receive.  */
386
            s->ercv = value & 0x1f;
387
        case 13:
388
            /* Ignore.  */
389
            return;
390
        }
391
        break;
392
    }
393
    cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n",
394
               s->bank, offset);
395
}
396

    
397
static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
398
{
399
    smc91c111_state *s = (smc91c111_state *)opaque;
400

    
401
    offset -= s->base;
402
    if (offset == 14) {
403
        return s->bank;
404
    }
405
    if (offset == 15)
406
        return 0x33;
407
    switch (s->bank) {
408
    case 0:
409
        switch (offset) {
410
        case 0: /* TCR */
411
            return s->tcr & 0xff;
412
        case 1:
413
            return s->tcr >> 8;
414
        case 2: /* EPH Status */
415
            return 0;
416
        case 3:
417
            return 0x40;
418
        case 4: /* RCR */
419
            return s->rcr & 0xff;
420
        case 5:
421
            return s->rcr >> 8;
422
        case 6: /* Counter */
423
        case 7:
424
            /* Not implemented.  */
425
            return 0;
426
        case 8: /* Free memory available.  */
427
            {
428
                int i;
429
                int n;
430
                n = 0;
431
                for (i = 0; i < NUM_PACKETS; i++) {
432
                    if (s->allocated & (1 << i))
433
                        n++;
434
                }
435
                return n;
436
            }
437
        case 9: /* Memory size.  */
438
            return NUM_PACKETS;
439
        case 10: case 11: /* RPCR */
440
            /* Not implemented.  */
441
            return 0;
442
        }
443
        break;
444

    
445
    case 1:
446
        switch (offset) {
447
        case 0: /* CONFIG */
448
            return s->cr & 0xff;
449
        case 1:
450
            return s->cr >> 8;
451
        case 2: case 3: /* BASE */
452
            /* Not implemented.  */
453
            return 0;
454
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
455
            return s->macaddr[offset - 4];
456
        case 10: /* General Purpose */
457
            return s->gpr & 0xff;
458
        case 11:
459
            return s->gpr >> 8;
460
        case 12: /* Control */
461
            return s->ctr & 0xff;
462
        case 13:
463
            return s->ctr >> 8;
464
        }
465
        break;
466

    
467
    case 2:
468
        switch (offset) {
469
        case 0: case 1: /* MMUCR Busy bit.  */
470
            return 0;
471
        case 2: /* Packet Number.  */
472
            return s->packet_num;
473
        case 3: /* Allocation Result.  */
474
            return s->tx_alloc;
475
        case 4: /* TX FIFO */
476
            if (s->tx_fifo_len == 0)
477
                return 0x80;
478
            else
479
                return s->tx_fifo[0];
480
        case 5: /* RX FIFO */
481
            if (s->rx_fifo_len == 0)
482
                return 0x80;
483
            else
484
                return s->rx_fifo[0];
485
        case 6: /* Pointer */
486
            return s->ptr & 0xff;
487
        case 7:
488
            return (s->ptr >> 8) & 0xf7;
489
        case 8: case 9: case 10: case 11: /* Data */
490
            {
491
                int p;
492
                int n;
493

    
494
                if (s->ptr & 0x8000)
495
                    n = s->rx_fifo[0];
496
                else
497
                    n = s->packet_num;
498
                p = s->ptr & 0x07ff;
499
                if (s->ptr & 0x4000) {
500
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
501
                } else {
502
                    p += (offset & 3);
503
                }
504
                return s->data[n][p];
505
            }
506
        case 12: /* Interrupt status.  */
507
            return s->int_level;
508
        case 13: /* Interrupt mask.  */
509
            return s->int_mask;
510
        }
511
        break;
512

    
513
    case 3:
514
        switch (offset) {
515
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
516
            /* Multicast table.  */
517
            /* Not implemented.  */
518
            return 0;
519
        case 8: /* Management Interface.  */
520
            /* Not implemented.  */
521
            return 0x30;
522
        case 9:
523
            return 0x33;
524
        case 10: /* Revision.  */
525
            return 0x91;
526
        case 11:
527
            return 0x33;
528
        case 12:
529
            return s->ercv;
530
        case 13:
531
            return 0;
532
        }
533
        break;
534
    }
535
    cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n",
536
               s->bank, offset);
537
    return 0;
538
}
539

    
540
static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
541
                             uint32_t value)
542
{
543
    smc91c111_writeb(opaque, offset, value & 0xff);
544
    smc91c111_writeb(opaque, offset + 1, value >> 8);
545
}
546

    
547
static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
548
                             uint32_t value)
549
{
550
    smc91c111_state *s = (smc91c111_state *)opaque;
551
    /* 32-bit writes to offset 0xc only actually write to the bank select
552
       register (offset 0xe)  */
553
    if (offset != s->base + 0xc)
554
        smc91c111_writew(opaque, offset, value & 0xffff);
555
    smc91c111_writew(opaque, offset + 2, value >> 16);
556
}
557

    
558
static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
559
{
560
    uint32_t val;
561
    val = smc91c111_readb(opaque, offset);
562
    val |= smc91c111_readb(opaque, offset + 1) << 8;
563
    return val;
564
}
565

    
566
static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
567
{
568
    uint32_t val;
569
    val = smc91c111_readw(opaque, offset);
570
    val |= smc91c111_readw(opaque, offset + 2) << 16;
571
    return val;
572
}
573

    
574
static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
575
{
576
    smc91c111_state *s = (smc91c111_state *)opaque;
577
    int status;
578
    int packetsize;
579
    uint32_t crc;
580
    int packetnum;
581
    uint8_t *p;
582

    
583
    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
584
        return;
585
    /* Short packets are padded with zeros.  Recieveing a packet
586
       < 64 bytes long is considered an error condition.  */
587
    if (size < 64)
588
        packetsize = 64;
589
    else
590
        packetsize = (size & ~1);
591
    packetsize += 6;
592
    crc = (s->rcr & RCR_STRIP_CRC) == 0;
593
    if (crc)
594
        packetsize += 4;
595
    /* TODO: Flag overrun and receive errors.  */
596
    if (packetsize > 2048)
597
        return;
598
    packetnum = smc91c111_allocate_packet(s);
599
    if (packetnum == 0x80)
600
        return;
601
    s->rx_fifo[s->rx_fifo_len++] = packetnum;
602

    
603
    p = &s->data[packetnum][0];
604
    /* ??? Multicast packets?  */
605
    status = 0;
606
    if (size > 1518)
607
        status |= RS_TOOLONG;
608
    if (size & 1)
609
        status |= RS_ODDFRAME;
610
    *(p++) = status & 0xff;
611
    *(p++) = status >> 8;
612
    *(p++) = packetsize & 0xff;
613
    *(p++) = packetsize >> 8;
614
    memcpy(p, buf, size & ~1);
615
    p += (size & ~1);
616
    /* Pad short packets.  */
617
    if (size < 64) {
618
        int pad;
619
        
620
        if (size & 1)
621
            *(p++) = buf[size - 1];
622
        pad = 64 - size;
623
        memset(p, 0, pad);
624
        p += pad;
625
        size = 64;
626
    }
627
    /* It's not clear if the CRC should go before or after the last byte in
628
       odd sized packets.  Linux disables the CRC, so that's no help.
629
       The pictures in the documentation show the CRC aligned on a 16-bit
630
       boundary before the last odd byte, so that's what we do.  */
631
    if (crc) {
632
        crc = crc32(~0, buf, size);
633
        *(p++) = crc & 0xff; crc >>= 8;
634
        *(p++) = crc & 0xff; crc >>= 8;
635
        *(p++) = crc & 0xff; crc >>= 8;
636
        *(p++) = crc & 0xff; crc >>= 8;
637
    }
638
    if (size & 1) {
639
        *(p++) = buf[size - 1];
640
        *(p++) = 0x60;
641
    } else {
642
        *(p++) = 0;
643
        *(p++) = 0x40;
644
    }
645
    /* TODO: Raise early RX interrupt?  */
646
    s->int_level |= INT_RCV;
647
    smc91c111_update(s);
648
}
649

    
650
static CPUReadMemoryFunc *smc91c111_readfn[] = {
651
    smc91c111_readb,
652
    smc91c111_readw,
653
    smc91c111_readl
654
};
655

    
656
static CPUWriteMemoryFunc *smc91c111_writefn[] = {
657
    smc91c111_writeb,
658
    smc91c111_writew,
659
    smc91c111_writel
660
};
661

    
662
void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
663
{
664
    smc91c111_state *s;
665
    int iomemtype;
666

    
667
    s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
668
    iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
669
                                       smc91c111_writefn, s);
670
    cpu_register_physical_memory(base, 16, iomemtype);
671
    s->base = base;
672
    s->pic = pic;
673
    s->irq = irq;
674
    memcpy(s->macaddr, nd->macaddr, 6);
675

    
676
    smc91c111_reset(s);
677

    
678
    s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, s);
679
    /* ??? Save/restore.  */
680
}