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

4.104.114.84.95
Last change on this file since dffa304 was d47de32, checked in by Joel Sherrill <joel.sherrill@…>, on 08/21/98 at 14:04:31

Update from Eric Norum.

  • Property mode set to 100644
File size: 21.3 KB
Line 
1/*
2 * RTEMS 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 <m68360.h>
15#include <stdio.h>
16#include <stdarg.h>
17#include <stdarg.h>
18#include <rtems/error.h>
19#include <rtems/rtems_bsdnet.h>
20
21#include <sys/param.h>
22#include <sys/mbuf.h>
23#include <sys/socket.h>
24#include <sys/sockio.h>
25
26#include <net/if.h>
27
28#include <netinet/in.h>
29#include <netinet/if_ether.h>
30
31/*
32 * Number of SCCs supported by this driver
33 */
34#define NSCCDRIVER      1
35
36/*
37 * Default number of buffer descriptors set aside for this driver.
38 * The number of transmit buffer descriptors has to be quite large
39 * since a single frame often uses four or more buffer descriptors.
40 */
41#define RX_BUF_COUNT     15
42#define TX_BUF_COUNT     4
43#define TX_BD_PER_BUF    4
44
45/*
46 * RTEMS event used by interrupt handler to signal driver tasks.
47 * This must not be any of the events used by the network task synchronization.
48 */
49#define INTERRUPT_EVENT RTEMS_EVENT_1
50
51/*
52 * RTEMS event used to start transmit daemon.
53 * This must not be the same as INTERRUPT_EVENT.
54 */
55#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
56
57/*
58 * Receive buffer size -- Allow for a full ethernet packet including CRC
59 */
60#define RBUF_SIZE       1520
61
62#if (MCLBYTES < RBUF_SIZE)
63# error "Driver must have MCLBYTES > RBUF_SIZE"
64#endif
65
66/*
67 * Per-device data
68 */
69struct scc_softc {
70        struct arpcom           arpcom;
71        struct mbuf             **rxMbuf;
72        struct mbuf             **txMbuf;
73        int                     acceptBroadcast;
74        int                     rxBdCount;
75        int                     txBdCount;
76        int                     txBdHead;
77        int                     txBdTail;
78        int                     txBdActiveCount;
79        m360BufferDescriptor_t  *rxBdBase;
80        m360BufferDescriptor_t  *txBdBase;
81        rtems_id                rxDaemonTid;
82        rtems_id                txDaemonTid;
83
84        /*
85         * Statistics
86         */
87        unsigned long   rxInterrupts;
88        unsigned long   rxNotFirst;
89        unsigned long   rxNotLast;
90        unsigned long   rxGiant;
91        unsigned long   rxNonOctet;
92        unsigned long   rxRunt;
93        unsigned long   rxBadCRC;
94        unsigned long   rxOverrun;
95        unsigned long   rxCollision;
96
97        unsigned long   txInterrupts;
98        unsigned long   txDeferred;
99        unsigned long   txHeartbeat;
100        unsigned long   txLateCollision;
101        unsigned long   txRetryLimit;
102        unsigned long   txUnderrun;
103        unsigned long   txLostCarrier;
104        unsigned long   txRawWait;
105};
106static struct scc_softc scc_softc[NSCCDRIVER];
107
108/*
109 * SCC1 interrupt handler
110 */
111static rtems_isr
112m360Enet_interrupt_handler (rtems_vector_number v)
113{
114        /*
115         * Frame received?
116         */
117        if ((m360.scc1.sccm & 0x8) && (m360.scc1.scce & 0x8)) {
118                m360.scc1.scce = 0x8;
119                m360.scc1.sccm &= ~0x8;
120                scc_softc[0].rxInterrupts++;
121                rtems_event_send (scc_softc[0].rxDaemonTid, INTERRUPT_EVENT);
122        }
123
124        /*
125         * Buffer transmitted or transmitter error?
126         */
127        if ((m360.scc1.sccm & 0x12) && (m360.scc1.scce & 0x12)) {
128                m360.scc1.scce = 0x12;
129                m360.scc1.sccm &= ~0x12;
130                scc_softc[0].txInterrupts++;
131                rtems_event_send (scc_softc[0].txDaemonTid, INTERRUPT_EVENT);
132        }
133        m360.cisr = 1UL << 30;  /* Clear SCC1 interrupt-in-service bit */
134}
135
136/*
137 * Initialize the ethernet hardware
138 */
139static void
140m360Enet_initialize_hardware (struct scc_softc *sc)
141{
142        int i;
143        unsigned char *hwaddr;
144        rtems_status_code status;
145        rtems_isr_entry old_handler;
146
147        /*
148         * Configure port A CLK1, CLK2, TXD1 and RXD1 pins
149         */
150        m360.papar |=  0x303;
151        m360.padir &= ~0x303;
152        m360.paodr &= ~0x303;
153       
154        /*
155         * Configure port C CTS1* and CD1* pins
156         */
157        m360.pcpar &= ~0x30;
158        m360.pcdir &= ~0x30;
159        m360.pcso  |=  0x30;
160
161        /*
162         * Connect CLK1 and CLK2 to SCC1
163         */
164        m360.sicr &= ~0xFF;
165        m360.sicr |= (5 << 3) | 4;
166
167        /*
168         * Allocate mbuf pointers
169         */
170        sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
171        sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
172        if (!sc->rxMbuf || !sc->txMbuf)
173                rtems_panic ("No memory for mbuf pointers");
174
175        /*
176         * Set receiver and transmitter buffer descriptor bases
177         */
178        sc->rxBdBase = M360AllocateBufferDescriptors(sc->rxBdCount);
179        sc->txBdBase = M360AllocateBufferDescriptors(sc->txBdCount);
180        m360.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m360;
181        m360.scc1p.tbase = (char *)sc->txBdBase - (char *)&m360;
182
183        /*
184         * Send "Init parameters" command
185         */
186        M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SCC1);
187
188        /*
189         * Set receive and transmit function codes
190         */
191        m360.scc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
192        m360.scc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
193
194        /*
195         * Set maximum receive buffer length
196         */
197        m360.scc1p.mrblr = RBUF_SIZE;
198
199        /*
200         * Set CRC parameters
201         */
202        m360.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
203        m360.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
204
205        /*
206         * Clear diagnostic counters
207         */
208        m360.scc1p.un.ethernet.crcec = 0;
209        m360.scc1p.un.ethernet.alec = 0;
210        m360.scc1p.un.ethernet.disfc = 0;
211
212        /*
213         * Set pad value
214         */
215        m360.scc1p.un.ethernet.pads = 0x8888;
216
217        /*
218         * Set retry limit
219         */
220        m360.scc1p.un.ethernet.ret_lim = 15;
221
222        /*
223         * Set maximum and minimum frame length
224         */
225        m360.scc1p.un.ethernet.mflr = 1518;
226        m360.scc1p.un.ethernet.minflr = 64;
227        m360.scc1p.un.ethernet.maxd1 = RBUF_SIZE;
228        m360.scc1p.un.ethernet.maxd2 = RBUF_SIZE;
229
230        /*
231         * Clear group address hash table
232         */
233        m360.scc1p.un.ethernet.gaddr1 = 0;
234        m360.scc1p.un.ethernet.gaddr2 = 0;
235        m360.scc1p.un.ethernet.gaddr3 = 0;
236        m360.scc1p.un.ethernet.gaddr4 = 0;
237
238        /*
239         * Set our physical address
240         */
241        hwaddr = sc->arpcom.ac_enaddr;
242        m360.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
243        m360.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
244        m360.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
245
246        /*
247         * Aggressive retry
248         */
249        m360.scc1p.un.ethernet.p_per = 0;
250       
251        /*
252         * Clear individual address hash table
253         */
254        m360.scc1p.un.ethernet.iaddr1 = 0;
255        m360.scc1p.un.ethernet.iaddr2 = 0;
256        m360.scc1p.un.ethernet.iaddr3 = 0;
257        m360.scc1p.un.ethernet.iaddr4 = 0;
258
259        /*
260         * Set up receive buffer descriptors
261         */
262        for (i = 0 ; i < sc->rxBdCount ; i++)
263                (sc->rxBdBase + i)->status = 0;
264
265        /*
266         * Set up transmit buffer descriptors
267         */
268        for (i = 0 ; i < sc->txBdCount ; i++) {
269                (sc->txBdBase + i)->status = 0;
270                sc->txMbuf[i] = NULL;
271        }
272        sc->txBdHead = sc->txBdTail = 0;
273        sc->txBdActiveCount = 0;
274
275        /*
276         * Clear any outstanding events
277         */
278        m360.scc1.scce = 0xFFFF;
279
280        /*
281         * Set up interrupts
282         */
283        status = rtems_interrupt_catch (m360Enet_interrupt_handler,
284                                                (m360.cicr & 0xE0) | 0x1E,
285                                                &old_handler);
286        if (status != RTEMS_SUCCESSFUL)
287                rtems_panic ("Can't attach M360 SCC1 interrupt handler: %s\n",
288                                                rtems_status_text (status));
289        m360.scc1.sccm = 0;     /* No interrupts unmasked till necessary */
290        m360.cimr |= (1UL << 30);       /* Enable SCC1 interrupt */
291
292        /*
293         * Set up General SCC Mode Register
294         * Ethernet configuration
295         */
296        m360.scc1.gsmr_h = 0x0;
297        m360.scc1.gsmr_l = 0x1088000c;
298
299        /*
300         * Set up data synchronization register
301         * Ethernet synchronization pattern
302         */
303        m360.scc1.dsr = 0xd555;
304
305        /*
306         * Set up protocol-specific mode register
307         *      Heartbeat check
308         *      No force collision
309         *      Discard short frames
310         *      Individual address mode
311         *      Ethernet CRC
312         *      Not promisuous
313         *      Ignore/accept broadcast packets as specified
314         *      Normal backoff timer
315         *      No loopback
316         *      No input sample at end of frame
317         *      64-byte limit for late collision
318         *      Wait 22 bits before looking for start of frame delimiter
319         *      Disable full-duplex operation
320         */
321        m360.scc1.psmr = 0x880A | (sc->acceptBroadcast ? 0 : 0x100);
322
323        /*
324         * Enable the TENA (RTS1*) pin
325         */
326#if (defined (M68360_ATLAS_HSB))
327        m360.pbpar |= 0x1000;
328        m360.pbdir |= 0x1000;
329#else
330        m360.pcpar |=  0x1;
331        m360.pcdir &= ~0x1;
332#endif
333}
334
335/*
336 * Soak up buffer descriptors that have been sent
337 * Note that a buffer descriptor can't be retired as soon as it becomes
338 * ready.  The MC68360 Errata (May 96) says that, "If an Ethernet frame is
339 *  made up of multiple buffers, the user should not reuse the first buffer
340 * descriptor until the last buffer descriptor of the frame has had its
341 * ready bit cleared by the CPM".
342 */
343static void
344m360Enet_retire_tx_bd (struct scc_softc *sc)
345{
346        rtems_unsigned16 status;
347        int i;
348        int nRetired;
349        struct mbuf *m, *n;
350
351        i = sc->txBdTail;
352        nRetired = 0;
353        while ((sc->txBdActiveCount != 0)
354           &&  (((status = (sc->txBdBase + i)->status) & M360_BD_READY) == 0)) {
355                /*
356                 * See if anything went wrong
357                 */
358                if (status & (M360_BD_DEFER |
359                                M360_BD_HEARTBEAT |
360                                M360_BD_LATE_COLLISION |
361                                M360_BD_RETRY_LIMIT |
362                                M360_BD_UNDERRUN |
363                                M360_BD_CARRIER_LOST)) {
364                        /*
365                         * Check for errors which stop the transmitter.
366                         */
367                        if (status & (M360_BD_LATE_COLLISION |
368                                        M360_BD_RETRY_LIMIT |
369                                        M360_BD_UNDERRUN)) {
370                                if (status & M360_BD_LATE_COLLISION)
371                                        scc_softc[0].txLateCollision++;
372                                if (status & M360_BD_RETRY_LIMIT)
373                                        scc_softc[0].txRetryLimit++;
374                                if (status & M360_BD_UNDERRUN)
375                                        scc_softc[0].txUnderrun++;
376
377                                /*
378                                 * Restart the transmitter
379                                 */
380                                M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);
381                        }
382                        if (status & M360_BD_DEFER)
383                                scc_softc[0].txDeferred++;
384                        if (status & M360_BD_HEARTBEAT)
385                                scc_softc[0].txHeartbeat++;
386                        if (status & M360_BD_CARRIER_LOST)
387                                scc_softc[0].txLostCarrier++;
388                }
389                nRetired++;
390                if (status & M360_BD_LAST) {
391                        /*
392                         * A full frame has been transmitted.
393                         * Free all the associated buffer descriptors.
394                         */
395                        sc->txBdActiveCount -= nRetired;
396                        while (nRetired) {
397                                nRetired--;
398                                m = sc->txMbuf[sc->txBdTail];
399                                MFREE (m, n);
400                                if (++sc->txBdTail == sc->txBdCount)
401                                        sc->txBdTail = 0;
402                        }
403                }
404                if (++i == sc->txBdCount)
405                        i = 0;
406        }
407}
408
409/*
410 * SCC reader task
411 */
412static void
413scc_rxDaemon (void *arg)
414{
415        struct scc_softc *sc = (struct scc_softc *)arg;
416        struct ifnet *ifp = &sc->arpcom.ac_if;
417        struct mbuf *m;
418        rtems_unsigned16 status;
419        m360BufferDescriptor_t *rxBd;
420        int rxBdIndex;
421
422        /*
423         * Allocate space for incoming packets and start reception
424         */
425        for (rxBdIndex = 0 ; ;) {
426                rxBd = sc->rxBdBase + rxBdIndex;
427                MGETHDR (m, M_WAIT, MT_DATA);
428                MCLGET (m, M_WAIT);
429                m->m_pkthdr.rcvif = ifp;
430                sc->rxMbuf[rxBdIndex] = m;
431                rxBd->buffer = mtod (m, void *);
432                rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT;
433                if (++rxBdIndex == sc->rxBdCount) {
434                        rxBd->status |= M360_BD_WRAP;
435                        break;
436                }
437        }
438
439        /*
440         * Input packet handling loop
441         */
442        rxBdIndex = 0;
443        for (;;) {
444                rxBd = sc->rxBdBase + rxBdIndex;
445
446                /*
447                 * Wait for packet if there's not one ready
448                 */
449                if ((status = rxBd->status) & M360_BD_EMPTY) {
450                        /*
451                         * Clear old events
452                         */
453                        m360.scc1.scce = 0x8;
454
455                        /*
456                         * Wait for packet
457                         * Note that the buffer descriptor is checked
458                         * *before* the event wait -- this catches the
459                         * possibility that a packet arrived between the
460                         * `if' above, and the clearing of the event register.
461                         */
462                        while ((status = rxBd->status) & M360_BD_EMPTY) {
463                                rtems_event_set events;
464
465                                /*
466                                 * Unmask RXF (Full frame received) event
467                                 */
468                                m360.scc1.sccm |= 0x8;
469
470                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
471                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
472                                                RTEMS_NO_TIMEOUT,
473                                                &events);
474                        }
475                }
476
477                /*
478                 * Check that packet is valid
479                 */
480                if ((status & (M360_BD_LAST |
481                                M360_BD_FIRST_IN_FRAME |
482                                M360_BD_LONG |
483                                M360_BD_NONALIGNED |
484                                M360_BD_SHORT |
485                                M360_BD_CRC_ERROR |
486                                M360_BD_OVERRUN |
487                                M360_BD_COLLISION)) ==
488                                                (M360_BD_LAST |
489                                                M360_BD_FIRST_IN_FRAME)) {
490                        /*
491                         * Pass the packet up the chain.
492                         * FIXME: Packet filtering hook could be done here.
493                         */
494                        struct ether_header *eh;
495
496                        m = sc->rxMbuf[rxBdIndex];
497                        m->m_len = m->m_pkthdr.len = rxBd->length -
498                                                sizeof(rtems_unsigned32) -
499                                                sizeof(struct ether_header);
500                        eh = mtod (m, struct ether_header *);
501                        m->m_data += sizeof(struct ether_header);
502                        ether_input (ifp, eh, m);
503
504                        /*
505                         * Allocate a new mbuf
506                         */
507                        MGETHDR (m, M_WAIT, MT_DATA);
508                        MCLGET (m, M_WAIT);
509                        m->m_pkthdr.rcvif = ifp;
510                        sc->rxMbuf[rxBdIndex] = m;
511                        rxBd->buffer = mtod (m, void *);
512                }
513                else {
514                        /*
515                         * Something went wrong with the reception
516                         */
517                        if (!(status & M360_BD_LAST))
518                                sc->rxNotLast++;
519                        if (!(status & M360_BD_FIRST_IN_FRAME))
520                                sc->rxNotFirst++;
521                        if (status & M360_BD_LONG)
522                                sc->rxGiant++;
523                        if (status & M360_BD_NONALIGNED)
524                                sc->rxNonOctet++;
525                        if (status & M360_BD_SHORT)
526                                sc->rxRunt++;
527                        if (status & M360_BD_CRC_ERROR)
528                                sc->rxBadCRC++;
529                        if (status & M360_BD_OVERRUN)
530                                sc->rxOverrun++;
531                        if (status & M360_BD_COLLISION)
532                                sc->rxCollision++;
533                }
534
535                /*
536                 * Reenable the buffer descriptor
537                 */
538                rxBd->status = (status & (M360_BD_WRAP | M360_BD_INTERRUPT)) | M360_BD_EMPTY;
539
540                /*
541                 * Move to next buffer descriptor
542                 */
543                if (++rxBdIndex == sc->rxBdCount)
544                        rxBdIndex = 0;
545        }
546}
547
548static void
549sendpacket (struct ifnet *ifp, struct mbuf *m)
550{
551        struct scc_softc *sc = ifp->if_softc;
552        volatile m360BufferDescriptor_t *firstTxBd, *txBd;
553        struct mbuf *l = NULL;
554        rtems_unsigned16 status;
555        int nAdded;
556
557        /*
558         * Free up buffer descriptors
559         */
560        m360Enet_retire_tx_bd (sc);
561
562        /*
563         * Set up the transmit buffer descriptors.
564         * No need to pad out short packets since the
565         * hardware takes care of that automatically.
566         * No need to copy the packet to a contiguous buffer
567         * since the hardware is capable of scatter/gather DMA.
568         */
569        nAdded = 0;
570        txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
571        for (;;) {
572                /*
573                 * Wait for buffer descriptor to become available.
574                 */
575                if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
576                        /*
577                         * Clear old events
578                         */
579                        m360.scc1.scce = 0x12;
580
581                        /*
582                         * Wait for buffer descriptor to become available.
583                         * Note that the buffer descriptors are checked
584                         * *before* * entering the wait loop -- this catches
585                         * the possibility that a buffer descriptor became
586                         * available between the `if' above, and the clearing
587                         * of the event register.
588                         * This is to catch the case where the transmitter
589                         * stops in the middle of a frame -- and only the
590                         * last buffer descriptor in a frame can generate
591                         * an interrupt.
592                         */
593                        m360Enet_retire_tx_bd (sc);
594                        while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
595                                rtems_event_set events;
596
597                                /*
598                                 * Unmask TXB (buffer transmitted) and
599                                 * TXE (transmitter error) events.
600                                 */
601                                m360.scc1.sccm |= 0x12;
602                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
603                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
604                                                RTEMS_NO_TIMEOUT,
605                                                &events);
606                                m360Enet_retire_tx_bd (sc);
607                        }
608                }
609
610                /*
611                 * Don't set the READY flag till the
612                 * whole packet has been readied.
613                 */
614                status = nAdded ? M360_BD_READY : 0;
615
616                /*
617                 *  FIXME: Why not deal with empty mbufs at at higher level?
618                 * The IP fragmentation routine in ip_output
619                 * can produce packet fragments with zero length.
620                 * I think that ip_output should be changed to get
621                 * rid of these zero-length mbufs, but for now,
622                 * I'll deal with them here.
623                 */
624                if (m->m_len) {
625                        /*
626                         * Fill in the buffer descriptor
627                         */
628                        txBd->buffer = mtod (m, void *);
629                        txBd->length = m->m_len;
630                        sc->txMbuf[sc->txBdHead] = m;
631                        nAdded++;
632                        if (++sc->txBdHead == sc->txBdCount) {
633                                status |= M360_BD_WRAP;
634                                sc->txBdHead = 0;
635                        }
636                        l = m;
637                        m = m->m_next;
638                }
639                else {
640                        /*
641                         * Just toss empty mbufs
642                         */
643                        struct mbuf *n;
644                        MFREE (m, n);
645                        m = n;
646                        if (l != NULL)
647                                l->m_next = m;
648                }
649
650                /*
651                 * Set the transmit buffer status.
652                 * Break out of the loop if this mbuf is the last in the frame.
653                 */
654                if (m == NULL) {
655                        if (nAdded) {
656                                status |= M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;
657                                txBd->status = status;
658                                firstTxBd->status |= M360_BD_READY;
659                                sc->txBdActiveCount += nAdded;
660                        }
661                        break;
662                }
663                txBd->status = status;
664                txBd = sc->txBdBase + sc->txBdHead;
665        }
666}
667
668/*
669 * Driver transmit daemon
670 */
671void
672scc_txDaemon (void *arg)
673{
674        struct scc_softc *sc = (struct scc_softc *)arg;
675        struct ifnet *ifp = &sc->arpcom.ac_if;
676        struct mbuf *m;
677        rtems_event_set events;
678
679        for (;;) {
680                /*
681                 * Wait for packet
682                 */
683                rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
684
685                /*
686                 * Send packets till queue is empty
687                 */
688                for (;;) {
689                        /*
690                         * Get the next mbuf chain to transmit.
691                         */
692                        IF_DEQUEUE(&ifp->if_snd, m);
693                        if (!m)
694                                break;
695                        sendpacket (ifp, m);
696                }
697                ifp->if_flags &= ~IFF_OACTIVE;
698        }
699}
700
701/*
702 * Send packet (caller provides header).
703 */
704static void
705scc_start (struct ifnet *ifp)
706{
707        struct scc_softc *sc = ifp->if_softc;
708
709        rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
710        ifp->if_flags |= IFF_OACTIVE;
711}
712
713/*
714 * Initialize and start the device
715 */
716static void
717scc_init (void *arg)
718{
719        struct scc_softc *sc = arg;
720        struct ifnet *ifp = &sc->arpcom.ac_if;
721
722        if (sc->txDaemonTid == 0) {
723
724                /*
725                 * Set up SCC hardware
726                 */
727                m360Enet_initialize_hardware (sc);
728
729                /*
730                 * Start driver tasks
731                 */
732                sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
733                sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
734
735        }
736
737        /*
738         * Set flags appropriately
739         */
740        if (ifp->if_flags & IFF_PROMISC)
741                m360.scc1.psmr |= 0x200;
742        else
743                m360.scc1.psmr &= ~0x200;
744
745        /*
746         * Tell the world that we're running.
747         */
748        ifp->if_flags |= IFF_RUNNING;
749
750        /*
751         * Enable receiver and transmitter
752         */
753        m360.scc1.gsmr_l |= 0x30;
754}
755
756/*
757 * Stop the device
758 */
759static void
760scc_stop (struct scc_softc *sc)
761{
762        struct ifnet *ifp = &sc->arpcom.ac_if;
763
764        ifp->if_flags &= ~IFF_RUNNING;
765
766        /*
767         * Shut down receiver and transmitter
768         */
769        m360.scc1.gsmr_l &= ~0x30;
770}
771
772
773/*
774 * Show interface statistics
775 */
776static void
777scc_stats (struct scc_softc *sc)
778{
779        printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
780        printf ("       Not First:%-8lu", sc->rxNotFirst);
781        printf ("        Not Last:%-8lu\n", sc->rxNotLast);
782        printf ("              Giant:%-8lu", sc->rxGiant);
783        printf ("            Runt:%-8lu", sc->rxRunt);
784        printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
785        printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
786        printf ("         Overrun:%-8lu", sc->rxOverrun);
787        printf ("       Collision:%-8lu\n", sc->rxCollision);
788        printf ("          Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
789
790        printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
791        printf ("        Deferred:%-8lu", sc->txDeferred);
792        printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
793        printf ("         No Carrier:%-8lu", sc->txLostCarrier);
794        printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
795        printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
796        printf ("           Underrun:%-8lu", sc->txUnderrun);
797        printf (" Raw output wait:%-8lu\n", sc->txRawWait);
798}
799
800/*
801 * Driver ioctl handler
802 */
803static int
804scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
805{
806        struct scc_softc *sc = ifp->if_softc;
807        int error = 0;
808
809        switch (command) {
810        case SIOCGIFADDR:
811        case SIOCSIFADDR:
812                ether_ioctl (ifp, command, data);
813                break;
814
815        case SIOCSIFFLAGS:
816                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
817                case IFF_RUNNING:
818                        scc_stop (sc);
819                        break;
820
821                case IFF_UP:
822                        scc_init (sc);
823                        break;
824
825                case IFF_UP | IFF_RUNNING:
826                        scc_stop (sc);
827                        scc_init (sc);
828                        break;
829
830                default:
831                        break;
832                }
833                break;
834
835        case SIO_RTEMS_SHOW_STATS:
836                scc_stats (sc);
837                break;
838               
839        /*
840         * FIXME: All sorts of multicast commands need to be added here!
841         */
842        default:
843                error = EINVAL;
844                break;
845        }
846        return error;
847}
848
849/*
850 * Attach an SCC driver to the system
851 */
852int
853rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config)
854{
855        struct scc_softc *sc;
856        struct ifnet *ifp;
857        int mtu;
858        int i;
859
860        /*
861         * Find a free driver
862         */
863        for (i = 0 ; i < NSCCDRIVER ; i++) {
864                sc = &scc_softc[i];
865                ifp = &sc->arpcom.ac_if;
866                if (ifp->if_softc == NULL)
867                        break;
868        }
869        if (i >= NSCCDRIVER) {
870                printf ("Too many SCC drivers.\n");
871                return 0;
872        }
873
874        /*
875         * Process options
876         */
877        if (config->hardware_address) {
878                memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
879        }
880        else {
881                /*
882                 * The first 4 bytes of the bootstrap prom
883                 * contain the value loaded into the stack
884                 * pointer as part of the CPU32's hardware
885                 * reset exception handler.  The following
886                 * 4 bytes contain the value loaded into the
887                 * program counter.  The boards' Ethernet
888                 * address is stored in the six bytes
889                 * immediately preceding this initial
890                 * program counter value.
891                 *
892                 * See start360/start360.s.
893                 */
894                extern void *_RomBase;  /* From linkcmds */
895                const unsigned long *ExceptionVectors;
896                const unsigned char *entryPoint;
897
898                /*
899                 * Sanity check -- assume entry point must be
900                 * within 1 MByte of beginning of boot ROM.
901                 */
902                ExceptionVectors = (const unsigned long *)&_RomBase;
903                entryPoint = (const unsigned char *)ExceptionVectors[1];
904                if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
905                                        >= (1 * 1024 * 1024)) {
906                        printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
907                        sc->arpcom.ac_enaddr[0] = 0x08;
908                        sc->arpcom.ac_enaddr[1] = 0xF3;
909                        sc->arpcom.ac_enaddr[2] = 0x3E;
910                        sc->arpcom.ac_enaddr[3] = 0xC2;
911                        sc->arpcom.ac_enaddr[4] = 0x7E;
912                        sc->arpcom.ac_enaddr[5] = 0x38;
913                }
914                else {
915                        memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, ETHER_ADDR_LEN);
916                }
917        }
918        if (config->mtu)
919                mtu = config->mtu;
920        else
921                mtu = ETHERMTU;
922        if (config->rbuf_count)
923                sc->rxBdCount = config->rbuf_count;
924        else
925                sc->rxBdCount = RX_BUF_COUNT;
926        if (config->xbuf_count)
927                sc->txBdCount = config->xbuf_count;
928        else
929                sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
930        sc->acceptBroadcast = !config->ignore_broadcast;
931
932        /*
933         * Set up network interface values
934         */
935        ifp->if_softc = sc;
936        ifp->if_unit = i + 1;
937        ifp->if_name = "scc";
938        ifp->if_mtu = mtu;
939        ifp->if_init = scc_init;
940        ifp->if_ioctl = scc_ioctl;
941        ifp->if_start = scc_start;
942        ifp->if_output = ether_output;
943        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
944        if (ifp->if_snd.ifq_maxlen == 0)
945                ifp->if_snd.ifq_maxlen = ifqmaxlen;
946
947        /*
948         * Attach the interface
949         */
950        if_attach (ifp);
951        ether_ifattach (ifp);
952        return 1;
953};
Note: See TracBrowser for help on using the repository browser.