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

4.104.114.84.95
Last change on this file since 424f3027 was 424f3027, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/03/04 at 08:45:30

2004-04-03 Ralf Corsepiu <ralf_corsepiu@…>

  • c/src/lib/libbsp/m68k/gen68360/clock/clock.c, c/src/lib/libbsp/m68k/gen68360/console/console.c, c/src/lib/libbsp/m68k/gen68360/console/consolereserveresources.c, c/src/lib/libbsp/m68k/gen68360/network/network.c, c/src/lib/libbsp/m68k/gen68360/startup/alloc360.c, c/src/lib/libbsp/m68k/gen68360/startup/init68360.c, c/src/lib/libbsp/m68k/gen68360/timer/timer.c: Include <rtems/m68k/m68360.h> instead of <m68360.h>.
  • Property mode set to 100644
File size: 23.6 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 <rtems/m68k/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        uint16_t         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        uint16_t         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(uint32_t) -
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        uint16_t         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, int attaching)
946{
947        struct scc_softc *sc;
948        struct ifnet *ifp;
949        int mtu;
950        int unitNumber;
951        char *unitName;
952
953        /*
954         * Make sure we're really being attached
955         */
956        if (!attaching) {
957                printf ("SCC1 driver can not be detached.\n");
958                return 0;
959        }
960               
961        /*
962         * Parse driver name
963         */
964        if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
965                return 0;
966       
967        /*
968         * Is driver free?
969         */
970        if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
971                printf ("Bad SCC unit number.\n");
972                return 0;
973        }
974        sc = &scc_softc[unitNumber - 1];
975        ifp = &sc->arpcom.ac_if;
976        if (ifp->if_softc != NULL) {
977                printf ("Driver already in use.\n");
978                return 0;
979        }
980
981        /*
982         * Process options
983         */
984        if (config->hardware_address) {
985                memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
986        }
987        else {
988                /*
989                 * The first 4 bytes of the bootstrap prom
990                 * contain the value loaded into the stack
991                 * pointer as part of the CPU32's hardware
992                 * reset exception handler.  The following
993                 * 4 bytes contain the value loaded into the
994                 * program counter.  The boards' Ethernet
995                 * address is stored in the six bytes
996                 * immediately preceding this initial
997                 * program counter value.
998                 *
999                 * See start360/start360.s.
1000                 */
1001                extern void *_RomBase;  /* From linkcmds */
1002                const unsigned long *ExceptionVectors;
1003                const unsigned char *entryPoint;
1004
1005                /*
1006                 * Sanity check -- assume entry point must be
1007                 * within 1 MByte of beginning of boot ROM.
1008                 */
1009                ExceptionVectors = (const unsigned long *)&_RomBase;
1010                entryPoint = (const unsigned char *)ExceptionVectors[1];
1011                if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
1012                                        >= (1 * 1024 * 1024)) {
1013                        printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
1014                        sc->arpcom.ac_enaddr[0] = 0x08;
1015                        sc->arpcom.ac_enaddr[1] = 0xF3;
1016                        sc->arpcom.ac_enaddr[2] = 0x3E;
1017                        sc->arpcom.ac_enaddr[3] = 0xC2;
1018                        sc->arpcom.ac_enaddr[4] = 0x7E;
1019                        sc->arpcom.ac_enaddr[5] = 0x38;
1020                }
1021                else {
1022                        memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, ETHER_ADDR_LEN);
1023                }
1024        }
1025        if (config->mtu)
1026                mtu = config->mtu;
1027        else
1028                mtu = ETHERMTU;
1029        if (config->rbuf_count)
1030                sc->rxBdCount = config->rbuf_count;
1031        else
1032                sc->rxBdCount = RX_BUF_COUNT;
1033        if (config->xbuf_count)
1034                sc->txBdCount = config->xbuf_count;
1035        else
1036                sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1037        sc->acceptBroadcast = !config->ignore_broadcast;
1038
1039        /*
1040         * Set up network interface values
1041         */
1042        ifp->if_softc = sc;
1043        ifp->if_unit = unitNumber;
1044        ifp->if_name = unitName;
1045        ifp->if_mtu = mtu;
1046        ifp->if_init = scc_init;
1047        ifp->if_ioctl = scc_ioctl;
1048        ifp->if_start = scc_start;
1049        ifp->if_output = ether_output;
1050        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1051        if (ifp->if_snd.ifq_maxlen == 0)
1052                ifp->if_snd.ifq_maxlen = ifqmaxlen;
1053
1054        /*
1055         * Attach the interface
1056         */
1057        if_attach (ifp);
1058        ether_ifattach (ifp);
1059        return 1;
1060}
Note: See TracBrowser for help on using the repository browser.