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

4.104.114.84.95
Last change on this file since d2632274 was 1f0f3e35, checked in by Joel Sherrill <joel.sherrill@…>, on 05/27/97 at 23:39:29

added ka9q stack

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