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

Last change on this file since 15093362 was 15093362, checked in by Joel Sherrill <joel.sherrill@…>, on 02/18/00 at 13:53:06

Patch from Eric Norum <eric@…> to address these issues:

1) Coalesce outgoing packet into a single mbuf when the packet is spread

over more mbufs than configured transmit buffer descriptors.

2) Add dianostic counters for successful and failed coalesce attempts.
3) Add diagnostic counter for transmit retries.

NOTE: (1) lead to deadlock and the same design based on underlying
hardware characteristics is currently also in the Sonic and
i386ex/network driver.

  • Property mode set to 100644
File size: 23.5 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 <stdio.h>
15#include <rtems/error.h>
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>
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 */
38#define RX_BUF_COUNT     15
39#define TX_BUF_COUNT     4
40#define TX_BD_PER_BUF    4
41
42/*
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.
45 */
46#define INTERRUPT_EVENT RTEMS_EVENT_1
47
48/*
49 * RTEMS event used to start transmit daemon.
50 * This must not be the same as INTERRUPT_EVENT.
51 */
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
62
63/*
64 * Per-device data
65 */
66struct scc_softc {
67        struct arpcom           arpcom;
68        struct mbuf             **rxMbuf;
69        struct mbuf             **txMbuf;
70        int                     acceptBroadcast;
71        int                     rxBdCount;
72        int                     txBdCount;
73        int                     txBdHead;
74        int                     txBdTail;
75        int                     txBdActiveCount;
76        m360BufferDescriptor_t  *rxBdBase;
77        m360BufferDescriptor_t  *txBdBase;
78        rtems_id                rxDaemonTid;
79        rtems_id                txDaemonTid;
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        unsigned long   txCoalesced;
103        unsigned long   txCoalesceFailed;
104        unsigned long   txRetry;
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        int retries = 0;
351        int saveStatus = 0;
352
353        i = sc->txBdTail;
354        nRetired = 0;
355        while ((sc->txBdActiveCount != 0)
356           &&  (((status = (sc->txBdBase + i)->status) & M360_BD_READY) == 0)) {
357                /*
358                 * Check for errors which stop the transmitter.
359                 */
360                if (status & (M360_BD_LATE_COLLISION |
361                                M360_BD_RETRY_LIMIT |
362                                M360_BD_UNDERRUN)) {
363                        int j;
364
365                        if (status & M360_BD_LATE_COLLISION)
366                                sc->txLateCollision++;
367                        if (status & M360_BD_RETRY_LIMIT)
368                                sc->txRetryLimit++;
369                        if (status & M360_BD_UNDERRUN)
370                                sc->txUnderrun++;
371
372                        /*
373                         * Reenable buffer descriptors
374                         */
375                        j = sc->txBdTail;
376                        for (;;) {
377                                status = (sc->txBdBase + j)->status;
378                                if (status & M360_BD_READY)
379                                        break;
380                                (sc->txBdBase + j)->status = M360_BD_READY |
381                                        (status & (M360_BD_PAD |
382                                                   M360_BD_WRAP |
383                                                   M360_BD_INTERRUPT |
384                                                   M360_BD_LAST |
385                                                   M360_BD_TX_CRC));
386                                if (status & M360_BD_LAST)
387                                        break;
388                                if (++j == sc->txBdCount)
389                                        j = 0;
390                        }
391
392                        /*
393                         * Move transmitter back to the first
394                         * buffer descriptor in the frame.
395                         */
396                        m360.scc1p._tbptr = m360.scc1p.tbase +
397                                sc->txBdTail * sizeof (m360BufferDescriptor_t);
398
399                        /*
400                         * Restart the transmitter
401                         */
402                        M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);
403                        continue;
404                }
405                saveStatus |= status;
406                retries += (status >> 2) & 0xF;
407                nRetired++;
408                if (status & M360_BD_LAST) {
409                        /*
410                         * A full frame has been transmitted.
411                         * Free all the associated buffer descriptors.
412                         */
413                        if (saveStatus & M360_BD_DEFER)
414                                sc->txDeferred++;
415                        if (saveStatus & M360_BD_HEARTBEAT)
416                                sc->txHeartbeat++;
417                        if (saveStatus & M360_BD_CARRIER_LOST)
418                                sc->txLostCarrier++;
419                        saveStatus = 0;
420                        sc->txRetry += retries;
421                        retries = 0;
422                        sc->txBdActiveCount -= nRetired;
423                        while (nRetired) {
424                                nRetired--;
425                                m = sc->txMbuf[sc->txBdTail];
426                                MFREE (m, n);
427                                if (++sc->txBdTail == sc->txBdCount)
428                                        sc->txBdTail = 0;
429                        }
430                }
431                if (++i == sc->txBdCount)
432                        i = 0;
433        }
434}
435
436/*
437 * SCC reader task
438 */
439static void
440scc_rxDaemon (void *arg)
441{
442        struct scc_softc *sc = (struct scc_softc *)arg;
443        struct ifnet *ifp = &sc->arpcom.ac_if;
444        struct mbuf *m;
445        rtems_unsigned16 status;
446        volatile m360BufferDescriptor_t *rxBd;
447        int rxBdIndex;
448
449        /*
450         * Allocate space for incoming packets and start reception
451         */
452        for (rxBdIndex = 0 ; ;) {
453                rxBd = sc->rxBdBase + rxBdIndex;
454                MGETHDR (m, M_WAIT, MT_DATA);
455                MCLGET (m, M_WAIT);
456                m->m_pkthdr.rcvif = ifp;
457                sc->rxMbuf[rxBdIndex] = m;
458                rxBd->buffer = mtod (m, void *);
459                if (++rxBdIndex == sc->rxBdCount) {
460                        rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT | M360_BD_WRAP;
461                        break;
462                }
463                rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT;
464        }
465
466        /*
467         * Input packet handling loop
468         */
469        rxBdIndex = 0;
470        for (;;) {
471                rxBd = sc->rxBdBase + rxBdIndex;
472
473                /*
474                 * Wait for packet if there's not one ready
475                 */
476                if ((status = rxBd->status) & M360_BD_EMPTY) {
477                        /*
478                         * Clear old events
479                         */
480                        m360.scc1.scce = 0x8;
481
482                        /*
483                         * Wait for packet
484                         * Note that the buffer descriptor is checked
485                         * *before* the event wait -- this catches the
486                         * possibility that a packet arrived between the
487                         * `if' above, and the clearing of the event register.
488                         */
489                        while ((status = rxBd->status) & M360_BD_EMPTY) {
490                                rtems_interrupt_level level;
491                                rtems_event_set events;
492
493                                /*
494                                 * Unmask RXF (Full frame received) event
495                                 */
496                                rtems_interrupt_disable (level);
497                                m360.scc1.sccm |= 0x8;
498                                rtems_interrupt_enable (level);
499
500                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
501                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
502                                                RTEMS_NO_TIMEOUT,
503                                                &events);
504                        }
505                }
506
507                /*
508                 * Check that packet is valid
509                 */
510                if ((status & (M360_BD_LAST |
511                                M360_BD_FIRST_IN_FRAME |
512                                M360_BD_LONG |
513                                M360_BD_NONALIGNED |
514                                M360_BD_SHORT |
515                                M360_BD_CRC_ERROR |
516                                M360_BD_OVERRUN |
517                                M360_BD_COLLISION)) ==
518                                                (M360_BD_LAST |
519                                                M360_BD_FIRST_IN_FRAME)) {
520                        /*
521                         * Pass the packet up the chain.
522                         * FIXME: Packet filtering hook could be done here.
523                         */
524                        struct ether_header *eh;
525
526                        m = sc->rxMbuf[rxBdIndex];
527                        m->m_len = m->m_pkthdr.len = rxBd->length -
528                                                sizeof(rtems_unsigned32) -
529                                                sizeof(struct ether_header);
530                        eh = mtod (m, struct ether_header *);
531                        m->m_data += sizeof(struct ether_header);
532                        ether_input (ifp, eh, m);
533
534                        /*
535                         * Allocate a new mbuf
536                         */
537                        MGETHDR (m, M_WAIT, MT_DATA);
538                        MCLGET (m, M_WAIT);
539                        m->m_pkthdr.rcvif = ifp;
540                        sc->rxMbuf[rxBdIndex] = m;
541                        rxBd->buffer = mtod (m, void *);
542                }
543                else {
544                        /*
545                         * Something went wrong with the reception
546                         */
547                        if (!(status & M360_BD_LAST))
548                                sc->rxNotLast++;
549                        if (!(status & M360_BD_FIRST_IN_FRAME))
550                                sc->rxNotFirst++;
551                        if (status & M360_BD_LONG)
552                                sc->rxGiant++;
553                        if (status & M360_BD_NONALIGNED)
554                                sc->rxNonOctet++;
555                        if (status & M360_BD_SHORT)
556                                sc->rxRunt++;
557                        if (status & M360_BD_CRC_ERROR)
558                                sc->rxBadCRC++;
559                        if (status & M360_BD_OVERRUN)
560                                sc->rxOverrun++;
561                        if (status & M360_BD_COLLISION)
562                                sc->rxCollision++;
563                }
564
565                /*
566                 * Reenable the buffer descriptor
567                 */
568                rxBd->status = (status & (M360_BD_WRAP | M360_BD_INTERRUPT)) | M360_BD_EMPTY;
569
570                /*
571                 * Move to next buffer descriptor
572                 */
573                if (++rxBdIndex == sc->rxBdCount)
574                        rxBdIndex = 0;
575        }
576}
577
578static void
579sendpacket (struct ifnet *ifp, struct mbuf *m)
580{
581        struct scc_softc *sc = ifp->if_softc;
582        volatile m360BufferDescriptor_t *firstTxBd, *txBd;
583        struct mbuf *l = NULL;
584        rtems_unsigned16 status;
585        int nAdded;
586
587        /*
588         * Free up buffer descriptors
589         */
590        m360Enet_retire_tx_bd (sc);
591
592        /*
593         * Set up the transmit buffer descriptors.
594         * No need to pad out short packets since the
595         * hardware takes care of that automatically.
596         * No need to copy the packet to a contiguous buffer
597         * since the hardware is capable of scatter/gather DMA.
598         */
599        status = 0;
600        nAdded = 0;
601        txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
602        while (m) {
603                /*
604                 * There are more mbufs in the packet than there
605                 * are transmit buffer descriptors.
606                 * Coalesce into a single buffer.
607                 */
608                if (nAdded == sc->txBdCount) {
609                        struct mbuf *nm;
610                        int j;
611                        char *dest;
612
613                        /*
614                         * Get the pointer to the first mbuf of the packet
615                         */
616                        if (sc->txBdTail != sc->txBdHead)
617                                rtems_panic ("sendpacket coalesce");
618                        m = sc->txMbuf[sc->txBdTail];
619
620                        /*
621                         * Rescind the buffer descriptor READY bits
622                         */
623                        for (j = 0 ; j < sc->txBdCount ; j++)
624                                (sc->txBdBase + j)->status = 0;
625
626                        /*
627                         * Allocate an mbuf cluster
628                         * Toss the packet if allocation fails
629                         */
630                        MGETHDR (nm, M_DONTWAIT, MT_DATA);
631                        if (nm == NULL) {
632                                sc->txCoalesceFailed++;
633                                m_freem (m);
634                                return;
635                        }
636                        MCLGET (nm, M_DONTWAIT);
637                        if (nm->m_ext.ext_buf == NULL) {
638                                sc->txCoalesceFailed++;
639                                m_freem (m);
640                                m_free (nm);
641                                return;
642                        }
643                        nm->m_pkthdr = m->m_pkthdr;
644                        nm->m_len = nm->m_pkthdr.len;
645
646                        /*
647                         * Copy data from packet chain to mbuf cluster
648                         */
649                        sc->txCoalesced++;
650                        dest = nm->m_ext.ext_buf;
651                        while (m) {
652                                struct mbuf *n;
653
654                                if (m->m_len) {
655                                        memcpy (dest, mtod(m, caddr_t), m->m_len);
656                                        dest += m->m_len;
657                                }
658                                MFREE (m, n);
659                                m = n;
660                        }
661                       
662                        /*
663                         * Redo the send with the new mbuf cluster
664                         */
665                        m = nm;
666                        nAdded = 0;
667                        status = 0;
668                        continue;
669                }
670
671                /*
672                 * Wait for buffer descriptor to become available.
673                 */
674                if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
675                        /*
676                         * Clear old events
677                         */
678                        m360.scc1.scce = 0x12;
679
680                        /*
681                         * Wait for buffer descriptor to become available.
682                         * Note that the buffer descriptors are checked
683                         * *before* entering the wait loop -- this catches
684                         * the possibility that a buffer descriptor became
685                         * available between the `if' above, and the clearing
686                         * of the event register.
687                         * This is to catch the case where the transmitter
688                         * stops in the middle of a frame -- and only the
689                         * last buffer descriptor in a frame can generate
690                         * an interrupt.
691                         */
692                        m360Enet_retire_tx_bd (sc);
693                        while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
694                                rtems_interrupt_level level;
695                                rtems_event_set events;
696
697                                /*
698                                 * Unmask TXB (buffer transmitted) and
699                                 * TXE (transmitter error) events.
700                                 */
701                                rtems_interrupt_disable (level);
702                                m360.scc1.sccm |= 0x12;
703                                rtems_interrupt_enable (level);
704                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
705                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
706                                                RTEMS_NO_TIMEOUT,
707                                                &events);
708                                m360Enet_retire_tx_bd (sc);
709                        }
710                }
711
712                /*
713                 * The IP fragmentation routine in ip_output
714                 * can produce packet fragments with zero length.
715                 */
716                if (m->m_len) {
717                        /*
718                         * Fill in the buffer descriptor.
719                         * Don't set the READY flag in the first buffer
720                         * descriptor till the whole packet has been readied.
721                         */
722                        txBd = sc->txBdBase + sc->txBdHead;
723                        txBd->buffer = mtod (m, void *);
724                        txBd->length = m->m_len;
725                        sc->txMbuf[sc->txBdHead] = m;
726                        status = nAdded ? M360_BD_READY : 0;
727                        if (++sc->txBdHead == sc->txBdCount) {
728                                status |= M360_BD_WRAP;
729                                sc->txBdHead = 0;
730                        }
731                        txBd->status = status;
732                        l = m;
733                        m = m->m_next;
734                        nAdded++;
735                }
736                else {
737                        /*
738                         * Just toss empty mbufs
739                         */
740                        struct mbuf *n;
741                        MFREE (m, n);
742                        m = n;
743                        if (l != NULL)
744                                l->m_next = m;
745                }
746        }
747        if (nAdded) {
748                /*
749                 * Send the packet
750                 */
751                txBd->status = status | M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;
752                firstTxBd->status |= M360_BD_READY;
753                sc->txBdActiveCount += nAdded;
754        }
755}
756
757/*
758 * Driver transmit daemon
759 */
760void
761scc_txDaemon (void *arg)
762{
763        struct scc_softc *sc = (struct scc_softc *)arg;
764        struct ifnet *ifp = &sc->arpcom.ac_if;
765        struct mbuf *m;
766        rtems_event_set events;
767
768        for (;;) {
769                /*
770                 * Wait for packet
771                 */
772                rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
773
774                /*
775                 * Send packets till queue is empty
776                 */
777                for (;;) {
778                        /*
779                         * Get the next mbuf chain to transmit.
780                         */
781                        IF_DEQUEUE(&ifp->if_snd, m);
782                        if (!m)
783                                break;
784                        sendpacket (ifp, m);
785                }
786                ifp->if_flags &= ~IFF_OACTIVE;
787        }
788}
789
790/*
791 * Send packet (caller provides header).
792 */
793static void
794scc_start (struct ifnet *ifp)
795{
796        struct scc_softc *sc = ifp->if_softc;
797
798        rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
799        ifp->if_flags |= IFF_OACTIVE;
800}
801
802/*
803 * Initialize and start the device
804 */
805static void
806scc_init (void *arg)
807{
808        struct scc_softc *sc = arg;
809        struct ifnet *ifp = &sc->arpcom.ac_if;
810
811        if (sc->txDaemonTid == 0) {
812
813                /*
814                 * Set up SCC hardware
815                 */
816                m360Enet_initialize_hardware (sc);
817
818                /*
819                 * Start driver tasks
820                 */
821                sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
822                sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
823
824        }
825
826        /*
827         * Set flags appropriately
828         */
829        if (ifp->if_flags & IFF_PROMISC)
830                m360.scc1.psmr |= 0x200;
831        else
832                m360.scc1.psmr &= ~0x200;
833
834        /*
835         * Tell the world that we're running.
836         */
837        ifp->if_flags |= IFF_RUNNING;
838
839        /*
840         * Enable receiver and transmitter
841         */
842        m360.scc1.gsmr_l |= 0x30;
843}
844
845/*
846 * Stop the device
847 */
848static void
849scc_stop (struct scc_softc *sc)
850{
851        struct ifnet *ifp = &sc->arpcom.ac_if;
852
853        ifp->if_flags &= ~IFF_RUNNING;
854
855        /*
856         * Shut down receiver and transmitter
857         */
858        m360.scc1.gsmr_l &= ~0x30;
859}
860
861
862/*
863 * Show interface statistics
864 */
865static void
866scc_stats (struct scc_softc *sc)
867{
868        printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
869        printf ("       Not First:%-8lu", sc->rxNotFirst);
870        printf ("        Not Last:%-8lu\n", sc->rxNotLast);
871        printf ("              Giant:%-8lu", sc->rxGiant);
872        printf ("            Runt:%-8lu", sc->rxRunt);
873        printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
874        printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
875        printf ("         Overrun:%-8lu", sc->rxOverrun);
876        printf ("       Collision:%-8lu\n", sc->rxCollision);
877        printf ("          Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
878
879        printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
880        printf ("        Deferred:%-8lu", sc->txDeferred);
881        printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
882        printf ("         No Carrier:%-8lu", sc->txLostCarrier);
883        printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
884        printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
885        printf ("           Underrun:%-8lu", sc->txUnderrun);
886        printf (" Raw output wait:%-8lu", sc->txRawWait);
887        printf ("       Coalesced:%-8lu\n", sc->txCoalesced);
888        printf ("    Coalesce failed:%-8lu", sc->txCoalesceFailed);
889        printf ("         Retries:%-8lu\n", sc->txRetry);
890}
891
892/*
893 * Driver ioctl handler
894 */
895static int
896scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
897{
898        struct scc_softc *sc = ifp->if_softc;
899        int error = 0;
900
901        switch (command) {
902        case SIOCGIFADDR:
903        case SIOCSIFADDR:
904                ether_ioctl (ifp, command, data);
905                break;
906
907        case SIOCSIFFLAGS:
908                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
909                case IFF_RUNNING:
910                        scc_stop (sc);
911                        break;
912
913                case IFF_UP:
914                        scc_init (sc);
915                        break;
916
917                case IFF_UP | IFF_RUNNING:
918                        scc_stop (sc);
919                        scc_init (sc);
920                        break;
921
922                default:
923                        break;
924                }
925                break;
926
927        case SIO_RTEMS_SHOW_STATS:
928                scc_stats (sc);
929                break;
930               
931        /*
932         * FIXME: All sorts of multicast commands need to be added here!
933         */
934        default:
935                error = EINVAL;
936                break;
937        }
938        return error;
939}
940
941/*
942 * Attach an SCC driver to the system
943 */
944int
945rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config)
946{
947        struct scc_softc *sc;
948        struct ifnet *ifp;
949        int mtu;
950        int unitNumber;
951        char *unitName;
952
953        /*
954         * Parse driver name
955         */
956        if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
957                return 0;
958       
959        /*
960         * Is driver free?
961         */
962        if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
963                printf ("Bad SCC unit number.\n");
964                return 0;
965        }
966        sc = &scc_softc[unitNumber - 1];
967        ifp = &sc->arpcom.ac_if;
968        if (ifp->if_softc != NULL) {
969                printf ("Driver already in use.\n");
970                return 0;
971        }
972
973        /*
974         * Process options
975         */
976        if (config->hardware_address) {
977                memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
978        }
979        else {
980                /*
981                 * The first 4 bytes of the bootstrap prom
982                 * contain the value loaded into the stack
983                 * pointer as part of the CPU32's hardware
984                 * reset exception handler.  The following
985                 * 4 bytes contain the value loaded into the
986                 * program counter.  The boards' Ethernet
987                 * address is stored in the six bytes
988                 * immediately preceding this initial
989                 * program counter value.
990                 *
991                 * See start360/start360.s.
992                 */
993                extern void *_RomBase;  /* From linkcmds */
994                const unsigned long *ExceptionVectors;
995                const unsigned char *entryPoint;
996
997                /*
998                 * Sanity check -- assume entry point must be
999                 * within 1 MByte of beginning of boot ROM.
1000                 */
1001                ExceptionVectors = (const unsigned long *)&_RomBase;
1002                entryPoint = (const unsigned char *)ExceptionVectors[1];
1003                if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
1004                                        >= (1 * 1024 * 1024)) {
1005                        printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
1006                        sc->arpcom.ac_enaddr[0] = 0x08;
1007                        sc->arpcom.ac_enaddr[1] = 0xF3;
1008                        sc->arpcom.ac_enaddr[2] = 0x3E;
1009                        sc->arpcom.ac_enaddr[3] = 0xC2;
1010                        sc->arpcom.ac_enaddr[4] = 0x7E;
1011                        sc->arpcom.ac_enaddr[5] = 0x38;
1012                }
1013                else {
1014                        memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, ETHER_ADDR_LEN);
1015                }
1016        }
1017        if (config->mtu)
1018                mtu = config->mtu;
1019        else
1020                mtu = ETHERMTU;
1021        if (config->rbuf_count)
1022                sc->rxBdCount = config->rbuf_count;
1023        else
1024                sc->rxBdCount = RX_BUF_COUNT;
1025        if (config->xbuf_count)
1026                sc->txBdCount = config->xbuf_count;
1027        else
1028                sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1029        sc->acceptBroadcast = !config->ignore_broadcast;
1030
1031        /*
1032         * Set up network interface values
1033         */
1034        ifp->if_softc = sc;
1035        ifp->if_unit = unitNumber;
1036        ifp->if_name = unitName;
1037        ifp->if_mtu = mtu;
1038        ifp->if_init = scc_init;
1039        ifp->if_ioctl = scc_ioctl;
1040        ifp->if_start = scc_start;
1041        ifp->if_output = ether_output;
1042        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1043        if (ifp->if_snd.ifq_maxlen == 0)
1044                ifp->if_snd.ifq_maxlen = ifqmaxlen;
1045
1046        /*
1047         * Attach the interface
1048         */
1049        if_attach (ifp);
1050        ether_ifattach (ifp);
1051        return 1;
1052};
Note: See TracBrowser for help on using the repository browser.