OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [drivers/] [net/] [am79c961a.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * linux/drivers/net/am79c961.c
3
 */
4
 
5
#include <linux/module.h>
6
#include <linux/kernel.h>
7
#include <linux/sched.h>
8
#include <linux/types.h>
9
#include <linux/fcntl.h>
10
#include <linux/interrupt.h>
11
#include <linux/ptrace.h>
12
#include <linux/ioport.h>
13
#include <linux/in.h>
14
#include <linux/malloc.h>
15
#include <linux/string.h>
16
#include <linux/errno.h>
17
#include <linux/netdevice.h>
18
#include <linux/etherdevice.h>
19
#include <linux/skbuff.h>
20
 
21
#include <asm/system.h>
22
#include <asm/bitops.h>
23
#include <asm/io.h>
24
#include <asm/dma.h>
25
#include <asm/ecard.h>
26
#include <asm/delay.h>
27
 
28
#define TX_BUFFERS 15
29
#define RX_BUFFERS 25
30
 
31
#include "am79c961a.h"
32
 
33
static unsigned int net_debug = NET_DEBUG;
34
 
35
static void
36
am79c961_setmulticastlist (struct device *dev);
37
 
38
static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n";
39
 
40
#define FUNC_PROLOGUE \
41
        struct dev_priv *priv = (struct dev_priv *)dev->priv
42
 
43
/* --------------------------------------------------------------------------- */
44
 
45
static void
46
write_rreg (unsigned long base, unsigned int reg, unsigned short val)
47
{
48
    __asm__("
49
        strh    %1, [%2]        @ NET_RAP
50
        strh    %0, [%2, #-4]   @ NET_RDP
51
        " : : "r" (val), "r" (reg), "r" (0xf0000464));
52
}
53
 
54
static inline void
55
write_ireg (unsigned long base, unsigned int reg, unsigned short val)
56
{
57
    __asm__("
58
        strh    %1, [%2]        @ NET_RAP
59
        strh    %0, [%2, #8]    @ NET_RDP
60
        " : : "r" (val), "r" (reg), "r" (0xf0000464));
61
}
62
 
63
#define am_writeword(dev,off,val)\
64
    __asm__("\
65
        strh    %0, [%1]\
66
        " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
67
 
68
static inline void
69
am_writebuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
70
{
71
        offset = 0xe0000000 + (offset << 1);
72
        length = (length + 1) & ~1;
73
        if ((int)buf & 2) {
74
                __asm__ __volatile__("
75
                        strh    %2, [%0], #4
76
                " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
77
                buf += 2;
78
                length -= 2;
79
        }
80
        while (length > 8) {
81
                unsigned int tmp, tmp2;
82
                __asm__ __volatile__("
83
                        ldmia   %1!, {%2, %3}
84
                        strh    %2, [%0], #4
85
                        mov     %2, %2, lsr #16
86
                        strh    %2, [%0], #4
87
                        strh    %3, [%0], #4
88
                        mov     %3, %3, lsr #16
89
                        strh    %3, [%0], #4
90
                " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
91
                  : "0" (offset), "1" (buf));
92
                length -= 8;
93
        }
94
        while (length > 0) {
95
                __asm__ __volatile__("
96
                        strh    %2, [%0], #4
97
                " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
98
                buf += 2;
99
                length -= 2;
100
        }
101
}
102
 
103
static inline unsigned short
104
read_rreg (unsigned int base_addr, unsigned int reg)
105
{
106
    unsigned short v;
107
    __asm__("
108
        strh    %1, [%2]        @ NET_RAP
109
        ldrh    %0, [%2, #-4]   @ NET_IDP
110
        " : "=r" (v): "r" (reg), "r" (0xf0000464));
111
    return v;
112
}
113
 
114
static inline unsigned short
115
am_readword (struct device *dev, unsigned long off)
116
{
117
    unsigned long address = 0xe0000000 + (off << 1);
118
    unsigned short val;
119
 
120
    __asm__("
121
        ldrh    %0, [%1]
122
        " : "=r" (val): "r" (address));
123
    return val;
124
}
125
 
126
static inline void
127
am_readbuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
128
{
129
        offset = 0xe0000000 + (offset << 1);
130
        length = (length + 1) & ~1;
131
        if ((int)buf & 2) {
132
                unsigned int tmp;
133
                __asm__ __volatile__("
134
                        ldrh    %2, [%0], #4
135
                        strb    %2, [%1], #1
136
                        mov     %2, %2, lsr #8
137
                        strb    %2, [%1], #1
138
                " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
139
                length -= 2;
140
        }
141
        while (length > 8) {
142
                unsigned int tmp, tmp2, tmp3;
143
                __asm__ __volatile__("
144
                        ldrh    %2, [%0], #4
145
                        ldrh    %3, [%0], #4
146
                        orr     %2, %2, %3, lsl #16
147
                        ldrh    %3, [%0], #4
148
                        ldrh    %4, [%0], #4
149
                        orr     %3, %3, %4, lsl #16
150
                        stmia   %1!, {%2, %3}
151
                " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
152
                  : "0" (offset), "1" (buf));
153
                length -= 8;
154
        }
155
        while (length > 0) {
156
                unsigned int tmp;
157
                __asm__ __volatile__("
158
                        ldrh    %2, [%0], #4
159
                        strb    %2, [%1], #1
160
                        mov     %2, %2, lsr #8
161
                        strb    %2, [%1], #1
162
                " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
163
                length -= 2;
164
        }
165
}
166
 
167
static int
168
am79c961_ramtest(struct device *dev, unsigned int val)
169
{
170
        unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
171
        int i, error = 0, errorcount = 0;
172
 
173
        if (!buffer)
174
                return 0;
175
        memset (buffer, val, 65536);
176
        am_writebuffer(dev, 0, buffer, 65536);
177
        memset (buffer, val ^ 255, 65536);
178
        am_readbuffer(dev, 0, buffer, 65536);
179
        for (i = 0; i < 65536; i++) {
180
                if (buffer[i] != val && !error) {
181
                        printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
182
                        error = 1;
183
                        errorcount ++;
184
                } else if (error && buffer[i] == val) {
185
                        printk ("%05X\n", i);
186
                        error = 0;
187
                }
188
        }
189
        if (error)
190
                printk ("10000\n");
191
        kfree (buffer);
192
        return errorcount;
193
}
194
 
195
static void
196
am79c961_init_for_open(struct device *dev)
197
{
198
    FUNC_PROLOGUE;
199
    unsigned long hdr_addr, first_free_addr;
200
    unsigned long flags;
201
    unsigned char *p;
202
    int i;
203
 
204
    save_flags_cli (flags);
205
 
206
    write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
207
    write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
208
 
209
    restore_flags (flags);
210
 
211
    first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
212
    hdr_addr = 0;
213
 
214
    priv->rxhead = 0;
215
    priv->rxtail = 0;
216
    priv->rxhdr = hdr_addr;
217
 
218
    for (i = 0; i < RX_BUFFERS; i++) {
219
        priv->rxbuffer[i] = first_free_addr;
220
        am_writeword (dev, hdr_addr, first_free_addr);
221
        am_writeword (dev, hdr_addr + 2, RMD_OWN);
222
        am_writeword (dev, hdr_addr + 4, (-1600));
223
        am_writeword (dev, hdr_addr + 6, 0);
224
        first_free_addr += 1600;
225
        hdr_addr += 8;
226
    }
227
    priv->txhead = 0;
228
    priv->txtail = 0;
229
    priv->txhdr = hdr_addr;
230
    for (i = 0; i < TX_BUFFERS; i++) {
231
        priv->txbuffer[i] = first_free_addr;
232
        am_writeword (dev, hdr_addr, first_free_addr);
233
        am_writeword (dev, hdr_addr + 2, 0);
234
        am_writeword (dev, hdr_addr + 4, 0);
235
        am_writeword (dev, hdr_addr + 6, 0);
236
        first_free_addr += 1600;
237
        hdr_addr += 8;
238
    }
239
 
240
    for (i = LADRL; i <= LADRH; i++)
241
        write_rreg (dev->base_addr, i, 0);
242
 
243
    for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
244
        write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
245
 
246
    i = MODE_PORT0;
247
    if (dev->flags & IFF_PROMISC)
248
        i |= MODE_PROMISC;
249
 
250
    write_rreg (dev->base_addr, MODE, i);
251
    write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
252
    write_rreg (dev->base_addr, BASERXH, 0);
253
    write_rreg (dev->base_addr, BASETXL, priv->txhdr);
254
    write_rreg (dev->base_addr, BASERXH, 0);
255
    write_rreg (dev->base_addr, POLLINT, 0);
256
    write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
257
    write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
258
    write_rreg (dev->base_addr, CSR0, CSR0_STOP);
259
    write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM);
260
    write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
261
}
262
 
263
static int
264
am79c961_init(struct device *dev)
265
{
266
    unsigned long flags;
267
 
268
    am79c961_ramtest(dev, 0x66);
269
    am79c961_ramtest(dev, 0x99);
270
 
271
    save_flags_cli (flags);
272
 
273
    write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
274
    write_rreg (dev->base_addr, CSR0, CSR0_STOP);
275
    write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
276
 
277
    restore_flags (flags);
278
 
279
    return 0;
280
}
281
 
282
/*
283
 * This is the real probe routine.
284
 */
285
static int
286
am79c961_probe1(struct device *dev)
287
{
288
    static unsigned version_printed = 0;
289
    struct dev_priv *priv;
290
    int i;
291
 
292
    if (!dev->priv) {
293
        dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL);
294
        if (!dev->priv)
295
            return -ENOMEM;
296
    }
297
 
298
    priv = (struct dev_priv *) dev->priv;
299
    memset (priv, 0, sizeof(struct dev_priv));
300
 
301
    /*
302
     * The PNP initialisation should have been done by the ether bootp loader.
303
     */
304
    inb ((dev->base_addr + NET_RESET) >> 1);    /* reset the device */
305
 
306
    udelay (5);
307
 
308
    if (inb (dev->base_addr >> 1) != 0x08 ||
309
        inb ((dev->base_addr >> 1) + 1) != 00 ||
310
        inb ((dev->base_addr >> 1) + 2) != 0x2b) {
311
        kfree (dev->priv);
312
        dev->priv = NULL;
313
        return -ENODEV;
314
    }
315
 
316
    /*
317
     * Ok, we've found a valid hw ID
318
     */
319
 
320
    if (net_debug  &&  version_printed++ == 0)
321
        printk (KERN_INFO "%s", version);
322
 
323
    printk(KERN_INFO "%s: am79c961 found [%04lx, %d] ", dev->name, dev->base_addr, dev->irq);
324
    request_region (dev->base_addr, 0x18, "am79c961");
325
 
326
    /* Retrive and print the ethernet address. */
327
    for (i = 0; i < 6; i++) {
328
        dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff;
329
        printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
330
    }
331
 
332
    if (am79c961_init(dev)) {
333
        kfree (dev->priv);
334
        dev->priv = NULL;
335
        return -ENODEV;
336
    }
337
 
338
    dev->open = am79c961_open;
339
    dev->stop = am79c961_close;
340
    dev->hard_start_xmit = am79c961_sendpacket;
341
    dev->get_stats = am79c961_getstats;
342
    dev->set_multicast_list = am79c961_setmulticastlist;
343
 
344
    /* Fill in the fields of the device structure with ethernet values. */
345
    ether_setup(dev);
346
    return 0;
347
}
348
 
349
int
350
am79c961_probe(struct device *dev)
351
{
352
    static int initialised = 0;
353
 
354
    if (initialised)
355
        return -ENODEV;
356
    initialised = 1;
357
 
358
    dev->base_addr = 0x220;
359
    dev->irq = 3;
360
 
361
    return am79c961_probe1(dev);
362
}
363
 
364
/*
365
 * Open/initialize the board.  This is called (in the current kernel)
366
 * sometime after booting when the 'ifconfig' program is run.
367
 *
368
 * This routine should set everything up anew at each open, even
369
 * registers that "should" only need to be set once at boot, so that
370
 * there is non-reboot way to recover if something goes wrong.
371
 */
372
static int
373
am79c961_open(struct device *dev)
374
{
375
    FUNC_PROLOGUE;
376
 
377
    MOD_INC_USE_COUNT;
378
 
379
    memset (&priv->stats, 0, sizeof (priv->stats));
380
 
381
    if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev))
382
        return -EAGAIN;
383
 
384
    am79c961_init_for_open(dev);
385
 
386
    dev->tbusy = 0;
387
    dev->interrupt = 0;
388
    dev->start = 1;
389
    return 0;
390
}
391
 
392
/*
393
 * The inverse routine to am79c961_open().
394
 */
395
static int
396
am79c961_close(struct device *dev)
397
{
398
    dev->tbusy = 1;
399
    dev->start = 0;
400
 
401
    am79c961_init(dev);
402
 
403
    free_irq (dev->irq, dev);
404
 
405
    MOD_DEC_USE_COUNT;
406
    return 0;
407
}
408
 
409
/*
410
 * Get the current statistics.  This may be called with the card open or
411
 * closed.
412
 */
413
static struct enet_statistics *am79c961_getstats (struct device *dev)
414
{
415
    FUNC_PROLOGUE;
416
    return &priv->stats;
417
}
418
 
419
/*
420
 * Set or clear promiscuous/multicast mode filter for this adaptor.
421
 *
422
 * We don't attempt any packet filtering.  The card may have a SEEQ 8004
423
 * in which does not have the other ethernet address registers present...
424
 */
425
static void am79c961_setmulticastlist (struct device *dev)
426
{
427
    unsigned long flags;
428
    int i;
429
 
430
    dev->flags &= ~IFF_ALLMULTI;
431
 
432
    i = MODE_PORT0;
433
    if (dev->flags & IFF_PROMISC)
434
        i |= MODE_PROMISC;
435
 
436
    save_flags_cli (flags);
437
    write_rreg (dev->base_addr, MODE, i);
438
    restore_flags (flags);
439
}
440
 
441
/*
442
 * Transmit a packet
443
 */
444
static int
445
am79c961_sendpacket(struct sk_buff *skb, struct device *dev)
446
{
447
        FUNC_PROLOGUE;
448
 
449
        if (!dev->tbusy) {
450
again:
451
                if (skb) {
452
                        if (!set_bit(0, (void*)&dev->tbusy)) {
453
                                unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
454
                                unsigned int hdraddr, bufaddr;
455
                                unsigned long flags;
456
 
457
                                hdraddr = priv->txhdr + (priv->txhead << 3);
458
                                bufaddr = priv->txbuffer[priv->txhead];
459
                                priv->txhead ++;
460
                                if (priv->txhead >= TX_BUFFERS)
461
                                        priv->txhead = 0;
462
 
463
                                am_writebuffer (dev, bufaddr, skb->data, length);
464
                                am_writeword (dev, hdraddr + 4, -length);
465
                                am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
466
 
467
                                save_flags_cli (flags);
468
                                write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
469
                                dev->trans_start = jiffies;
470
                                restore_flags (flags);
471
 
472
                                if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
473
                                        dev->tbusy = 0;
474
                                dev_kfree_skb (skb, FREE_WRITE);
475
                                return 0;
476
                        } else
477
                                printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
478
                                return 1;
479
                } else {
480
                        dev_tint(dev);
481
                        return 0;
482
                }
483
        } else {
484
                int tickssofar = jiffies - dev->trans_start;
485
                if (tickssofar < 5)
486
                        return 1;
487
                printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name);
488
                /* Try to restart the adaptor. */
489
                dev->tbusy = 0;
490
                dev->trans_start = jiffies;
491
                goto again;
492
        }
493
}
494
 
495
static void
496
am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
497
{
498
    struct device *dev = (struct device *)dev_id;
499
    struct dev_priv *priv = (struct dev_priv *)dev->priv;
500
    unsigned int status;
501
 
502
#if NET_DEBUG > 1
503
    if(net_debug & DEBUG_INT)
504
        printk(KERN_DEBUG "am79c961irq: %d ", irq);
505
#endif
506
 
507
    dev->interrupt = 1;
508
 
509
    status = read_rreg (dev->base_addr, CSR0);
510
    write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
511
 
512
    if (status & CSR0_RINT) /* Got a packet(s). */
513
        am79c961_rx (dev, priv);
514
    if (status & CSR0_TINT) /* Packets transmitted */
515
        am79c961_tx (dev, priv);
516
    if (status & CSR0_MISS)
517
        priv->stats.rx_dropped ++;
518
 
519
    dev->interrupt = 0;
520
 
521
#if NET_DEBUG > 1
522
    if(net_debug & DEBUG_INT)
523
        printk("done\n");
524
#endif
525
}
526
 
527
/*
528
 * If we have a good packet(s), get it/them out of the buffers.
529
 */
530
static void
531
am79c961_rx(struct device *dev, struct dev_priv *priv)
532
{
533
        unsigned long hdraddr;
534
        unsigned long pktaddr;
535
 
536
        do {
537
                unsigned long status;
538
                struct sk_buff *skb;
539
                int len;
540
 
541
                hdraddr = priv->rxhdr + (priv->rxtail << 3);
542
                pktaddr = priv->rxbuffer[priv->rxtail];
543
 
544
                status = am_readword (dev, hdraddr + 2);
545
                if (status & RMD_OWN) /* do we own it? */
546
                        break;
547
 
548
                priv->rxtail ++;
549
                if (priv->rxtail >= RX_BUFFERS)
550
                        priv->rxtail = 0;
551
 
552
                if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
553
                        am_writeword (dev, hdraddr + 2, RMD_OWN);
554
                        priv->stats.rx_errors ++;
555
                        if (status & RMD_ERR) {
556
                                if (status & RMD_FRAM)
557
                                        priv->stats.rx_frame_errors ++;
558
                                if (status & RMD_CRC)
559
                                        priv->stats.rx_crc_errors ++;
560
                        } else if (status & RMD_STP)
561
                                priv->stats.rx_length_errors ++;
562
                        continue;
563
                }
564
 
565
                len = am_readword (dev, hdraddr + 6);
566
                skb = dev_alloc_skb (len + 2);
567
 
568
                if (skb) {
569
                        unsigned char *buf;
570
 
571
                        skb->dev = dev;
572
                        skb_reserve (skb, 2);
573
                        buf = skb_put (skb, len);
574
 
575
                        am_readbuffer (dev, pktaddr, buf, len);
576
                        am_writeword (dev, hdraddr + 2, RMD_OWN);
577
                        skb->protocol = eth_type_trans(skb, dev);
578
                        netif_rx (skb);
579
                        priv->stats.rx_packets ++;
580
                } else {
581
                        am_writeword (dev, hdraddr + 2, RMD_OWN);
582
                        printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
583
                        priv->stats.rx_dropped ++;
584
                        break;
585
                }
586
        } while (1);
587
}
588
 
589
/*
590
 * Update stats for the transmitted packet
591
 */
592
static void
593
am79c961_tx(struct device *dev, struct dev_priv *priv)
594
{
595
        do {
596
                unsigned long hdraddr;
597
                unsigned long status;
598
 
599
                hdraddr = priv->txhdr + (priv->txtail << 3);
600
                status = am_readword (dev, hdraddr + 2);
601
                if (status & TMD_OWN)
602
                        break;
603
 
604
                priv->txtail ++;
605
                if (priv->txtail >= TX_BUFFERS)
606
                        priv->txtail = 0;
607
 
608
                if (status & TMD_ERR) {
609
                        unsigned long status2;
610
 
611
                        priv->stats.tx_errors ++;
612
 
613
                        status2 = am_readword (dev, hdraddr + 6);
614
                        am_writeword (dev, hdraddr + 6, 0);
615
 
616
                        if (status2 & TST_RTRY)
617
                                priv->stats.collisions += 1;
618
                        if (status2 & TST_LCOL)
619
                                priv->stats.tx_window_errors ++;
620
                        if (status2 & TST_LCAR)
621
                                priv->stats.tx_carrier_errors ++;
622
                        if (status2 & TST_UFLO)
623
                                priv->stats.tx_fifo_errors ++;
624
                        continue;
625
                }
626
                priv->stats.tx_packets ++;
627
        } while (priv->txtail != priv->txhead);
628
 
629
        dev->tbusy = 0;
630
        mark_bh (NET_BH);
631
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.