source: rtems/c/src/lib/libbsp/m68k/gen68360/network/network.c @ 35a1ec9

4.104.114.84.95
Last change on this file since 35a1ec9 was 35a1ec9, checked in by Joel Sherrill <joel.sherrill@…>, on 01/06/98 at 20:18:21

Updates from Eric Norum. Changed CPU CFLAG and went to a common name
for the network driver attach entry point.

  • Property mode set to 100644
File size: 22.5 KB
Line 
1/*
2 * RTEMS/KA9Q driver for M68360 SCC1 Ethernet
3 *
4 * W. Eric Norum
5 * Saskatchewan Accelerator Laboratory
6 * University of Saskatchewan
7 * Saskatoon, Saskatchewan, CANADA
8 * eric@skatter.usask.ca
9 *
10 *  $Id$
11 */
12#include <bsp.h>
13#include <m68360.h>
14#include <rtems/error.h>
15#include <ka9q/rtems_ka9q.h>
16#include <ka9q/global.h>
17#include <ka9q/enet.h>
18#include <ka9q/iface.h>
19#include <ka9q/netuser.h>
20#include <ka9q/trace.h>
21#include <ka9q/commands.h>
22
23/*
24 * Number of SCCs supported by this driver
25 */
26#define NSCCDRIVER      1
27
28/*
29 * Default number of buffer descriptors set aside for this driver.
30 * The number of transmit buffer descriptors has to be quite large
31 * since a single frame often uses four or more buffer descriptors.
32 */
33#define RX_BUF_COUNT     15
34#define TX_BUF_COUNT     4
35#define TX_BD_PER_BUF    4
36
37/*
38 * RTEMS event used by interrupt handler to signal daemons.
39 * This must *not* be the same event used by the KA9Q task synchronization.
40 */
41#define INTERRUPT_EVENT RTEMS_EVENT_1
42
43/*
44 * Receive buffer size -- Allow for a full ethernet packet plus a pointer
45 */
46#define RBUF_SIZE       (1520 + sizeof (struct iface *))
47
48/*
49 * Hardware-specific storage
50 */
51struct m360EnetDriver {
52        struct mbuf             **rxMbuf;
53        struct mbuf             **txMbuf;
54        int                     rxBdCount;
55        int                     txBdCount;
56        int                     txBdHead;
57        int                     txBdTail;
58        int                     txBdActiveCount;
59        m360BufferDescriptor_t  *rxBdBase;
60        m360BufferDescriptor_t  *txBdBase;
61        struct iface            *iface;
62        rtems_id                txWaitTid;
63
64        /*
65         * Statistics
66         */
67        unsigned long   rxInterrupts;
68        unsigned long   rxNotFirst;
69        unsigned long   rxNotLast;
70        unsigned long   rxGiant;
71        unsigned long   rxNonOctet;
72        unsigned long   rxRunt;
73        unsigned long   rxBadCRC;
74        unsigned long   rxOverrun;
75        unsigned long   rxCollision;
76
77        unsigned long   txInterrupts;
78        unsigned long   txDeferred;
79        unsigned long   txHeartbeat;
80        unsigned long   txLateCollision;
81        unsigned long   txRetryLimit;
82        unsigned long   txUnderrun;
83        unsigned long   txLostCarrier;
84        unsigned long   txRawWait;
85};
86static struct m360EnetDriver m360EnetDriver[NSCCDRIVER];
87
88/*
89 * SCC1 interrupt handler
90 */
91static rtems_isr
92m360Enet_interrupt_handler (rtems_vector_number v)
93{
94        /*
95         * Frame received?
96         */
97        if ((m360.scc1.sccm & 0x8) && (m360.scc1.scce & 0x8)) {
98                m360.scc1.scce = 0x8;
99                m360.scc1.sccm &= ~0x8;
100                m360EnetDriver[0].rxInterrupts++;
101                rtems_event_send (m360EnetDriver[0].iface->rxproc, INTERRUPT_EVENT);
102        }
103
104        /*
105         * Buffer transmitted or transmitter error?
106         */
107        if ((m360.scc1.sccm & 0x12) && (m360.scc1.scce & 0x12)) {
108                m360.scc1.scce = 0x12;
109                m360.scc1.sccm &= ~0x12;
110                m360EnetDriver[0].txInterrupts++;
111                rtems_event_send (m360EnetDriver[0].txWaitTid, INTERRUPT_EVENT);
112        }
113        m360.cisr = 1UL << 30;  /* Clear SCC1 interrupt-in-service bit */
114}
115
116/*
117 * Initialize the ethernet hardware
118 */
119static void
120m360Enet_initialize_hardware (struct m360EnetDriver *dp, int broadcastFlag)
121{
122        int i;
123        unsigned char *hwaddr;
124        rtems_status_code sc;
125        rtems_isr_entry old_handler;
126
127        /*
128         * Configure port A CLK1, CLK2, TXD1 and RXD1 pins
129         */
130        m360.papar |=  0x303;
131        m360.padir &= ~0x303;
132        m360.paodr &= ~0x303;
133       
134        /*
135         * Configure port C CTS1* and CD1* pins
136         */
137        m360.pcpar &= ~0x30;
138        m360.pcdir &= ~0x30;
139        m360.pcso  |=  0x30;
140
141        /*
142         * Connect CLK1 and CLK2 to SCC1
143         */
144        m360.sicr &= ~0xFF;
145        m360.sicr |= (5 << 3) | 4;
146
147        /*
148         * Allocate mbuf pointers
149         */
150        dp->rxMbuf = mallocw (dp->rxBdCount * sizeof *dp->rxMbuf);
151        dp->txMbuf = mallocw (dp->txBdCount * sizeof *dp->txMbuf);
152
153        /*
154         * Set receiver and transmitter buffer descriptor bases
155         */
156        dp->rxBdBase = M360AllocateBufferDescriptors(dp->rxBdCount);
157        dp->txBdBase = M360AllocateBufferDescriptors(dp->txBdCount);
158        m360.scc1p.rbase = (char *)dp->rxBdBase - (char *)&m360;
159        m360.scc1p.tbase = (char *)dp->txBdBase - (char *)&m360;
160
161        /*
162         * Send "Init parameters" command
163         */
164        M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SCC1);
165
166        /*
167         * Set receive and transmit function codes
168         */
169        m360.scc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
170        m360.scc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
171
172        /*
173         * Set maximum receive buffer length
174         */
175        m360.scc1p.mrblr = 1520;
176
177        /*
178         * Set CRC parameters
179         */
180        m360.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
181        m360.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
182
183        /*
184         * Clear diagnostic counters
185         */
186        m360.scc1p.un.ethernet.crcec = 0;
187        m360.scc1p.un.ethernet.alec = 0;
188        m360.scc1p.un.ethernet.disfc = 0;
189
190        /*
191         * Set pad value
192         */
193        m360.scc1p.un.ethernet.pads = 0x8888;
194
195        /*
196         * Set retry limit
197         */
198        m360.scc1p.un.ethernet.ret_lim = 15;
199
200        /*
201         * Set maximum and minimum frame length
202         */
203        m360.scc1p.un.ethernet.mflr = 1518;
204        m360.scc1p.un.ethernet.minflr = 64;
205        m360.scc1p.un.ethernet.maxd1 = 1520;
206        m360.scc1p.un.ethernet.maxd2 = 1520;
207
208        /*
209         * Clear group address hash table
210         */
211        m360.scc1p.un.ethernet.gaddr1 = 0;
212        m360.scc1p.un.ethernet.gaddr2 = 0;
213        m360.scc1p.un.ethernet.gaddr3 = 0;
214        m360.scc1p.un.ethernet.gaddr4 = 0;
215
216        /*
217         * Set our physical address
218         */
219        hwaddr = dp->iface->hwaddr;
220        m360.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
221        m360.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
222        m360.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
223
224        /*
225         * Aggressive retry
226         */
227        m360.scc1p.un.ethernet.p_per = 0;
228       
229        /*
230         * Clear individual address hash table
231         */
232        m360.scc1p.un.ethernet.iaddr1 = 0;
233        m360.scc1p.un.ethernet.iaddr2 = 0;
234        m360.scc1p.un.ethernet.iaddr3 = 0;
235        m360.scc1p.un.ethernet.iaddr4 = 0;
236
237        /*
238         * Set up receive buffer descriptors
239         */
240        for (i = 0 ; i < dp->rxBdCount ; i++)
241                (dp->rxBdBase + i)->status = 0;
242
243        /*
244         * Set up transmit buffer descriptors
245         */
246        for (i = 0 ; i < dp->txBdCount ; i++) {
247                (dp->txBdBase + i)->status = 0;
248                dp->txMbuf[i] = NULL;
249        }
250        dp->txBdHead = dp->txBdTail = 0;
251        dp->txBdActiveCount = 0;
252
253        /*
254         * Clear any outstanding events
255         */
256        m360.scc1.scce = 0xFFFF;
257
258        /*
259         * Set up interrupts
260         */
261        sc = rtems_interrupt_catch (m360Enet_interrupt_handler,
262                                                (m360.cicr & 0xE0) | 0x1E,
263                                                &old_handler);
264        if (sc != RTEMS_SUCCESSFUL)
265                rtems_panic ("Can't attach M360 SCC1 interrupt handler: %s\n",
266                                                        rtems_status_text (sc));
267        m360.scc1.sccm = 0;     /* No interrupts unmasked till necessary */
268        m360.cimr |= (1UL << 30);       /* Enable SCC1 interrupt */
269
270        /*
271         * Set up General SCC Mode Register
272         * Ethernet configuration
273         */
274        m360.scc1.gsmr_h = 0x0;
275        m360.scc1.gsmr_l = 0x1088000c;
276
277        /*
278         * Set up data synchronization register
279         * Ethernet synchronization pattern
280         */
281        m360.scc1.dsr = 0xd555;
282
283        /*
284         * Set up protocol-specific mode register
285         *      Heartbeat check
286         *      No force collision
287         *      Discard short frames
288         *      Individual address mode
289         *      Ethernet CRC
290         *      Not promisuous
291         *      Ignore/accept broadcast packets as specified
292         *      Normal backoff timer
293         *      No loopback
294         *      No input sample at end of frame
295         *      64-byte limit for late collision
296         *      Wait 22 bits before looking for start of frame delimiter
297         *      Disable full-duplex operation
298         */
299        m360.scc1.psmr = 0x880A | (broadcastFlag ? 0 : 0x100);
300
301        /*
302         * Enable the TENA (RTS1*) pin
303         */
304#if (defined (M68360_ATLAS_HSB))
305        m360.pbpar |= 0x1000;
306        m360.pbdir |= 0x1000;
307#else
308        m360.pcpar |=  0x1;
309        m360.pcdir &= ~0x1;
310#endif
311
312        /*
313         * Enable receiver and transmitter
314         */
315        m360.scc1.gsmr_l = 0x1088003c;
316}
317
318/*
319 * Soak up buffer descriptors that have been sent
320 * Note that a buffer descriptor can't be retired as soon as it becomes
321 * ready.  The MC68360 Errata (May 96) says that, "If an Ethernet frame is
322 *  made up of multiple buffers, the user should not reuse the first buffer
323 * descriptor until the last buffer descriptor of the frame has had its
324 * ready bit cleared by the CPM".
325 */
326static void
327m360Enet_retire_tx_bd (struct m360EnetDriver *dp)
328{
329        rtems_unsigned16 status;
330        int i;
331        int nRetired;
332
333        i = dp->txBdTail;
334        nRetired = 0;
335        while ((dp->txBdActiveCount != 0)
336           &&  (((status = (dp->txBdBase + i)->status) & M360_BD_READY) == 0)) {
337                /*
338                 * See if anything went wrong
339                 */
340                if (status & (M360_BD_DEFER |
341                                M360_BD_HEARTBEAT |
342                                M360_BD_LATE_COLLISION |
343                                M360_BD_RETRY_LIMIT |
344                                M360_BD_UNDERRUN |
345                                M360_BD_CARRIER_LOST)) {
346                        /*
347                         * Check for errors which stop the transmitter.
348                         */
349                        if (status & (M360_BD_LATE_COLLISION |
350                                        M360_BD_RETRY_LIMIT |
351                                        M360_BD_UNDERRUN)) {
352                                if (status & M360_BD_LATE_COLLISION)
353                                        m360EnetDriver[0].txLateCollision++;
354                                if (status & M360_BD_RETRY_LIMIT)
355                                        m360EnetDriver[0].txRetryLimit++;
356                                if (status & M360_BD_UNDERRUN)
357                                        m360EnetDriver[0].txUnderrun++;
358
359                                /*
360                                 * Restart the transmitter
361                                 */
362                                M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);
363                        }
364                        if (status & M360_BD_DEFER)
365                                m360EnetDriver[0].txDeferred++;
366                        if (status & M360_BD_HEARTBEAT)
367                                m360EnetDriver[0].txHeartbeat++;
368                        if (status & M360_BD_CARRIER_LOST)
369                                m360EnetDriver[0].txLostCarrier++;
370                }
371                nRetired++;
372                if (status & M360_BD_LAST) {
373                        /*
374                         * A full frame has been transmitted.
375                         * Free all the associated buffer descriptors.
376                         */
377                        dp->txBdActiveCount -= nRetired;
378                        while (nRetired) {
379                                nRetired--;
380                                free_mbuf (&dp->txMbuf[dp->txBdTail]);
381                                if (++dp->txBdTail == dp->txBdCount)
382                                        dp->txBdTail = 0;
383                        }
384                }
385                if (++i == dp->txBdCount)
386                        i = 0;
387        }
388}
389
390/*
391 * Send raw packet (caller provides header).
392 * This code runs in the context of the interface transmit
393 * task or in the context of the network task.
394 */
395static int
396m360Enet_raw (struct iface *iface, struct mbuf **bpp)
397{
398        struct m360EnetDriver *dp = &m360EnetDriver[iface->dev];
399        struct mbuf *bp;
400        volatile m360BufferDescriptor_t *firstTxBd, *txBd;
401        rtems_unsigned16 status;
402        int nAdded;
403
404        /*
405         * Fill in some logging data
406         */
407        iface->rawsndcnt++;
408        iface->lastsent = secclock ();
409        dump (iface, IF_TRACE_OUT, *bpp);
410
411        /*
412         * It would not do to have two tasks active in the transmit
413         * loop at the same time.
414         * The blocking is simple-minded since the odds of two tasks
415         * simultaneously attempting to use this code are low.  The only
416         * way that two tasks can try to run here is:
417         *      1) Task A enters this code and ends up having to
418         *         wait for a transmit buffer descriptor.
419         *      2) Task B  gains control and tries to transmit a packet.
420         * The RTEMS/KA9Q scheduling semaphore ensures that there
421         * are no race conditions associated with manipulating the
422         * txWaitTid variable.
423         */
424        if (dp->txWaitTid) {
425                dp->txRawWait++;
426                while (dp->txWaitTid)
427                        rtems_ka9q_ppause (10);
428        }
429
430        /*
431         * Free up buffer descriptors
432         */
433        m360Enet_retire_tx_bd (dp);
434
435        /*
436         * Set up the transmit buffer descriptors.
437         * No need to pad out short packets since the
438         * hardware takes care of that automatically.
439         * No need to copy the packet to a contiguous buffer
440         * since the hardware is capable of scatter/gather DMA.
441         */
442        bp = *bpp;
443        nAdded = 0;
444        txBd = firstTxBd = dp->txBdBase + dp->txBdHead;
445        for (;;) {
446                /*
447                 * Wait for buffer descriptor to become available.
448                 */
449                if ((dp->txBdActiveCount + nAdded) == dp->txBdCount) {
450                        /*
451                         * Find out who we are
452                         */
453                        if (dp->txWaitTid == 0)
454                                rtems_task_ident (0, 0, &dp->txWaitTid);
455
456                        /*
457                         * Clear old events
458                         */
459                        m360.scc1.scce = 0x12;
460
461                        /*
462                         * Wait for buffer descriptor to become available.
463                         * Note that the buffer descriptors are checked
464                         * *before* * entering the wait loop -- this catches
465                         * the possibility that a buffer descriptor became
466                         * available between the `if' above, and the clearing
467                         * of the event register.
468                         * This is to catch the case where the transmitter
469                         * stops in the middle of a frame -- and only the
470                         * last buffer descriptor in a frame can generate
471                         * an interrupt.
472                         */
473                        m360Enet_retire_tx_bd (dp);
474                        while ((dp->txBdActiveCount + nAdded) == dp->txBdCount) {
475                                /*
476                                 * Unmask TXB (buffer transmitted) and
477                                 * TXE (transmitter error) events.
478                                 */
479                                m360.scc1.sccm |= 0x12;
480
481                                rtems_ka9q_event_receive (INTERRUPT_EVENT,
482                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
483                                                RTEMS_NO_TIMEOUT);
484                                m360Enet_retire_tx_bd (dp);
485                        }
486                }
487
488                /*
489                 * Fill in the buffer descriptor
490                 */
491                txBd->buffer = bp->data;
492                txBd->length = bp->cnt;
493                dp->txMbuf[dp->txBdHead] = bp;
494
495                /*
496                 * Don't set the READY flag till the whole packet has been readied.
497                 */
498                status = nAdded ? M360_BD_READY : 0;
499                nAdded++;
500                if (++dp->txBdHead == dp->txBdCount) {
501                        status |= M360_BD_WRAP;
502                        dp->txBdHead = 0;
503                }
504
505                /*
506                 * Set the transmit buffer status.
507                 * Break out of the loop if this mbuf is the last in the frame.
508                 */
509                if ((bp = bp->next) == NULL) {
510                        status |= M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;
511                        txBd->status = status;
512                        firstTxBd->status |= M360_BD_READY;
513                        dp->txBdActiveCount += nAdded;
514                        break;
515                }
516                txBd->status = status;
517                txBd = dp->txBdBase + dp->txBdHead;
518        }
519
520        /*
521         * Show that we've finished with the packet
522         */
523        dp->txWaitTid = 0;
524        *bpp = NULL;
525        return 0;
526}
527
528/*
529 * SCC reader task
530 */
531static void
532m360Enet_rx (int dev, void *p1, void *p2)
533{
534        struct iface *iface = (struct iface *)p1;
535        struct m360EnetDriver *dp = (struct m360EnetDriver *)p2;
536        struct mbuf *bp;
537        rtems_unsigned16 status;
538        m360BufferDescriptor_t *rxBd;
539        int rxBdIndex;
540        int continuousCount;
541
542        /*
543         * Allocate space for incoming packets and start reception
544         */
545        for (rxBdIndex = 0 ; ;) {
546                rxBd = dp->rxBdBase + rxBdIndex;
547                dp->rxMbuf[rxBdIndex] = bp = ambufw (RBUF_SIZE);
548                bp->data += sizeof (struct iface *);
549                rxBd->buffer = bp->data;
550                rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT;
551                if (++rxBdIndex == dp->rxBdCount) {
552                        rxBd->status |= M360_BD_WRAP;
553                        break;
554                }
555        }
556
557        /*
558         * Input packet handling loop
559         */
560        continuousCount = 0;
561        rxBdIndex = 0;
562        for (;;) {
563                rxBd = dp->rxBdBase + rxBdIndex;
564
565                /*
566                 * Wait for packet if there's not one ready
567                 */
568                if ((status = rxBd->status) & M360_BD_EMPTY) {
569                        /*
570                         * Reset `continuous-packet' count
571                         */
572                        continuousCount = 0;
573
574                        /*
575                         * Clear old events
576                         */
577                        m360.scc1.scce = 0x8;
578
579                        /*
580                         * Wait for packet
581                         * Note that the buffer descriptor is checked
582                         * *before* the event wait -- this catches the
583                         * possibility that a packet arrived between the
584                         * `if' above, and the clearing of the event register.
585                         */
586                        while ((status = rxBd->status) & M360_BD_EMPTY) {
587                                /*
588                                 * Unmask RXF (Full frame received) event
589                                 */
590                                m360.scc1.sccm |= 0x8;
591
592                                rtems_ka9q_event_receive (INTERRUPT_EVENT,
593                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
594                                                RTEMS_NO_TIMEOUT);
595                        }
596                }
597
598                /*
599                 * Check that packet is valid
600                 */
601                if ((status & (M360_BD_LAST |
602                                M360_BD_FIRST_IN_FRAME |
603                                M360_BD_LONG |
604                                M360_BD_NONALIGNED |
605                                M360_BD_SHORT |
606                                M360_BD_CRC_ERROR |
607                                M360_BD_OVERRUN |
608                                M360_BD_COLLISION)) ==
609                                                (M360_BD_LAST |
610                                                M360_BD_FIRST_IN_FRAME)) {
611                        /*
612                         * Pass the packet up the chain
613                         * The mbuf count is reduced to remove
614                         * the frame check sequence at the end
615                         * of the packet.
616                         */
617                        bp = dp->rxMbuf[rxBdIndex];
618                        bp->cnt = rxBd->length - sizeof (uint32);
619                        net_route (iface, &bp);
620
621                        /*
622                         * Give the network code a chance to digest the
623                         * packet.  This guards against a flurry of
624                         * incoming packets (usually an ARP storm) from
625                         * using up all the available memory.
626                         */
627                        if (++continuousCount >= dp->rxBdCount)
628                                kwait_null ();
629
630                        /*
631                         * Allocate a new mbuf
632                         * FIXME: It seems to me that it would be better
633                         * if there were some way to limit number of mbufs
634                         * in use by this interface, but I don't see any
635                         * way of determining when the mbuf we pass up
636                         * is freed.
637                         */
638                        dp->rxMbuf[rxBdIndex] = bp = ambufw (RBUF_SIZE);
639                        bp->data += sizeof (struct iface *);
640                        rxBd->buffer = bp->data;
641                }
642                else {
643                        /*
644                         * Something went wrong with the reception
645                         */
646                        if (!(status & M360_BD_LAST))
647                                dp->rxNotLast++;
648                        if (!(status & M360_BD_FIRST_IN_FRAME))
649                                dp->rxNotFirst++;
650                        if (status & M360_BD_LONG)
651                                dp->rxGiant++;
652                        if (status & M360_BD_NONALIGNED)
653                                dp->rxNonOctet++;
654                        if (status & M360_BD_SHORT)
655                                dp->rxRunt++;
656                        if (status & M360_BD_CRC_ERROR)
657                                dp->rxBadCRC++;
658                        if (status & M360_BD_OVERRUN)
659                                dp->rxOverrun++;
660                        if (status & M360_BD_COLLISION)
661                                dp->rxCollision++;
662                }
663
664                /*
665                 * Reenable the buffer descriptor
666                 */
667                rxBd->status = (status & (M360_BD_WRAP | M360_BD_INTERRUPT)) | M360_BD_EMPTY;
668
669                /*
670                 * Move to next buffer descriptor
671                 */
672                if (++rxBdIndex == dp->rxBdCount)
673                        rxBdIndex = 0;
674        }
675}
676
677/*
678 * Shut down the interface
679 * FIXME: This is a pretty simple-minded routine.  It doesn't worry
680 * about cleaning up mbufs, shutting down daemons, etc.
681 */
682static int
683m360Enet_stop (struct iface *iface)
684{
685        /*
686         * Stop the transmitter
687         */
688        M360ExecuteRISC (M360_CR_OP_GR_STOP_TX | M360_CR_CHAN_SCC1);
689
690        /*
691         * Wait for graceful stop
692         * FIXME: Maybe there should be a watchdog loop around this....
693         */
694        while ((m360.scc1.scce & 0x80) == 0)
695                continue;
696
697        /*
698         * Shut down receiver and transmitter
699         */
700        m360.scc1.gsmr_l &= ~0x30;
701        return 0;
702}
703
704/*
705 * Show interface statistics
706 */
707static void
708m360Enet_show (struct iface *iface)
709{
710        printf ("      Rx Interrupts:%-8lu", m360EnetDriver[0].rxInterrupts);
711        printf ("       Not First:%-8lu", m360EnetDriver[0].rxNotFirst);
712        printf ("        Not Last:%-8lu\n", m360EnetDriver[0].rxNotLast);
713        printf ("              Giant:%-8lu", m360EnetDriver[0].rxGiant);
714        printf ("            Runt:%-8lu", m360EnetDriver[0].rxRunt);
715        printf ("       Non-octet:%-8lu\n", m360EnetDriver[0].rxNonOctet);
716        printf ("            Bad CRC:%-8lu", m360EnetDriver[0].rxBadCRC);
717        printf ("         Overrun:%-8lu", m360EnetDriver[0].rxOverrun);
718        printf ("       Collision:%-8lu\n", m360EnetDriver[0].rxCollision);
719        printf ("          Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
720
721        printf ("      Tx Interrupts:%-8lu", m360EnetDriver[0].txInterrupts);
722        printf ("        Deferred:%-8lu", m360EnetDriver[0].txDeferred);
723        printf (" Missed Hearbeat:%-8lu\n", m360EnetDriver[0].txHeartbeat);
724        printf ("         No Carrier:%-8lu", m360EnetDriver[0].txLostCarrier);
725        printf ("Retransmit Limit:%-8lu", m360EnetDriver[0].txRetryLimit);
726        printf ("  Late Collision:%-8lu\n", m360EnetDriver[0].txLateCollision);
727        printf ("           Underrun:%-8lu", m360EnetDriver[0].txUnderrun);
728        printf (" Raw output wait:%-8lu\n", m360EnetDriver[0].txRawWait);
729}
730
731/*
732 * Attach an SCC driver to the system
733 * This is the only `extern' function in the driver.
734 *
735 * argv[0]: interface label, e.g., "rtems"
736 * The remainder of the arguemnts are key/value pairs:
737 * mtu ##                  --  maximum transmission unit, default 1500
738 * broadcast y/n           -- accept or ignore broadcast packets, default yes
739 * rbuf ##                 -- Set number of receive buffer descriptors
740 * rbuf ##                 -- Set number of transmit buffer descriptors
741 * ip ###.###.###.###      -- IP address
742 * ether ##:##:##:##:##:## -- Ethernet address
743 * ether prom              -- Get Ethernet address from bootstrap PROM
744 */
745int
746rtems_ka9q_driver_attach (int argc, char *argv[], void *p)
747{
748        struct iface *iface;
749        struct m360EnetDriver *dp;
750        char *cp;
751        int i;
752        int argIndex;
753        int broadcastFlag;
754        char cbuf[30];
755
756        /*
757         * Find a free driver
758         */
759        for (i = 0 ; i < NSCCDRIVER ; i++) {
760                if (m360EnetDriver[i].iface == NULL)
761                        break;
762        }
763        if (i >= NSCCDRIVER) {
764                printf ("Too many SCC drivers.\n");
765                return -1;
766        }
767        if (if_lookup (argv[0]) != NULL) {
768                printf ("Interface %s already exists\n", argv[0]);
769                return -1;
770        }
771        dp = &m360EnetDriver[i];
772
773        /*
774         * Create an inteface descriptor
775         */
776        iface = callocw (1, sizeof *iface);
777        iface->name = strdup (argv[0]);
778
779        /*
780         * Set default values
781         */
782        broadcastFlag = 1;
783        dp->txWaitTid = 0;
784        dp->rxBdCount = RX_BUF_COUNT;
785        dp->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
786        iface->mtu = 1500;
787        iface->addr = Ip_addr;
788        iface->hwaddr = mallocw (EADDR_LEN);
789        memset (iface->hwaddr, 0x08, EADDR_LEN);
790
791        /*
792         * Parse arguments
793         */
794        for (argIndex = 1 ; argIndex < (argc - 1) ; argIndex++) {
795                if (strcmp ("mtu", argv[argIndex]) == 0) {
796                        iface->mtu = atoi (argv[++argIndex]);
797                }
798                else if (strcmp ("broadcast", argv[argIndex]) == 0) {
799                        if (*argv[++argIndex] == 'n')
800                                broadcastFlag = 0;
801                }
802                else if (strcmp ("rbuf", argv[argIndex]) == 0) {
803                        dp->rxBdCount = atoi (argv[++argIndex]);
804                }
805                else if (strcmp ("tbuf", argv[argIndex]) == 0) {
806                        dp->txBdCount = atoi (argv[++argIndex]) * TX_BD_PER_BUF;
807                }
808                else if (strcmp ("ip", argv[argIndex]) == 0) {
809                        iface->addr = resolve (argv[++argIndex]);
810                }
811                else if (strcmp ("ether", argv[argIndex]) == 0) {
812                        argIndex++;
813                        if (strcmp (argv[argIndex], "prom") == 0) {
814                                /*
815                                 * The first 4 bytes of the bootstrap prom
816                                 * contain the value loaded into the stack
817                                 * pointer as part of the CPU32's hardware
818                                 * reset exception handler.  The following
819                                 * 4 bytes contain the value loaded into the
820                                 * program counter.  The low order three
821                                 * octets of the boards' Ethernet address are
822                                 * stored in the three bytes immediately
823                                 * preceding this initial program counter value.
824                                 *
825                                 * See startup/linkcmds and start360/start360.s
826                                 * for details on how this is done.
827                                 *
828                                 * The high order three octets of the Ethernet
829                                 * address are fixed and indicate that the
830                                 * address is that of a Motorola device.
831                                 */
832                                extern void *_RomBase;  /* From linkcmds */
833                                const unsigned long *ExceptionVectors;
834                                const unsigned char *entryPoint;
835
836                                /*
837                                 * Set up the fixed portion of the address
838                                 */
839                                iface->hwaddr[0] = 0x08;
840                                iface->hwaddr[1] = 0x00;
841                                iface->hwaddr[2] = 0x3e;
842
843                                /*
844                                 * Sanity check -- assume entry point must be
845                                 * within 1 MByte of beginning of boot ROM.
846                                 */
847                                ExceptionVectors = (const unsigned long *)&_RomBase;
848                                entryPoint = (const unsigned char *)ExceptionVectors[1];
849                                if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
850                                                        >= (1 * 1024 * 1024)) {
851                                        printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
852                                        iface->hwaddr[3] = 0xC2;
853                                        iface->hwaddr[4] = 0xE7;
854                                        iface->hwaddr[5] = 0x08;
855                                }
856                                else {
857                                        iface->hwaddr[3] = entryPoint[-3];
858                                        iface->hwaddr[4] = entryPoint[-2];
859                                        iface->hwaddr[5] = entryPoint[-1];
860                                }
861                        }
862                        else {
863                                gether (iface->hwaddr, argv[argIndex]);
864                        }
865                }
866                else {
867                        printf ("Argument %d (%s) is invalid.\n", argIndex, argv[argIndex]);
868                        return -1;
869                }
870        }
871        printf ("Ethernet address: %s\n", pether (cbuf, iface->hwaddr));
872
873        /*
874         * Fill in remainder of interface configuration
875         */
876        iface->dev = i;
877        iface->raw = m360Enet_raw;
878        iface->stop = m360Enet_stop;
879        iface->show = m360Enet_show;
880        dp->iface = iface;
881        setencap (iface, "Ethernet");
882
883        /*
884         * Set up SCC hardware
885         */
886        m360Enet_initialize_hardware (dp, broadcastFlag);
887
888        /*
889         * Chain onto list of interfaces
890         */
891        iface->next = Ifaces;
892        Ifaces = iface;
893
894        /*
895         * Start I/O daemons
896         */
897        cp = if_name (iface, " tx");
898        iface->txproc = newproc (cp, 1024, if_tx, iface->dev, iface, NULL, 0);
899        free (cp);
900        cp = if_name (iface, " rx");
901        iface->rxproc = newproc (cp, 1024, m360Enet_rx, iface->dev, iface, dp, 0);
902        free (cp);
903        return 0;
904}
905
906/*
907 * FIXME: There should be an ioctl routine to allow things like
908 * enabling/disabling reception of broadcast packets.
909 */
Note: See TracBrowser for help on using the repository browser.