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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [powerpc/] [ppcn_60x/] [network/] [amd79c970.c] - Blame information for rev 846

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*
2
 *  COPYRIGHT (c) 1998 by Radstone Technology
3
 *
4
 *
5
 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
6
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
7
 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
8
 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
9
 *
10
 * You are hereby granted permission to use, copy, modify, and distribute
11
 * this file, provided that this notice, plus the above copyright notice
12
 * and disclaimer, appears in all copies. Radstone Technology will provide
13
 * no support for this code.
14
 *
15
 */
16
/*
17
 * RTEMS/KA9Q driver for PC-NET
18
 */
19
#include <bsp.h>
20
#include <rtems/error.h>
21
#include <ka9q/rtems_ka9q.h>
22
#include <ka9q/global.h>
23
#include <ka9q/enet.h>
24
#include <ka9q/iface.h>
25
#include <ka9q/netuser.h>
26
#include <ka9q/trace.h>
27
#include <ka9q/commands.h>
28
 
29
#include <pci.h>
30
#include "amd79c970.h"
31
 
32
/*
33
 * Number of PC-NETs supported by this driver
34
 */
35
#define NPCNETDRIVER    1
36
 
37
/*
38
 * Default number of buffer descriptors set aside for this driver.
39
 * The number of transmit buffer descriptors has to be quite large
40
 * since a single frame often uses four or more buffer descriptors.
41
 *
42
 * Set the number of Tx and Rx buffers, using Log_2(# buffers).
43
 */
44
#define LANCE_LOG2_TX_BUFFERS 4
45
#define LANCE_LOG2_RX_BUFFERS 4
46
#define TX_RING_SIZE                    (1 << (LANCE_LOG2_TX_BUFFERS))
47
#define TX_RING_MOD_MASK                (TX_RING_SIZE - 1)
48
#define TX_RING_LEN_BITS                ((LANCE_LOG2_TX_BUFFERS) << 4)
49
#define RX_RING_SIZE                    (1 << (LANCE_LOG2_RX_BUFFERS))
50
#define RX_RING_MOD_MASK                (RX_RING_SIZE - 1)
51
#define RX_RING_LEN_BITS                ((LANCE_LOG2_RX_BUFFERS) << 4)
52
 
53
/*
54
 * RTEMS event used by interrupt handler to signal daemons.
55
 * This must *not* be the same event used by the KA9Q task synchronization.
56
 */
57
#define INTERRUPT_EVENT RTEMS_EVENT_1
58
 
59
/*
60
 * Receive buffer size -- Allow for a full ethernet packet plus a pointer
61
 */
62
#define ETHPKT_SIZE     1520
63
#define RBUF_SIZE       (ETHPKT_SIZE + sizeof (struct iface *))
64
 
65
/*
66
 * LANCE Register Access Macros
67
 */
