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

4.104.114.84.95
Last change on this file since 35ece2e was 35ece2e, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 11, 2000 at 3:21:40 PM

Patch from Eric Norum <eric@…> based on working with
Bob Wisdon <bobwis@…> and Chris Johns <ccj@…>
to resolve a random network lockup problem.

ckinit.c:

Occasional network lockups have been noted when the PIT has a higher
interrupt request level than the CPM. The SCC1 bit in the CISR is set
even though the SCC1 interrupt handler is not active. This blocks
interrupts from SCC1 (and all other CPM sources) and locks up the
system. It has not been determined whether the error is within the
68360 or in the RTEMS interrupt support assembler code. The solution,
for now, is to set both PIT and CPM interrupt request levels to the same
value (4).

network.c:

Set CPM transmitter buffer pointer (_tbptr) to beginning of frame
before restarting transmitter. Don't retire transmitter buffer
descriptors belonging to the restarted frame.

  • Property mode set to 100644
File size: 22.0 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};
103static struct scc_softc scc_softc[NSCCDRIVER];
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;
116                m360.scc1.sccm &= ~0x8;
117                scc_softc[0].rxInterrupts++;
118                rtems_event_send (scc_softc[0].rxDaemonTid, INTERRUPT_EVENT);
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;
126                m360.scc1.sccm &= ~0x12;
127                scc_softc[0].txInterrupts++;
128                rtems_event_send (scc_softc[0].txDaemonTid, INTERRUPT_EVENT);
129        }
130        m360.cisr = 1UL << 30;  /* Clear SCC1 interrupt-in-service bit */
131}
132
133/*
134 * Initialize the ethernet hardware
135 */
136static void
137m360Enet_initialize_hardware (struct scc_softc *sc)
138{
139        int i;
140        unsigned char *hwaddr;
141        rtems_status_code status;
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         */
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");
171
172        /*
173         * Set receiver and transmitter buffer descriptor bases
174         */
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;
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         */
194        m360.scc1p.mrblr = RBUF_SIZE;
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;
224        m360.scc1p.un.ethernet.maxd1 = RBUF_SIZE;
225        m360.scc1p.un.ethernet.maxd2 = RBUF_SIZE;
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         */
238        hwaddr = sc->arpcom.ac_enaddr;
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         */
259        for (i = 0 ; i < sc->rxBdCount ; i++)
260                (sc->rxBdBase + i)->status = 0;
261
262        /*
263         * Set up transmit buffer descriptors
264         */
265        for (i = 0 ; i < sc->txBdCount ; i++) {
266                (sc->txBdBase + i)->status = 0;
267                sc->txMbuf[i] = NULL;
268        }
269        sc->txBdHead = sc->txBdTail = 0;
270        sc->txBdActiveCount = 0;
271
272        /*
273         * Clear any outstanding events
274         */
275        m360.scc1.scce = 0xFFFF;
276
277        /*
278         * Set up interrupts
279         */
280        status = rtems_interrupt_catch (m360Enet_interrupt_handler,
281                                                (m360.cicr & 0xE0) | 0x1E,
282                                                &old_handler);
283        if (status != RTEMS_SUCCESSFUL)
284                rtems_panic ("Can't attach M360 SCC1 interrupt handler: %s\n",
285                                                rtems_status_text (status));
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         */
318        m360.scc1.psmr = 0x880A | (sc->acceptBroadcast ? 0 : 0x100);
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
341m360Enet_retire_tx_bd (struct scc_softc *sc)
342{
343        rtems_unsigned16 status;
344        int i;
345        int nRetired;
346        struct mbuf *m, *n;
347
348        i = sc->txBdTail;
349        nRetired = 0;
350        while ((sc->txBdActiveCount != 0)
351           &&  (((status = (sc->txBdBase + i)->status) & M360_BD_READY) == 0)) {
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                                int j;
368
369                                if (status & M360_BD_LATE_COLLISION)
370                                        scc_softc[0].txLateCollision++;
371                                if (status & M360_BD_RETRY_LIMIT)
372                                        scc_softc[0].txRetryLimit++;
373                                if (status & M360_BD_UNDERRUN)
374                                        scc_softc[0].txUnderrun++;
375
376                                /*
377                                 * Reenable buffer descriptors
378                                 */
379                                j = sc->txBdTail;
380                                for (;;) {
381                                        status = (sc->txBdBase + j)->status;
382                                        if (status & M360_BD_READY)
383                                                break;
384                                        (sc->txBdBase + j)->status = M360_BD_READY | 
385                                                (status & (M360_BD_PAD | 
386                                                           M360_BD_WRAP | 
387                                                           M360_BD_INTERRUPT | 
388                                                           M360_BD_LAST |
389                                                           M360_BD_TX_CRC));
390                                        if (status & M360_BD_LAST)
391                                                break;
392                                        if (++j == sc->txBdCount)
393                                                j = 0;
394                                }
395
396                                /*
397                                 * Move transmitter back to the first
398                                 * buffer descriptor in the frame.
399                                 */
400                                m360.scc1p._tbptr = m360.scc1p.tbase + 
401                                        sc->txBdTail * sizeof (m360BufferDescriptor_t);
402
403                                /*
404                                 * Restart the transmitter
405                                 */
406                                M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);
407                                continue;
408                        }
409                        if (status & M360_BD_DEFER)
410                                scc_softc[0].txDeferred++;
411                        if (status & M360_BD_HEARTBEAT)
412                                scc_softc[0].txHeartbeat++;
413                        if (status & M360_BD_CARRIER_LOST)
414                                scc_softc[0].txLostCarrier++;
415                }
416                nRetired++;
417                if (status & M360_BD_LAST) {
418                        /*
419                         * A full frame has been transmitted.
420                         * Free all the associated buffer descriptors.
421                         */
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                 * Wait for buffer descriptor to become available.
605                 */
606                if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
607                        /*
608                         * Clear old events
609                         */
610                        m360.scc1.scce = 0x12;
611
612                        /*
613                         * Wait for buffer descriptor to become available.
614                         * Note that the buffer descriptors are checked
615                         * *before* entering the wait loop -- this catches
616                         * the possibility that a buffer descriptor became
617                         * available between the `if' above, and the clearing
618                         * of the event register.
619                         * This is to catch the case where the transmitter
620                         * stops in the middle of a frame -- and only the
621                         * last buffer descriptor in a frame can generate
622                         * an interrupt.
623                         */
624                        m360Enet_retire_tx_bd (sc);
625                        while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
626                                rtems_interrupt_level level;
627                                rtems_event_set events;
628
629                                /*
630                                 * Unmask TXB (buffer transmitted) and
631                                 * TXE (transmitter error) events.
632                                 */
633                                rtems_interrupt_disable (level);
634                                m360.scc1.sccm |= 0x12;
635                                rtems_interrupt_enable (level);
636                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
637                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
638                                                RTEMS_NO_TIMEOUT,
639                                                &events);
640                                m360Enet_retire_tx_bd (sc);
641                        }
642                }
643
644                /*
645                 * The IP fragmentation routine in ip_output
646                 * can produce packet fragments with zero length.
647                 */
648                if (m->m_len) {
649                        /*
650                         * Fill in the buffer descriptor.
651                         * Don't set the READY flag in the first buffer
652                         * descriptor till the whole packet has been readied.
653                         */
654                        txBd = sc->txBdBase + sc->txBdHead;
655                        txBd->buffer = mtod (m, void *);
656                        txBd->length = m->m_len;
657                        sc->txMbuf[sc->txBdHead] = m;
658                        status = nAdded ? M360_BD_READY : 0;
659                        if (++sc->txBdHead == sc->txBdCount) {
660                                status |= M360_BD_WRAP;
661                                sc->txBdHead = 0;
662                        }
663                        txBd->status = status;
664                        l = m;
665                        m = m->m_next;
666                        nAdded++;
667                }
668                else {
669                        /*
670                         * Just toss empty mbufs
671                         */
672                        struct mbuf *n;
673                        MFREE (m, n);
674                        m = n;
675                        if (l != NULL)
676                                l->m_next = m;
677                }
678        }
679        if (nAdded) {
680                /*
681                 * Send the packet
682                 */
683                txBd->status = status | M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;
684                firstTxBd->status |= M360_BD_READY;
685                sc->txBdActiveCount += nAdded;
686        }
687}
688
689/*
690 * Driver transmit daemon
691 */
692void
693scc_txDaemon (void *arg)
694{
695        struct scc_softc *sc = (struct scc_softc *)arg;
696        struct ifnet *ifp = &sc->arpcom.ac_if;
697        struct mbuf *m;
698        rtems_event_set events;
699
700        for (;;) {
701                /*
702                 * Wait for packet
703                 */
704                rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
705
706                /*
707                 * Send packets till queue is empty
708                 */
709                for (;;) {
710                        /*
711                         * Get the next mbuf chain to transmit.
712                         */
713                        IF_DEQUEUE(&ifp->if_snd, m);
714                        if (!m)
715                                break;
716                        sendpacket (ifp, m);
717                }
718                ifp->if_flags &= ~IFF_OACTIVE;
719        }
720}
721
722/*
723 * Send packet (caller provides header).
724 */
725static void
726scc_start (struct ifnet *ifp)
727{
728        struct scc_softc *sc = ifp->if_softc;
729
730        rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
731        ifp->if_flags |= IFF_OACTIVE;
732}
733
734/*
735 * Initialize and start the device
736 */
737static void
738scc_init (void *arg)
739{
740        struct scc_softc *sc = arg;
741        struct ifnet *ifp = &sc->arpcom.ac_if;
742
743        if (sc->txDaemonTid == 0) {
744
745                /*
746                 * Set up SCC hardware
747                 */
748                m360Enet_initialize_hardware (sc);
749
750                /*
751                 * Start driver tasks
752                 */
753                sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
754                sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
755
756        }
757
758        /*
759         * Set flags appropriately
760         */
761        if (ifp->if_flags & IFF_PROMISC)
762                m360.scc1.psmr |= 0x200;
763        else
764                m360.scc1.psmr &= ~0x200;
765
766        /*
767         * Tell the world that we're running.
768         */
769        ifp->if_flags |= IFF_RUNNING;
770
771        /*
772         * Enable receiver and transmitter
773         */
774        m360.scc1.gsmr_l |= 0x30;
775}
776
777/*
778 * Stop the device
779 */
780static void
781scc_stop (struct scc_softc *sc)
782{
783        struct ifnet *ifp = &sc->arpcom.ac_if;
784
785        ifp->if_flags &= ~IFF_RUNNING;
786
787        /*
788         * Shut down receiver and transmitter
789         */
790        m360.scc1.gsmr_l &= ~0x30;
791}
792
793
794/*
795 * Show interface statistics
796 */
797static void
798scc_stats (struct scc_softc *sc)
799{
800        printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
801        printf ("       Not First:%-8lu", sc->rxNotFirst);
802        printf ("        Not Last:%-8lu\n", sc->rxNotLast);
803        printf ("              Giant:%-8lu", sc->rxGiant);
804        printf ("            Runt:%-8lu", sc->rxRunt);
805        printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
806        printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
807        printf ("         Overrun:%-8lu", sc->rxOverrun);
808        printf ("       Collision:%-8lu\n", sc->rxCollision);
809        printf ("          Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
810
811        printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
812        printf ("        Deferred:%-8lu", sc->txDeferred);
813        printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
814        printf ("         No Carrier:%-8lu", sc->txLostCarrier);
815        printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
816        printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
817        printf ("           Underrun:%-8lu", sc->txUnderrun);
818        printf (" Raw output wait:%-8lu\n", sc->txRawWait);
819}
820
821/*
822 * Driver ioctl handler
823 */
824static int
825scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
826{
827        struct scc_softc *sc = ifp->if_softc;
828        int error = 0;
829
830        switch (command) {
831        case SIOCGIFADDR:
832        case SIOCSIFADDR:
833                ether_ioctl (ifp, command, data);
834                break;
835
836        case SIOCSIFFLAGS:
837                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
838                case IFF_RUNNING:
839                        scc_stop (sc);
840                        break;
841
842                case IFF_UP:
843                        scc_init (sc);
844                        break;
845
846                case IFF_UP | IFF_RUNNING:
847                        scc_stop (sc);
848                        scc_init (sc);
849                        break;
850
851                default:
852                        break;
853                }
854                break;
855
856        case SIO_RTEMS_SHOW_STATS:
857                scc_stats (sc);
858                break;
859               
860        /*
861         * FIXME: All sorts of multicast commands need to be added here!
862         */
863        default:
864                error = EINVAL;
865                break;
866        }
867        return error;
868}
869
870/*
871 * Attach an SCC driver to the system
872 */
873int
874rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config)
875{
876        struct scc_softc *sc;
877        struct ifnet *ifp;
878        int mtu;
879        int unitNumber;
880        char *unitName;
881
882        /*
883         * Parse driver name
884         */
885        if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
886                return 0;
887       
888        /*
889         * Is driver free?
890         */
891        if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
892                printf ("Bad SCC unit number.\n");
893                return 0;
894        }
895        sc = &scc_softc[unitNumber - 1];
896        ifp = &sc->arpcom.ac_if;
897        if (ifp->if_softc != NULL) {
898                printf ("Driver already in use.\n");
899                return 0;
900        }
901
902        /*
903         * Process options
904         */
905        if (config->hardware_address) {
906                memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
907        }
908        else {
909                /*
910                 * The first 4 bytes of the bootstrap prom
911                 * contain the value loaded into the stack
912                 * pointer as part of the CPU32's hardware
913                 * reset exception handler.  The following
914                 * 4 bytes contain the value loaded into the
915                 * program counter.  The boards' Ethernet
916                 * address is stored in the six bytes
917                 * immediately preceding this initial
918                 * program counter value.
919                 *
920                 * See start360/start360.s.
921                 */
922                extern void *_RomBase;  /* From linkcmds */
923                const unsigned long *ExceptionVectors;
924                const unsigned char *entryPoint;
925
926                /*
927                 * Sanity check -- assume entry point must be
928                 * within 1 MByte of beginning of boot ROM.
929                 */
930                ExceptionVectors = (const unsigned long *)&_RomBase;
931                entryPoint = (const unsigned char *)ExceptionVectors[1];
932                if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
933                                        >= (1 * 1024 * 1024)) {
934                        printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
935                        sc->arpcom.ac_enaddr[0] = 0x08;
936                        sc->arpcom.ac_enaddr[1] = 0xF3;
937                        sc->arpcom.ac_enaddr[2] = 0x3E;
938                        sc->arpcom.ac_enaddr[3] = 0xC2;
939                        sc->arpcom.ac_enaddr[4] = 0x7E;
940                        sc->arpcom.ac_enaddr[5] = 0x38;
941                }
942                else {
943                        memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, ETHER_ADDR_LEN);
944                }
945        }
946        if (config->mtu)
947                mtu = config->mtu;
948        else
949                mtu = ETHERMTU;
950        if (config->rbuf_count)
951                sc->rxBdCount = config->rbuf_count;
952        else
953                sc->rxBdCount = RX_BUF_COUNT;
954        if (config->xbuf_count)
955                sc->txBdCount = config->xbuf_count;
956        else
957                sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
958        sc->acceptBroadcast = !config->ignore_broadcast;
959
960        /*
961         * Set up network interface values
962         */
963        ifp->if_softc = sc;
964        ifp->if_unit = unitNumber;
965        ifp->if_name = unitName;
966        ifp->if_mtu = mtu;
967        ifp->if_init = scc_init;
968        ifp->if_ioctl = scc_ioctl;
969        ifp->if_start = scc_start;
970        ifp->if_output = ether_output;
971        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
972        if (ifp->if_snd.ifq_maxlen == 0)
973                ifp->if_snd.ifq_maxlen = ifqmaxlen;
974
975        /*
976         * Attach the interface
977         */
978        if_attach (ifp);
979        ether_ifattach (ifp);
980        return 1;
981};
Note: See TracBrowser for help on using the repository browser.