source: rtems/c/src/lib/libbsp/powerpc/ppcn_60x/network/amd79c970.c @ 6128a4a

4.104.114.84.95
Last change on this file since 6128a4a was 6128a4a, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/21/04 at 10:43:04

Remove stray white spaces.

  • Property mode set to 100644
File size: 22.0 KB
Line 
1/*
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 */
98typedef 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        uint32_t                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;
137static amd79c970Context_t *pAmd79c970Context[NPCNETDRIVER];
138
139/*
140 * PC-NET interrupt handler
141 */
142static rtems_isr
143amd79c970_isr (rtems_vector_number v)
144{
145        uint32_t   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 */
217static boolean
218amd79c970_initialize_hardware (int instance, int broadcastFlag)
219{
220        amd79c970Context_t *dp;
221        struct mbuf     *bp;
222        int             i;
223        uint8_t         ucPCIBusCount;
224        uint8_t         ucBusNumber;
225        uint8_t         ucSlotNumber;
226        uint32_t        ulDeviceID;
227        uint32_t        ulBAR0;
228        uint8_t         ucIntVector;
229        uint32_t        ulInitClkPCIAddr;
230        uint32_t        ulAPROM;
231        uint32_t        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((uint32_t)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((uint32_t)&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((uint32_t)&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=(uint32_t)&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 */
461static void
462amd79c970_retire_tx_bd (amd79c970Context_t *dp)
463{
464        uint16_t   status;
465        uint32_t   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 */
522static int
523amd79c970_raw (struct iface *iface, struct mbuf **bpp)
524{
525        amd79c970Context_t *dp;
526        struct mbuf *bp;
527        tmde_t *firstTxBd, *txBd;
528        uint16_t   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((uint32_t)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 */
673static void
674amd79c970_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        uint16_t         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                                (uint32_t)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 */
796static int
797amd79c970_stop (struct iface *iface)
798{
799        amd79c970Context_t *dp;
800        uint32_t        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 */
841static void
842amd79c970_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 */
883int
884rtems_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                (((uint32_t)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 */
Note: See TracBrowser for help on using the repository browser.