68
#define PCNET_IO_RD32(dp, reg, value)   \
69
        inport_32(&dp->pPCNet->u.dwio.##reg, value)
70
#define PCNET_IO_WR32(dp, reg, value)   \
71
        outport_32(&dp->pPCNet->u.dwio.##reg, value)
72
 
73
/*
74
 * LANCE Register Access Macros
75
 */
76
#define RD_CSR32(dp, index, value) \
77
        PCNET_IO_WR32(dp, rap, index); \
78
        PCNET_IO_RD32(dp, rdp, value)
79
 
80
#define WR_CSR32(dp, index, value) \
81
        PCNET_IO_WR32(dp, rap, index); \
82
        PCNET_IO_WR32(dp, rdp, value)
83
 
84
#define RD_BCR32(dp, index, value) \
85
        PCNET_IO_WR32(dp, rap, index); \
86
        PCNET_IO_RD32(dp, bdp, value)
87
 
88
#define WR_BCR32(dp, index, value) \
89
        PCNET_IO_WR32(dp, rap, index); \
90
        PCNET_IO_WR32(dp, bdp, value)
91
 
92
/*
93
 * Hardware-specific storage
94
 *
95
 * Note that the enetInitBlk field must be aligned to a 16 byte
96
 * boundary
97
 */
98
typedef struct amd79c970Context {
99
        rmde_t          rxBdBase[RX_RING_SIZE];
100
        tmde_t          txBdBase[TX_RING_SIZE];
101
        initblk_t               initBlk;
102
        pc_net_t                *pPCNet;
103
        unsigned32              ulIntVector;
104
        struct mbuf             **rxMbuf;
105
        struct mbuf             **txMbuf;
106
        int                     rxBdCount;
107
        int                     txBdCount;
108
        int                     txBdHead;
109
        int                     txBdTail;
110
        int                     txBdActiveCount;
111
        struct iface            *iface;
112
        rtems_id                txWaitTid;
113
 
114
        /*
115
         * Statistics
116
         */
117
        unsigned long   rxInterrupts;
118
        unsigned long   rxNotFirst;
119
        unsigned long   rxNotLast;
120
        unsigned long   rxGiant;
121
        unsigned long   rxNonOctet;
122
        unsigned long   rxRunt;
123
        unsigned long   rxBadCRC;
124
        unsigned long   rxOverrun;
125
        unsigned long   rxCollision;
126
        unsigned long   rxDiscarded;
127
 
128
        unsigned long   txInterrupts;
129
        unsigned long   txDeferred;
130
        unsigned long   txHeartbeat;
131
        unsigned long   txLateCollision;
132
        unsigned long   txRetryLimit;
133
        unsigned long   txUnderrun;
134
        unsigned long   txLostCarrier;
135
        unsigned long   txRawWait;
136
} amd79c970Context_t;
137
static amd79c970Context_t *pAmd79c970Context[NPCNETDRIVER];
138
 
139
/*
140
 * PC-NET interrupt handler
141
 */
142
static rtems_isr
143
amd79c970_isr (rtems_vector_number v)
144
{
145
        unsigned32 ulCSR0, ulCSR4, ulCSR5;
146
        amd79c970Context_t *dp;
147
        int i;
148
 
149
        for(i=0; i<NPCNETDRIVER; i++)
150
        {
151
                dp=pAmd79c970Context[i];
152
                if(dp->ulIntVector==v)
153
                {
154
                        RD_CSR32(dp, CSR0, ulCSR0);
155
                        if(ulCSR0 & CSR0_RINT)
156
                        {
157
                                /*
158
                                 * We have recieve data
159
                                 */
160
                                dp->rxInterrupts++;
161
                                rtems_event_send(
162
                                        dp->iface->rxproc,
163
                                        INTERRUPT_EVENT);
164
                        }
165
 
166
                        if(ulCSR0 & CSR0_TINT)
167
                        {
168
                                /*
169
                                 * Data tranmitted or error
170
                                 */
171
                                dp->txInterrupts++;
172
                                if(dp->txWaitTid)
173
                                {
174
                                        rtems_event_send(
175
                                                dp->txWaitTid,
176
                                                INTERRUPT_EVENT);
177
                                }
178
                        }
179
 
180
                        if((ulCSR0 & CSR0_INTR) &&
181
                           !(ulCSR0 & (CSR0_RINT | CSR0_TINT)))
182
                        {
183
                                /*
184
                                 * Many possible sources
185
                                 */
186
                                RD_CSR32(dp, CSR4, ulCSR4);
187
                                RD_CSR32(dp, CSR5, ulCSR5);
188
                                DEBUG_puts("CSR0=");
189
                                DEBUG_puth(ulCSR0);
190
                                DEBUG_puts(", CSR4=");
191
                                DEBUG_puth(ulCSR4);
192
                                DEBUG_puts(", CSR5=");
193
                                DEBUG_puth(ulCSR5);
194
                                DEBUG_puts("\n\r");
195
                                /*
196
                                 * Clear it
197
                                 */
198
                                WR_CSR32(dp, CSR4, ulCSR4);
199
                                WR_CSR32(dp, CSR5, ulCSR5);
200
                        }
201
 
202
                        /*
203
                         * Clear interrupts
204
                         */
205
                        ulCSR0&=CSR0_BABL | CSR0_CERR | CSR0_MISS |
206
                                CSR0_MERR | CSR0_RINT | CSR0_TINT | CSR0_IENA;
207
                        WR_CSR32(dp, CSR0, ulCSR0);
208
 
209
                        RD_CSR32(dp, CSR0, ulCSR0);
210
                }
211
        }
212
}
213
 
214
/*
215
 * Initialize the ethernet hardware
216
 */
217
static boolean
218
amd79c970_initialize_hardware (int instance, int broadcastFlag)
219
{
220
        amd79c970Context_t *dp;
221
        struct mbuf     *bp;
222
        int             i;
223
        unsigned8       ucPCIBusCount;
224
        unsigned8       ucBusNumber;
225
        unsigned8       ucSlotNumber;
226
        unsigned32      ulDeviceID;
227
        unsigned32      ulBAR0;
228
        unsigned8       ucIntVector;
229
        unsigned32      ulInitClkPCIAddr;
230
        unsigned32      ulAPROM;
231
        unsigned32      ulCSR0;
232
 
233
        ucPCIBusCount=BusCountPCI();
234
 
235
        /*
236
         * Scan the available busses for instance of hardware
237
         */
238
        i=0;
239
 
240
        dp=pAmd79c970Context[instance];
241
        dp->pPCNet=(pc_net_t *)NULL;
242
 
243
        for(ucBusNumber=0;
244
            (ucBusNumber<ucPCIBusCount) && (dp->pPCNet==(pc_net_t *)NULL);
245
            ucBusNumber++)
246
        {
247
                for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++)
248
                {
249
                        PCIConfigRead32(ucBusNumber,
250
                                        ucSlotNumber,
251
                                        0,
252
                                        PCI_CONFIG_VENDOR_LOW,
253
                                        &ulDeviceID);
254
                        if(ulDeviceID!=PCI_ID(0x1022, 0x2000))
255
                        {
256
                                continue;
257
                        }
258
 
259
                        /*
260
                         * We've found a PC-NET controller
261
                         */
262
                        if(i++<instance)
263
                        {
264
                                continue;
265
                        }
266
 
267
                        /*
268
                         * Read base address
269
                         */
270
                        PCIConfigRead32(ucBusNumber,
271
                                        ucSlotNumber,
272
                                        0,
273
                                        PCI_CONFIG_BAR_0,
274
                                        &ulBAR0);
275
                        dp->pPCNet=(pc_net_t *)(ulBAR0&~PCI_ADDRESS_IO_SPACE);
276
 
277
                        /*
278
                         * Read interrupt vector
279
                         */
280
                        PCIConfigRead8(ucBusNumber,
281
                                       ucSlotNumber,
282
                                       0,
283
                                       PCI_CONFIG_INTERRUPTLINE,
284
                                       &ucIntVector);
285
                        dp->ulIntVector=PPCN_60X_IRQ_PCI(ucIntVector);
286
 
287
                        /*
288
                         * Ensure that device is enabled
289
                         */
290
                        PCIConfigWrite16(ucBusNumber,
291
                                         ucSlotNumber,
292
                                         0,
293
                                         PCI_CONFIG_COMMAND,
294
                                         PCI_ENABLE_IO_SPACE |
295
                                         PCI_ENABLE_BUS_MASTER);
296
                        break;
297
                }
298
        }
299
 
300
        if(dp->pPCNet==(pc_net_t *)NULL)
301
        {
302
                return(FALSE);
303
        }
304
 
305
        /*
306
         * Read the ethernet number
307
         */
308
        if(!dp->iface->hwaddr)
309
        {
310
                dp->iface->hwaddr=mallocw (EADDR_LEN);
311
                PCNET_IO_RD32(dp, aprom[0], ulAPROM);
312
                for(i=0;i<4;i++)
313
                {
314
                        dp->iface->hwaddr[i]=(ulAPROM>>(i*8))&0xff;
315
                }
316
                PCNET_IO_RD32(dp, aprom[1], ulAPROM);
317
                for(i=0;i<2;i++)
318
                {
319
                        dp->iface->hwaddr[i+4]=(ulAPROM>>(i*8))&0xff;
320
                }
321
        }
322
 
323
        /*
324
         * Allocate mbuf pointers
325
         */
326
        dp->rxMbuf=mallocw (dp->rxBdCount * sizeof(*dp->rxMbuf));
327
        dp->txMbuf=mallocw (dp->txBdCount * sizeof(*dp->txMbuf));
328
 
329
        /*
330
         * Allocate space for incoming packets
331
         */
332
        for(i=0; i<dp->rxBdCount; i++)
333
        {
334
                dp->rxMbuf[i]=bp=ambufw (RBUF_SIZE);
335
                bp->data += sizeof (struct iface *);
336
                dp->rxBdBase[i].rmde_addr=
337
                        Swap32((unsigned32)bp->data+PCI_SYS_MEM_BASE);
338
                dp->rxBdBase[i].rmde_bcnt=
339
                        Swap16(-(bp->size-sizeof (struct iface *)));
340
                dp->rxBdBase[i].rmde_flags=Swap16(RFLG_OWN);
341
        }
342
 
343
        /*
344
         * Set up transmit buffer descriptors
345
         */
346
        for(i=0; i<dp->txBdCount; i++)
347
        {
348
                dp->txBdBase[i].tmde_status=Swap16(TST_STP | TST_ENP);
349
                dp->txBdBase[i].tmde_error=0;
350
                dp->txMbuf[i]=NULL;
351
        }
352
 
353
        /*
354
         * Initialise initblk
355
         */
356
        if(broadcastFlag)
357
        {
358
                dp->initBlk.ib_mode=0;
359
        }
360
        else
361
        {
362
                dp->initBlk.ib_mode=Swap16(CSR15_DRCVBC);
363
        }
364
 
365
        /*
366
         * Set the receive descriptor ring length
367
         */
368
        dp->initBlk.ib_rlen=RX_RING_LEN_BITS;
369
        /*
370
         * Set the receive descriptor ring address
371
         */
372
        dp->initBlk.ib_rdra=Swap32((unsigned32)&dp->rxBdBase[0]+
373
                                     PCI_SYS_MEM_BASE);
374
 
375
        /*
376
         * Set the transmit descriptor ring length
377
         */
378
        dp->initBlk.ib_tlen=TX_RING_LEN_BITS;
379
        /*
380
         * Set the tranmit descriptor ring address
381
         */
382
        dp->initBlk.ib_tdra=Swap32((unsigned32)&dp->txBdBase[0]+
383
                                     PCI_SYS_MEM_BASE);
384
 
385
        for(i=0;i<6;i++)
386
        {
387
                dp->initBlk.ib_padr[i]=dp->iface->hwaddr[i];
388
        }
389
 
390
        /*
391
         * Ensure that we are in DWIO mode
392
         */
393
        PCNET_IO_WR32(dp, rdp, 0);
394
 
395
        WR_CSR32(dp, 58,CSR58_PCISTYLE);
396
 
397
        WR_CSR32(dp, CSR3,
398
                 CSR3_BABLM | CSR3_MERRM | CSR3_IDONM | CSR3_DXSUFLO);
399
 
400
        WR_CSR32(dp, CSR4,
401
                 CSR4_APADXMIT | CSR4_MFCOM | CSR4_RCVCCOM |
402
                 CSR4_TXSTRTM | CSR4_JABM);
403
 
404
        WR_CSR32(dp, CSR5, 0);
405
 
406
        ulInitClkPCIAddr=(unsigned32)&dp->initBlk+PCI_SYS_MEM_BASE;
407
        /*
408
         * CSR2 must contain the high order 16 bits of the first word in
409
         * the initialization block
410
         */
411
        WR_CSR32(dp, CSR2, (ulInitClkPCIAddr >> 16) & 0xffff);
412
        /*
413
         * CSR1 must contain the low order 16 bits of the first word in
414
         * the initialization block
415
         */
416
        WR_CSR32(dp, CSR1, (ulInitClkPCIAddr & 0xffff));
417
 
418
        /*
419
         * Set up interrupts
420
         */
421
        set_vector(amd79c970_isr,
422
                   dp->ulIntVector,
423
                   instance);
424
 
425
        /*
426
         * Start the device
427
         */
428
        WR_CSR32(dp, CSR0, CSR0_INIT | CSR0_STRT);
429
 
430
        /*
431
         * Wait for 100mS for the device to initialise
432
         */
433
        for(i=0; i<100; i++)
434
        {
435
                RD_CSR32(dp, CSR0, ulCSR0);
436
                if(ulCSR0 & CSR0_IDON)
437
                {
438
                        break;
439
                }
440
                rtems_ka9q_ppause(1); /* 1mS */
441
        }
442
        if(i >= 100)
443
        {
444
                return(FALSE);
445
        }
446
 
447
        /*
448
         * Enable interrupts
449
         */
450
        WR_CSR32(dp, CSR0, CSR0_IENA);
451
 
452
        dp->txBdHead=dp->txBdTail=0;
453
        dp->txBdActiveCount=0;
454
 
455
        return(TRUE);
456
}
457
 
458
/*
459
 * Soak up buffer descriptors that have been sent
460
 */
461
static void
462
amd79c970_retire_tx_bd (amd79c970Context_t *dp)
463
{
464
        unsigned16 status;
465
        unsigned32 error;
466
        int i;
467
        int nRetired;
468
 
469
        i = dp->txBdTail;
470
        nRetired = 0;
471
        while((dp->txBdActiveCount != 0) &&
472
              (((status=Swap16(dp->txBdBase[i].tmde_status)) & TST_OWN)==0))
473
        {
474
                /*
475
                 * See if anything went wrong
476
                 */
477
                if(status & TST_ERR)
478
                {
479
                        /*
480
                         * Check for errors
481
                         */
482
                        error=Swap16(dp->txBdBase[i].tmde_error);
483
 
484
                        if (error & TERR_LCOL)
485
                                dp->txLateCollision++;
486
                        if (error & TERR_RTRY)
487
                                dp->txRetryLimit++;
488
                        if (error & TERR_UFLO)
489
                                dp->txUnderrun++;
490
                        if (error & TERR_EXDEF)
491
                                dp->txDeferred++;
492
                        if (error & TERR_LCAR)
493
                                dp->txLostCarrier++;
494
                }
495
                nRetired++;
496
                if (status & TST_ENP)
497
                {
498
                        /*
499
                         * A full frame has been transmitted.
500
                         * Free all the associated buffer descriptors.
501
                         */
502
                        dp->txBdActiveCount -= nRetired;
503
                        while (nRetired) {
504
                                nRetired--;
505
                                free_mbuf (&dp->txMbuf[dp->txBdTail]);
506
                                if (++dp->txBdTail == dp->txBdCount)
507
                                        dp->txBdTail = 0;
508
                        }
509
                }
510
                if (++i == dp->txBdCount)
511
                {
512
                        i = 0;
513
                }
514
        }
515
}
516
 
517
/*
518
 * Send raw packet (caller provides header).
519
 * This code runs in the context of the interface transmit
520
 * task or in the context of the network task.
521
 */
522
static int
523
amd79c970_raw (struct iface *iface, struct mbuf **bpp)
524
{
525
        amd79c970Context_t *dp;
526
        struct mbuf *bp;
527
        tmde_t *firstTxBd, *txBd;
528
        unsigned16 status;
529
        int nAdded;
530
 
531
        dp = pAmd79c970Context[iface->dev];
532
 
533
        /*
534
         * Fill in some logging data
535
         */
536
        iface->rawsndcnt++;
537
        iface->lastsent = secclock ();
538
        dump (iface, IF_TRACE_OUT, *bpp);
539
 
540
        /*
541
         * It would not do to have two tasks active in the transmit
542
         * loop at the same time.
543
         * The blocking is simple-minded since the odds of two tasks
544
         * simultaneously attempting to use this code are low.  The only
545
         * way that two tasks can try to run here is:
546
         *      1) Task A enters this code and ends up having to
547
         *         wait for a transmit buffer descriptor.
548
         *      2) Task B  gains control and tries to transmit a packet.
549
         * The RTEMS/KA9Q scheduling semaphore ensures that there
550
         * are no race conditions associated with manipulating the
551
         * txWaitTid variable.
552
         */
553
        if (dp->txWaitTid) {
554
                dp->txRawWait++;
555
                while (dp->txWaitTid)
556
                        rtems_ka9q_ppause (10);
557
        }
558
 
559
        /*
560
         * Free up buffer descriptors
561
         */
562
        amd79c970_retire_tx_bd (dp);
563
 
564
        /*
565
         * Set up the transmit buffer descriptors.
566
         * No need to pad out short packets since the
567
         * hardware takes care of that automatically.
568
         * No need to copy the packet to a contiguous buffer
569
         * since the hardware is capable of scatter/gather DMA.
570
         */
571
        bp = *bpp;
572
        nAdded = 0;
573
        txBd = firstTxBd = dp->txBdBase + dp->txBdHead;
574
        for (;;) {
575
                /*
576
                 * Wait for buffer descriptor to become available.
577
                 */
578
                if ((dp->txBdActiveCount + nAdded) == dp->txBdCount) {
579
                        /*
580
                         * Find out who we are
581
                         */
582
                        if (dp->txWaitTid == 0)
583
                                rtems_task_ident (0, 0, &dp->txWaitTid);
584
 
585
                        /*
586
                         * Wait for buffer descriptor to become available.
587
                         * Note that the buffer descriptors are checked
588
                         * *before* * entering the wait loop -- this catches
589
                         * the possibility that a buffer descriptor became
590
                         * available between the `if' above, and the clearing
591
                         * of the event register.
592
                         * Also, the event receive doesn't wait forever.
593
                         * This is to catch the case where the transmitter
594
                         * stops in the middle of a frame -- and only the
595
                         * last buffer descriptor in a frame can generate
596
                         * an interrupt.
597
                         */
598
                        amd79c970_retire_tx_bd (dp);
599
                        while ((dp->txBdActiveCount + nAdded) == dp->txBdCount) {
600
                                rtems_ka9q_event_receive (INTERRUPT_EVENT,
601
                                        RTEMS_WAIT|RTEMS_EVENT_ANY,
602
                                        1 + 1000000/BSP_Configuration.microseconds_per_tick);
603
                                amd79c970_retire_tx_bd (dp);
604
                        }
605
                }
606
 
607
                /*
608
                 * Fill in the buffer descriptor
609
                 */
610
                txBd->tmde_addr=Swap32((unsigned32)bp->data+PCI_SYS_MEM_BASE);
611
                txBd->tmde_bcnt=Swap16(-bp->cnt);
612
                dp->txMbuf[dp->txBdHead] = bp;
613
 
614
                nAdded++;
615
                if (++dp->txBdHead == dp->txBdCount)
616
                {
617
                        dp->txBdHead = 0;
618
                }
619
 
620
                /*
621
                 * Set the transmit buffer status.
622
                 * Break out of the loop if this mbuf is the last in the frame.
623
                 */
624
                if ((bp = bp->next) == NULL) {
625
                        if(txBd==firstTxBd)
626
                        {
627
                                /*
628
                                 * There is only one frame
629
                                 */
630
                                txBd->tmde_status=Swap16(TST_OWN |
631
                                                         TST_STP |
632
                                                         TST_ENP);
633
                        }
634
                        else
635
                        {
636
                                /*
637
                                 * Mark the last buffer
638
                                 */
639
                                txBd->tmde_status=Swap16(TST_OWN |
640
                                                         TST_ENP);
641
                                /*
642
                                 * Trigger the first transmit
643
                                 */
644
                                firstTxBd->tmde_status=Swap16(TST_OWN |
645
                                                              TST_STP);
646
                        }
647
                        /*
648
                         * Sync instruction required to overcome the Grackle
649
                         * stale data bug
650
                         */
651
                        asm volatile("sync");
652
                        dp->txBdActiveCount += nAdded;
653
                        break;
654
                }
655
                else if(txBd!=firstTxBd)
656
                {
657
                        txBd->tmde_status = Swap16(TST_OWN);
658
                }
659
                txBd = dp->txBdBase + dp->txBdHead;
660
        }
661
 
662
        /*
663
         * Show that we've finished with the packet
664
         */
665
        dp->txWaitTid = 0;
666
        *bpp = NULL;
667
        return 0;
668
}
669
 
670
/*
671
 * PC-NET reader task
672
 */
673
static void
674
amd79c970_rx (int dev, void *p1, void *p2)
675
{
676
        struct iface *iface=(struct iface *)p1;
677
        amd79c970Context_t *dp=(amd79c970Context_t *)p2;
678
        struct mbuf *bp;
679
        rtems_unsigned16 status;
680
        rmde_t *rxBd;
681
        int rxBdIndex;
682
        int continuousCount;
683
 
684
        /*
685
         * Input packet handling loop
686
         */
687
        continuousCount=0;
688
        rxBdIndex=0;
689
 
690
        while(TRUE)
691
        {
692
                rxBd=&dp->rxBdBase[rxBdIndex];
693
 
694
                /*
695
                 * Wait for packet if there's not one ready
696
                 */
697
                if((status=Swap16(rxBd->rmde_flags)) & RFLG_OWN)
698
                {
699
                        /*
700
                         * Reset `continuous-packet' count
701
                         */
702
                        continuousCount=0;
703
 
704
                        /*
705
                         * Wait for packet
706
                         * Note that the buffer descriptor is checked
707
                         * *before* the event wait -- this catches the
708
                         * possibility that a packet arrived between the
709
                         * `if' above, and the clearing of the event register.
710
                         */
711
                        while ((status=Swap16(rxBd->rmde_flags)) & RFLG_OWN)
712
                        {
713
                                rtems_ka9q_event_receive (INTERRUPT_EVENT,
714
                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
715
                                                RTEMS_NO_TIMEOUT);
716
                        }
717
                }
718
 
719
                /*
720
                 * Check that packet is valid
721
                 */
722
                if((status & RFLG_ERR) ||
723
                   ((status & (RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP)))
724
                {
725
                        /*
726
                         * Something went wrong with the reception
727
                         */
728
                        if(!(status & RFLG_ENP))
729
                                dp->rxNotLast++;
730
                        if(!(status & RFLG_STP))
731
                                dp->rxNotFirst++;
732
                        if(status & RFLG_OFLO)
733
                                dp->rxGiant++;
734
                        if(status & RFLG_FRAM)
735
                                dp->rxNonOctet++;
736
                        if(status & RFLG_CRC)
737
                                dp->rxBadCRC++;
738
                        if(status & RFLG_BUFF)
739
                                dp->rxOverrun++;
740
                }
741
                else
742
                {
743
                        /*
744
                         * Pass the packet up the chain
745
                         * The mbuf count is reduced to remove
746
                         * the frame check sequence at the end
747
                         * of the packet.
748
                         */
749
                        bp=dp->rxMbuf[rxBdIndex];
750
                        bp->cnt=Swap16(rxBd->rmde_mcnt) - sizeof (uint32);
751
                        net_route (iface, &bp);
752
 
753
                        /*
754
                         * Give the network code a chance to digest the
755
                         * packet.  This guards against a flurry of
756
                         * incoming packets (usually an ARP storm) from
757
                         * using up all the available memory.
758
                         */
759
                        if(++continuousCount >= dp->rxBdCount)
760
                                kwait_null ();
761
 
762
                        /*
763
                         * Allocate a new mbuf
764
                         * FIXME: It seems to me that it would be better
765
                         * if there were some way to limit number of mbufs
766
                         * in use by this interface, but I don't see any
767
                         * way of determining when the mbuf we pass up
768
                         * is freed.
769
                         */
770
                        dp->rxMbuf[rxBdIndex]=bp=ambufw (RBUF_SIZE);
771
                        bp->data += sizeof (struct iface *);
772
                        rxBd->rmde_addr=Swap32(
773
                                (unsigned32)bp->data+PCI_SYS_MEM_BASE);
774
                        rxBd->rmde_bcnt=Swap16(
775
                                -(bp->size-sizeof (struct iface *)));
776
                }
777
 
778
                /*
779
                 * Reenable the buffer descriptor
780
                 */
781
                rxBd->rmde_flags=Swap16(RFLG_OWN);
782
 
783
                /*
784
                 * Move to next buffer descriptor
785
                 */
786
                if(++rxBdIndex==dp->rxBdCount)
787
                        rxBdIndex=0;
788
        }
789
}
790
 
791
/*
792
 * Shut down the interface
793
 * FIXME: This is a pretty simple-minded routine.  It doesn't worry
794
 * about cleaning up mbufs, shutting down daemons, etc.
795
 */
796
static int
797
amd79c970_stop (struct iface *iface)
798
{
799
        amd79c970Context_t *dp;
800
        unsigned32      ulCSR0;
801
        int             i;
802
 
803
        dp=pAmd79c970Context[iface->dev];
804
 
805
        /*
806
         * Stop the device
807
         */
808
        WR_CSR32(dp, CSR0, CSR0_STOP);
809
 
810
        /*
811
         * Wait for 100mS for the device to stop
812
         */
813
        for(i=0; i<100; i++)
814
        {
815
                RD_CSR32(dp, CSR0, ulCSR0);
816
                if(!(ulCSR0 & (CSR0_RXON | CSR0_TXON)))
817
                {
818
                        break;
819
                }
820
                rtems_ka9q_ppause(1); /* 1mS */
821
        }
822
        if(i >= 100)
823
        {
824
                return(-1);
825
        }
826
 
827
        /*
828
         * Free up all the mbufs we've allocated
829
         */
830
        for(i=0; i<dp->rxBdCount; i++)
831
        {
832
                free_mbuf(&dp->rxMbuf[i]);
833
        }
834
 
835
        return 0;
836
}
837
 
838
/*
839
 * Show interface statistics
840
 */
841
static void
842
amd79c970_show (struct iface *iface)
843
{
844
        int i;
845
 
846
        i=iface->dev;
847
 
848
        printf ("      Rx Interrupts:%-8lu", pAmd79c970Context[i]->rxInterrupts);
849
        printf ("       Not First:%-8lu", pAmd79c970Context[i]->rxNotFirst);
850
        printf ("        Not Last:%-8lu\n", pAmd79c970Context[i]->rxNotLast);
851
        printf ("              Giant:%-8lu", pAmd79c970Context[i]->rxGiant);
852
        printf ("            Runt:%-8lu", pAmd79c970Context[i]->rxRunt);
853
        printf ("       Non-octet:%-8lu\n", pAmd79c970Context[i]->rxNonOctet);
854
        printf ("            Bad CRC:%-8lu", pAmd79c970Context[i]->rxBadCRC);
855
        printf ("         Overrun:%-8lu", pAmd79c970Context[i]->rxOverrun);
856
        printf ("       Collision:%-8lu\n", pAmd79c970Context[i]->rxCollision);
857
        printf ("          Discarded:%-8lu\n", pAmd79c970Context[i]->rxDiscarded);
858
 
859
        printf ("      Tx Interrupts:%-8lu", pAmd79c970Context[i]->txInterrupts);
860
        printf ("        Deferred:%-8lu", pAmd79c970Context[i]->txDeferred);
861
        printf (" Missed Hearbeat:%-8lu\n", pAmd79c970Context[i]->txHeartbeat);
862
        printf ("         No Carrier:%-8lu", pAmd79c970Context[i]->txLostCarrier);
863
        printf ("Retransmit Limit:%-8lu", pAmd79c970Context[i]->txRetryLimit);
864
        printf ("  Late Collision:%-8lu\n", pAmd79c970Context[i]->txLateCollision);
865
        printf ("           Underrun:%-8lu", pAmd79c970Context[i]->txUnderrun);
866
        printf (" Raw output wait:%-8lu\n", pAmd79c970Context[i]->txRawWait);
867
}
868
 
869
/*
870
 * Attach an PC-NET driver to the system
871
 * This is the only `extern' function in the driver.
872
 *
873
 * argv[0]: interface label, e.g., "amd79c970"
874
 * argv[1]: maximum transmission unit, bytes, e.g., "1500"
875
 * argv[2]: accept ("broadcast") or ignore ("nobroadcast") broadcast packets
876
 * Following arguments are optional, but if present, must appear in
877
 * the following order:
878
 * Following arguments are optional, but if Ethernet address is
879
 * specified, Internet address must also be specified.
880
 * ###.###.###.###   -- IP address
881
 * ##:##:##:##:##:## -- Ethernet address
882
 */
883
int
884
rtems_ka9q_driver_attach (int argc, char *argv[], void *p)
885
{
886
        struct iface *iface;
887
        struct amd79c970Context *dp;
888
        char *cp;
889
        int i;
890
        int argIndex;
891
        int broadcastFlag;
892
 
893
        /*
894
         * Find a free driver
895
         */
896
        for(i=0; i<NPCNETDRIVER; i++)
897
        {
898
                if(pAmd79c970Context[i]==NULL)
899
                        break;
900
        }
901
        if(i==NPCNETDRIVER)
902
        {
903
                printf ("Too many PC-NET drivers.\n");
904
                return -1;
905
        }
906
        if(if_lookup (argv[0]) != NULL)
907
        {
908
                printf ("Interface %s already exists\n", argv[0]);
909
                return -1;
910
        }
911
 
912
        /*
913
         * Note that this structure must be aligned to a 16 byte boundary
914
         */
915
        pAmd79c970Context[i]=(amd79c970Context_t *)
916
                (((unsigned32)callocw(1,
917
                                      sizeof(amd79c970Context_t)+16)+16) & ~15);
918
        dp=pAmd79c970Context[i];
919
 
920
        /*
921
         * Create an interface descriptor
922
         */
923
        iface=callocw (1, sizeof *iface);
924
        iface->name=strdup (argv[0]);
925
        iface->mtu=atoi (argv[1]);
926
 
927
        /*
928
         * Select broadcast packet handling
929
         */
930
        cp=argv[2];
931
        if(strnicmp (cp, "broadcast", strlen (cp))==0)
932
        {
933
                broadcastFlag=1;
934
        }
935
        else if(strnicmp (cp, "nobroadcast", strlen (cp))==0)
936
        {
937
                broadcastFlag=0;
938
        }
939
        else {
940
                printf ("Argument `%s' is neither `broadcast' nor `nobroadcast'.\n", cp);
941
                return -1;
942
        }
943
        argIndex=3;
944
 
945
        /*
946
         * Set receive buffer descriptor count
947
         */
948
        dp->rxBdCount=RX_RING_SIZE;
949
 
950
        /*
951
         * Set transmit buffer descriptor count
952
         */
953
        dp->txWaitTid=0;
954
        dp->txBdCount=TX_RING_SIZE;
955
 
956
        /*
957
         * Set Internet address
958
         */
959
        if(argIndex<argc)
960
                iface->addr=resolve (argv[argIndex++]);
961
        else
962
                iface->addr=Ip_addr;
963
 
964
        /*
965
         * Set Ethernet address
966
         */
967
        if(argIndex<argc)
968
        {
969
                iface->hwaddr=mallocw (EADDR_LEN);
970
                gether (iface->hwaddr, argv[argIndex++]);
971
        }
972
 
973
        iface->dev=i;
974
        iface->raw=amd79c970_raw;
975
        iface->stop=amd79c970_stop;
976
        iface->show=amd79c970_show;
977
        dp->iface=iface;
978
        setencap (iface, "Ethernet");
979
 
980
        /*
981
         * Set up PC-NET hardware
982
         */
983
        if(!amd79c970_initialize_hardware (i, broadcastFlag))
984
        {
985
                printf ("Unable to initialize hardware for %s\n", argv[0]);
986
                return -1;
987
        }
988
 
989
        /*
990
         * Chain onto list of interfaces
991
         */
992
        iface->next=Ifaces;
993
        Ifaces=iface;
994
 
995
        /*
996
         * Start I/O daemons
997
         */
998
        cp=if_name (iface, " tx");
999
        iface->txproc=newproc (cp, 1024, if_tx, iface->dev, iface, NULL, 0);
1000
        free (cp);
1001
        cp=if_name (iface, " rx");
1002
        iface->rxproc=newproc (cp, 1024, amd79c970_rx, iface->dev, iface, dp, 0);
1003
        free (cp);
1004
        return 0;
1005
}
1006
 
1007
/*
1008
 * FIXME: There should be an ioctl routine to allow things like
1009
 * enabling/disabling reception of broadcast packets.
1010
 */

powered by: WebSVN 2.1.0

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