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

4.104.114.84.95
Last change on this file since 9a95524f was 9a95524f, checked in by Joel Sherrill <joel.sherrill@…>, on 08/24/98 at 14:47:19

Cleanup patch from Eric Norum.

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