source: rtems/c/src/lib/libbsp/m68k/gen68302/network/network.c @ f05b2ac

4.104.114.84.95
Last change on this file since f05b2ac was f05b2ac, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/21/04 at 16:01:48

Remove duplicate white lines.

  • Property mode set to 100644
File size: 21.2 KB
Line 
1/*
2 * RTEMS driver for M68360 SCC1 Ethernet
3 * W. Eric Norum
4 * Saskatchewan Accelerator Laboratory
5 * University of Saskatchewan
6 * Saskatoon, Saskatchewan, CANADA
7 * eric@skatter.usask.ca
8 *
9 *  $Id$
10 *
11 * Modify for Motorola 68en320 Ethernet Controller
12 * CXR S.A. France - 2000/09/14  - franckj@cxr.fr
13 */
14#include <bsp.h>
15#include <stdio.h>
16#include <rtems/error.h>
17#include <m302_int.h>
18#include <rtems/rtems_bsdnet.h>
19
20#include <sys/param.h>
21#include <sys/mbuf.h>
22#include <sys/socket.h>
23#include <sys/sockio.h>
24
25#include <net/if.h>
26
27#include <netinet/in.h>
28#include <netinet/if_ether.h>
29#include <rtems/m68k/m68302.h>
30
31/*
32 * Number of SCCs supported by this driver
33 */
34#define NSCCDRIVER      1
35
36/*
37 * Default number of buffer descriptors set aside for this driver.
38 * The number of transmit buffer descriptors has to be quite large
39 * since a single frame often uses four or more buffer descriptors.
40 */
41#define RX_BUF_COUNT     64
42#define TX_BUF_COUNT     64
43
44/*
45 * RTEMS event used by interrupt handler to signal driver tasks.
46 * This must not be any of the events used by the network task synchronization.
47 */
48#define INTERRUPT_EVENT RTEMS_EVENT_1
49
50/*
51 * RTEMS event used to start transmit daemon.
52 * This must not be the same as INTERRUPT_EVENT.
53 */
54#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
55
56/*
57 * Receive buffer size -- Allow for a full ethernet packet including CRC
58 */
59#define RBUF_SIZE       1520
60
61#if (MCLBYTES < RBUF_SIZE)
62# error "Driver must have MCLBYTES > RBUF_SIZE"
63#endif
64
65static  struct m68302_imp *             a_m68302_imp;
66
67#define M302_ETHER_IVECTOR              0x40
68
69/*
70 * Per-device data
71 */
72struct scc_softc {
73        struct arpcom           arpcom;
74        struct mbuf             **rxMbuf;
75        struct mbuf             **txMbuf;
76        int                     acceptBroadcast;
77        int                     rxBdCount;
78        int                     txBdCount;
79        int                     txBdHead;
80        int                     txBdTail;
81        int                     txBdActiveCount;
82
83        struct m68302_scc_bd    *rxBdBase;
84        struct m68302_scc_bd    *txBdBase;
85
86        rtems_id                rxDaemonTid;
87        rtems_id                txDaemonTid;
88
89        /*
90         * Statistics
91         */
92        unsigned long   rxInterrupts;
93        unsigned long   rxNotFirst;
94        unsigned long   rxNotLast;
95        unsigned long   rxGiant;
96        unsigned long   rxNonOctet;
97        unsigned long   rxRunt;
98        unsigned long   rxBadCRC;
99        unsigned long   rxOverrun;
100        unsigned long   rxCollision;
101
102        unsigned long   txInterrupts;
103        unsigned long   txDeferred;
104        unsigned long   txHeartbeat;
105        unsigned long   txLateCollision;
106        unsigned long   txRetryLimit;
107        unsigned long   txUnderrun;
108        unsigned long   txLostCarrier;
109        unsigned long   txRawWait;
110        unsigned long   txCoalesced;
111        unsigned long   txCoalesceFailed;
112        unsigned long   txRetry;
113};
114static struct scc_softc scc_softc[NSCCDRIVER];
115
116/*
117 *  interrupt handler
118 */
119static rtems_isr
120m302Enet_interrupt_handler (rtems_vector_number v)
121{
122
123        /*
124         * Frame received?
125         */
126        if (M68en302imp_intr_event & INTR_EVENT_BIT_RFINT) {
127                M68en302imp_intr_event = INTR_EVENT_BIT_RFINT;
128                M68en302imp_intr_mask &= ~INTR_MASK_BIT_RFIEN;
129                scc_softc[0].rxInterrupts++;
130                rtems_event_send (scc_softc[0].rxDaemonTid, INTERRUPT_EVENT);
131        }
132
133        /*
134         * Buffer transmitted    or transmitter error?
135         */
136        if ((M68en302imp_intr_event & INTR_EVENT_BIT_TFINT) ||
137                 ((M68en302imp_intr_event & INTR_EVENT_BIT_TXB))){
138                M68en302imp_intr_event = INTR_EVENT_BIT_TFINT | INTR_EVENT_BIT_TXB;
139                M68en302imp_intr_mask &= ~(INTR_MASK_BIT_TFIEN | INTR_MASK_BIT_TXIEN);
140                scc_softc[0].txInterrupts++;
141                rtems_event_send (scc_softc[0].txDaemonTid, INTERRUPT_EVENT);
142        }
143}
144
145/*
146 * Initialize the ethernet hardware
147 */
148static void
149m302Enet_initialize_hardware (struct scc_softc *sc)
150{
151        int i;
152        unsigned char *hwaddr;
153        rtems_status_code status;
154        rtems_isr_entry old_handler;
155        struct m68302_scc_bd    *a_bd;                  /* Buffer Descriptor pointer */
156        ushort *cam;
157#define LBK             0x0008
158#define DSQE    0x0010
159#define FDE             0x0020
160
161        /*
162         * standard loopback
163         */
164        M68302imp_port_data     (1) &= ~(LBK);
165        M68302imp_port_data     (1) |= (FDE);
166
167        M68en302imp_ecntrl=0x0001;
168        /*
169         * Set dma configuration status register EDMA
170         */
171        i = (sc->txBdCount == 16) ? EDMA_BDSIZE_16T_112R :
172                        (sc->txBdCount == 32) ? EDMA_BDSIZE_32T_96R :
173                        (sc->txBdCount == 64) ? EDMA_BDSIZE_64T_64R :
174                        EDMA_BDSIZE_8T_120R;
175
176        M68en302imp_edma =  EDMA_BLIM_8ACCESS | EDMA_WMRK_16FIFO | EDMA_BIT_TSRLY | (ushort)i;
177
178        /*
179         * Set maximum receive buffer length
180         */
181
182        M68en302imp_emrblr = RBUF_SIZE; /* 1520 */
183
184        /*
185         * Set interrupt vector
186         */
187        M68en302imp_intr_vect = M302_ETHER_IVECTOR;
188
189        M68en302imp_intr_mask=0x0;
190
191        /*
192         * Set ethernet Configuration
193         */
194        M68en302imp_ecnfig=0x0000;
195
196        /*
197         * Set ETHER_TEST
198         */
199        M68en302imp_ether_test=0x0000;
200
201        /*
202         *  Set AR control Register
203         *      Ignore/accept broadcast packets as specified
204         */
205        M68en302imp_ar_cntrl = ((sc->acceptBroadcast) ? 0 : AR_CNTRL_BIT_NO_BROADCAST) ;
206
207        /*
208         * Allocate mbuf pointers
209         */
210        sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
211        sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
212        if (!sc->rxMbuf || !sc->txMbuf)
213                rtems_panic ("No memory for mbuf pointers");
214
215        /*
216         * Set our physical address
217         */
218        hwaddr = sc->arpcom.ac_enaddr;
219
220        cam=(ushort *)(M68en302imp_cet);
221        for (i=0;i<64;i++){
222                cam[(4*i)]=0x00ff;
223                cam[(4*i)+1]=0x00ff;
224                cam[(4*i)+2]=0x00ff;
225        }
226
227        cam[4] = (hwaddr[0] << 8) | hwaddr[1];
228        cam[5] = (hwaddr[2] << 8) | hwaddr[3];
229        cam[6] = (hwaddr[4] << 8) | hwaddr[5];
230
231        /*
232         * Set receiver and transmitter buffer descriptor bases
233         */
234        a_bd = M68302imp_a_eth_bd (0);                  /* point to first BD */
235
236        for (i=0;i<128;i++){
237
238                M68302_scc_bd_stat_ctrl (a_bd + i) = 0;
239                M68302_scc_bd_data_lgth (a_bd + i) = 0;
240                M68302_scc_bd_p_buffer  (a_bd + i) = NULL;
241        }
242
243        sc->txBdBase = M68302imp_a_eth_bd (  0 );                       /* point to first BD */
244        sc->rxBdBase = M68302imp_a_eth_bd ( sc->txBdCount);             /* point to first RX BD atfer all TX*/
245
246        /*
247         * Set up transmit buffer descriptors
248         */
249        for (i = 0 ; i < sc->txBdCount ; i++) {
250                sc->txMbuf[i] = NULL;
251        }
252        sc->txBdHead = sc->txBdTail = 0;
253        sc->txBdActiveCount = 0;
254
255        /*
256         * Clear any outstanding events
257         */
258        M68en302imp_intr_event = 0x07FF;
259        /*
260         * Set up interrupts
261         */
262
263        status = rtems_interrupt_catch (m302Enet_interrupt_handler,
264                                                M302_ETHER_IVECTOR,
265                                                &old_handler);
266        if (status != RTEMS_SUCCESSFUL)
267                rtems_panic ("Can't attach M302 ether interrupt handler: %s\r\n",
268                                                rtems_status_text (status));
269}
270
271/*
272 * Soak up buffer descriptors that have been sent
273 * Note that a buffer descriptor can't be retired as soon as it becomes
274 * ready.  The MC68360 Errata (May 96) says that, "If an Ethernet frame is
275 *  made up of multiple buffers, the user should not reuse the first buffer
276 * descriptor until the last buffer descriptor of the frame has had its
277 * ready bit cleared by the CPM".
278 */
279static void
280m302Enet_retire_tx_bd (struct scc_softc *sc)
281{
282
283        uint16_t         status;
284        int i;
285        int nRetired;
286        struct mbuf *m, *n;
287        int retries = 0;
288        int saveStatus = 0;
289
290        i = sc->txBdTail;
291        nRetired = 0;
292        while ((sc->txBdActiveCount != 0)
293           &&  (((status = (sc->txBdBase + i)->stat_ctrl) & BUF_STAT_READY) == 0)) {
294                /*
295                 * Check for errors which stop the transmitter.
296                 */
297                if (status & (BUF_STAT_LATE_COLLISION |
298                                BUF_STAT_RETRY_LIMIT |
299                                BUF_STAT_UNDERRUN)) {
300                        int j;
301
302                        if (status & BUF_STAT_LATE_COLLISION)
303                                sc->txLateCollision++;
304                        if (status & BUF_STAT_RETRY_LIMIT)
305                                sc->txRetryLimit++;
306                        if (status & BUF_STAT_UNDERRUN)
307                                sc->txUnderrun++;
308
309                        /*
310                         * Reenable buffer descriptors
311                         */
312                        j = sc->txBdTail;
313                        for (;;) {
314                                status = (sc->txBdBase + j)->stat_ctrl;
315                                if (status & BUF_STAT_READY)
316                                        break;
317                                (sc->txBdBase + j)->stat_ctrl = BUF_STAT_READY |
318                                        (status & ( BUF_STAT_WRAP |
319                                                   BUF_STAT_INTERRUPT |
320                                                   BUF_STAT_LAST |
321                                                   BUF_STAT_TX_CRC));
322                                if (status & BUF_STAT_LAST)
323                                        break;
324                                if (++j == sc->txBdCount)
325                                        j = 0;
326                        }
327
328                        /*
329                         * Move transmitter back to the first
330                         * buffer descriptor in the frame.
331                         */
332/*                      m360.scc1p._tbptr = m360.scc1p.tbase +
333                                sc->txBdTail * sizeof (m360BufferDescriptor_t);
334*/
335                        /*
336                         * Restart the transmitter
337                         */
338/*                      M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);*/
339                        continue;
340                }
341                saveStatus |= status;
342                retries += (status >> 2) & 0xF;
343                nRetired++;
344                if (status & BUF_STAT_LAST) {
345                        /*
346                         * A full frame has been transmitted.
347                         * Free all the associated buffer descriptors.
348                         */
349                        if (saveStatus & BUF_STAT_DEFER)
350                                sc->txDeferred++;
351                        if (saveStatus & BUF_STAT_HEARTBIT)
352                                sc->txHeartbeat++;
353                        if (saveStatus & BUF_STAT_CARRIER_LOST)
354                                sc->txLostCarrier++;
355                        saveStatus = 0;
356                        sc->txRetry += retries;
357                        retries = 0;
358                        sc->txBdActiveCount -= nRetired;
359                        while (nRetired) {
360                                nRetired--;
361                                m = sc->txMbuf[sc->txBdTail];
362                                MFREE (m, n);
363                                if (++sc->txBdTail == sc->txBdCount)
364                                        sc->txBdTail = 0;
365                        }
366                }
367                if (++i == sc->txBdCount)
368                        i = 0;
369        }
370
371}
372
373/*
374 * SCC reader task
375 */
376static void
377scc_rxDaemon (void *arg)
378{
379
380        struct scc_softc *sc = (struct scc_softc *)arg;
381        struct ifnet *ifp = &sc->arpcom.ac_if;
382        struct mbuf *m;
383        uint16_t         status;
384        volatile struct m68302_scc_bd *rxBd;
385        int rxBdIndex;
386
387        /*
388         * Allocate space for incoming packets and start reception
389         */
390        for (rxBdIndex = 0 ; ;) {
391                rxBd = sc->rxBdBase + rxBdIndex;
392                MGETHDR (m, M_WAIT, MT_DATA);
393                MCLGET (m, M_WAIT);
394                m->m_pkthdr.rcvif = ifp;
395                sc->rxMbuf[rxBdIndex] = m;
396                rxBd->p_buffer = mtod (m, void *);
397
398                if (++rxBdIndex == sc->rxBdCount) {
399                        rxBd->stat_ctrl = BUF_STAT_EMPTY | BUF_STAT_INTERRUPT | BUF_STAT_WRAP;
400                        break;
401                }
402                rxBd->stat_ctrl = BUF_STAT_EMPTY | BUF_STAT_INTERRUPT;
403        }
404
405        /*
406         * Input packet handling loop
407         */
408        rxBdIndex = 0;
409        for (;;) {
410                rxBd = sc->rxBdBase + rxBdIndex;
411
412                /*
413                 * Wait for packet if there's not one ready
414                 */
415                if ((status = rxBd->stat_ctrl) & BUF_STAT_EMPTY) {
416                        /*
417                         * Clear old events
418                         */
419                        M68en302imp_intr_event = INTR_EVENT_BIT_RFINT;
420
421                        /*
422                         * Wait for packet
423                         * Note that the buffer descriptor is checked
424                         * *before* the event wait -- this catches the
425                         * possibility that a packet arrived between the
426                         * `if' above, and the clearing of the event register.
427                         */
428                        while ((status = rxBd->stat_ctrl) & BUF_STAT_EMPTY) {
429                                rtems_interrupt_level level;
430                                rtems_event_set events;
431
432                                /*
433                                 * Unmask RXF (Full frame received) event
434                                 */
435                                rtems_interrupt_disable (level);
436                                M68en302imp_intr_mask |= INTR_MASK_BIT_RFIEN;
437
438                                rtems_interrupt_enable (level);
439                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
440                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
441                                                RTEMS_NO_TIMEOUT,
442                                                &events);
443                        }
444                }
445
446                /*
447                 * Check that packet is valid
448                 */
449                if ((status & (BUF_STAT_LAST |
450                                BUF_STAT_FIRST_IN_FRAME |
451                                BUF_STAT_LONG |
452                                BUF_STAT_NONALIGNED |
453                                BUF_STAT_SHORT |
454                                BUF_STAT_CRC_ERROR |
455                                BUF_STAT_OVERRUN |
456                                BUF_STAT_COLLISION)) ==
457                                                (BUF_STAT_LAST |
458                                                BUF_STAT_FIRST_IN_FRAME)) {
459                        /*
460                         * Pass the packet up the chain.
461                         * FIXME: Packet filtering hook could be done here.
462                         */
463                        struct ether_header *eh;
464
465                        m = sc->rxMbuf[rxBdIndex];
466                        m->m_len = m->m_pkthdr.len = rxBd->data_lgth -
467                                                sizeof(uint32_t) -
468                                                sizeof(struct ether_header);
469                        eh = mtod (m, struct ether_header *);
470                        m->m_data += sizeof(struct ether_header);
471
472                        ether_input (ifp, eh, m);
473
474                        /*
475                         * Allocate a new mbuf
476                         */
477                        MGETHDR (m, M_WAIT, MT_DATA);
478                        MCLGET (m, M_WAIT);
479                        m->m_pkthdr.rcvif = ifp;
480                        sc->rxMbuf[rxBdIndex] = m;
481                        rxBd->p_buffer = mtod (m, void *);
482                }
483                else {
484                        /*
485                         * Something went wrong with the reception
486                         */
487                        if (!(status & BUF_STAT_LAST))
488                                sc->rxNotLast++;
489                        if (!(status & BUF_STAT_FIRST_IN_FRAME))
490                                sc->rxNotFirst++;
491                        if (status & BUF_STAT_LONG)
492                                sc->rxGiant++;
493                        if (status & BUF_STAT_NONALIGNED)
494                                sc->rxNonOctet++;
495                        if (status & BUF_STAT_SHORT)
496                                sc->rxRunt++;
497                        if (status & BUF_STAT_CRC_ERROR)
498                                sc->rxBadCRC++;
499                        if (status & BUF_STAT_OVERRUN)
500                                sc->rxOverrun++;
501                        if (status & BUF_STAT_COLLISION)
502                                sc->rxCollision++;
503                }
504
505                /*
506                 * Reenable the buffer descriptor
507                 */
508                rxBd->stat_ctrl = (status & (BUF_STAT_WRAP | BUF_STAT_INTERRUPT)) | BUF_STAT_EMPTY;
509
510                /*
511                 * Move to next buffer descriptor
512                 */
513                if (++rxBdIndex == sc->rxBdCount)
514                        rxBdIndex = 0;
515        }
516
517}
518
519static void
520sendpacket (struct ifnet *ifp, struct mbuf *m)
521{
522
523        struct scc_softc *sc = ifp->if_softc;
524        volatile struct m68302_scc_bd *firstTxBd, *txBd;
525        struct mbuf *l = NULL;
526        uint16_t         status;
527        int nAdded;
528
529        /*
530         * Free up buffer descriptors
531         */
532        m302Enet_retire_tx_bd (sc);
533        /*
534         * Set up the transmit buffer descriptors.
535         * No need to pad out short packets since the
536         * hardware takes care of that automatically.
537         * No need to copy the packet to a contiguous buffer
538         * since the hardware is capable of scatter/gather DMA.
539         */
540        status = 0;
541        nAdded = 0;
542        txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
543        while (m) {
544                /*
545                 * There are more mbufs in the packet than there
546                 * are transmit buffer descriptors.
547                 * Coalesce into a single buffer.
548                 */
549                if (nAdded == sc->txBdCount) {
550                        struct mbuf *nm;
551                        int j;
552                        char *dest;
553
554                        /*
555                         * Get the pointer to the first mbuf of the packet
556                         */
557                        if (sc->txBdTail != sc->txBdHead)
558                                rtems_panic ("sendpacket coalesce");
559                        m = sc->txMbuf[sc->txBdTail];
560
561                        /*
562                         * Rescind the buffer descriptor READY bits
563                         */
564                        for (j = 0 ; j < sc->txBdCount ; j++)
565                                (sc->txBdBase + j)->stat_ctrl = 0;
566
567                        /*
568                         * Allocate an mbuf cluster
569                         * Toss the packet if allocation fails
570                         */
571                        MGETHDR (nm, M_DONTWAIT, MT_DATA);
572                        if (nm == NULL) {
573                                sc->txCoalesceFailed++;
574                                m_freem (m);
575
576                                return;
577                        }
578                        MCLGET (nm, M_DONTWAIT);
579                        if (nm->m_ext.ext_buf == NULL) {
580                                sc->txCoalesceFailed++;
581                                m_freem (m);
582                                m_free (nm);
583
584                                return;
585                        }
586                        nm->m_pkthdr = m->m_pkthdr;
587                        nm->m_len = nm->m_pkthdr.len;
588
589                        /*
590                         * Copy data from packet chain to mbuf cluster
591                         */
592                        sc->txCoalesced++;
593                        dest = nm->m_ext.ext_buf;
594                        while (m) {
595                                struct mbuf *n;
596
597                                if (m->m_len) {
598                                        memcpy (dest, mtod(m, caddr_t), m->m_len);
599                                        dest += m->m_len;
600                                }
601                                MFREE (m, n);
602                                m = n;
603                        }
604
605                        /*
606                         * Redo the send with the new mbuf cluster
607                         */
608                        m = nm;
609                        nAdded = 0;
610                        status = 0;
611
612                        continue;
613                }
614
615                /*
616                 * Wait for buffer descriptor to become available.
617                 */
618                if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
619                        /*
620                         * Clear old events
621                         */
622                        M68en302imp_intr_event = INTR_EVENT_BIT_TFINT | INTR_EVENT_BIT_TXB;
623
624                        /*
625                         * Wait for buffer descriptor to become available.
626                         * Note that the buffer descriptors are checked
627                         * *before* entering the wait loop -- this catches
628                         * the possibility that a buffer descriptor became
629                         * available between the `if' above, and the clearing
630                         * of the event register.
631                         * This is to catch the case where the transmitter
632                         * stops in the middle of a frame -- and only the
633                         * last buffer descriptor in a frame can generate
634                         * an interrupt.
635                         */
636                        m302Enet_retire_tx_bd (sc);
637                        while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
638                                rtems_interrupt_level level;
639                                rtems_event_set events;
640
641                                /*
642                                 * Unmask TXB (buffer transmitted) and
643                                 * TXE (transmitter error) events.
644                                 */
645                                rtems_interrupt_disable (level);
646                                M68en302imp_intr_mask |= INTR_MASK_BIT_TFIEN | INTR_MASK_BIT_TXIEN;
647                                rtems_interrupt_enable (level);
648
649                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
650                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
651                                                RTEMS_NO_TIMEOUT,
652                                                &events);
653                                m302Enet_retire_tx_bd (sc);
654                        }
655                }
656
657                /*
658                 * The IP fragmentation routine in ip_output
659                 * can produce packet fragments with zero length.
660                 */
661                if (m->m_len) {
662                        /*
663                         * Fill in the buffer descriptor.
664                         * Don't set the READY flag in the first buffer
665                         * descriptor till the whole packet has been readied.
666                         */
667                        txBd = sc->txBdBase + sc->txBdHead;
668                        txBd->p_buffer = mtod (m, void *);
669                        txBd->data_lgth = m->m_len;
670
671                        sc->txMbuf[sc->txBdHead] = m;
672                        status = nAdded ? BUF_STAT_READY : 0;
673                        if (++sc->txBdHead == sc->txBdCount) {
674                                status |= BUF_STAT_WRAP;
675                                sc->txBdHead = 0;
676                        }
677                        txBd->stat_ctrl = status;
678                        l = m;
679                        m = m->m_next;
680                        nAdded++;
681
682                }
683                else {
684                        /*
685                         * Just toss empty mbufs
686                         */
687                        struct mbuf *n;
688                        MFREE (m, n);
689                        m = n;
690                        if (l != NULL)
691                                l->m_next = m;
692
693                }
694        }
695        if (nAdded) {
696                /*
697                 * Send the packet
698                 */
699                txBd->stat_ctrl = status | BUF_STAT_LAST | BUF_STAT_TX_CRC | BUF_STAT_INTERRUPT;
700                firstTxBd->stat_ctrl |= BUF_STAT_READY;
701                sc->txBdActiveCount += nAdded;
702
703        }
704
705}
706
707/*
708 * Driver transmit daemon
709 */
710void
711scc_txDaemon (void *arg)
712{
713
714        struct scc_softc *sc = (struct scc_softc *)arg;
715        struct ifnet *ifp = &sc->arpcom.ac_if;
716        struct mbuf *m;
717        rtems_event_set events;
718
719        for (;;) {
720                /*
721                 * Wait for packet
722                 */
723                rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
724
725                /*
726                 * Send packets till queue is empty
727                 */
728                for (;;) {
729                        /*
730                         * Get the next mbuf chain to transmit.
731                         */
732                        IF_DEQUEUE(&ifp->if_snd, m);
733                        if (!m)
734                                break;
735                        sendpacket (ifp, m);
736                }
737                ifp->if_flags &= ~IFF_OACTIVE;
738        }
739
740}
741
742/*
743 * Send packet (caller provides header).
744 */
745static void
746scc_start (struct ifnet *ifp)
747{
748        struct scc_softc *sc = ifp->if_softc;
749
750        rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
751        ifp->if_flags |= IFF_OACTIVE;
752}
753
754/*
755 * Initialize and start the device
756 */
757static void
758scc_init (void *arg)
759{
760        struct scc_softc *sc = arg;
761        struct ifnet *ifp = &sc->arpcom.ac_if;
762
763        if (sc->txDaemonTid == 0) {
764
765                /*
766                 * Set up SCC hardware
767                 */
768                m302Enet_initialize_hardware (sc);
769
770                sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
771                sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
772
773        }
774
775        /*
776         * Set flags appropriately
777         */
778/*      if (ifp->if_flags & IFF_PROMISC)
779                m360.scc1.psmr |= 0x200;
780        else
781                m360.scc1.psmr &= ~0x200;
782*/
783        /*
784         * Tell the world that we're running.
785         */
786        ifp->if_flags |= IFF_RUNNING;
787
788        /*
789         * Enable receiver and transmitter
790         */
791        M68en302imp_ecntrl = ECNTRL_BIT_RESET   | ECNTRL_BIT_ETHER_EN;
792
793}
794
795/*
796 * Stop the device
797 */
798static void
799scc_stop (struct scc_softc *sc)
800{
801
802        struct ifnet *ifp = &sc->arpcom.ac_if;
803
804        ifp->if_flags &= ~IFF_RUNNING;
805
806        /*
807         * Shut down receiver and transmitter
808         */
809        M68en302imp_ecntrl &= ~(ECNTRL_BIT_RESET        | ECNTRL_BIT_ETHER_EN);
810
811}
812
813/*
814 * Show interface statistics
815 */
816static void
817scc_stats (struct scc_softc *sc)
818{
819        printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
820        printf ("       Not First:%-8lu", sc->rxNotFirst);
821        printf ("        Not Last:%-8lu\r\n", sc->rxNotLast);
822        printf ("              Giant:%-8lu", sc->rxGiant);
823        printf ("            Runt:%-8lu", sc->rxRunt);
824        printf ("       Non-octet:%-8lu\r\n", sc->rxNonOctet);
825        printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
826        printf ("         Overrun:%-8lu", sc->rxOverrun);
827        printf ("       Collision:%-8lu\r\n", sc->rxCollision);
828/*      printf ("          Discarded:%-8lu\r\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
829*/
830        printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
831        printf ("        Deferred:%-8lu", sc->txDeferred);
832        printf (" Missed Hearbeat:%-8lu\r\n", sc->txHeartbeat);
833        printf ("         No Carrier:%-8lu", sc->txLostCarrier);
834        printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
835        printf ("  Late Collision:%-8lu\r\n", sc->txLateCollision);
836        printf ("           Underrun:%-8lu", sc->txUnderrun);
837        printf (" Raw output wait:%-8lu", sc->txRawWait);
838        printf ("       Coalesced:%-8lu\r\n", sc->txCoalesced);
839        printf ("    Coalesce failed:%-8lu", sc->txCoalesceFailed);
840        printf ("         Retries:%-8lu\r\n", sc->txRetry);
841}
842
843/*
844 * Driver ioctl handler
845 */
846static int
847scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
848{
849
850        struct scc_softc *sc = ifp->if_softc;
851        int error = 0;
852
853        switch (command) {
854        case SIOCGIFADDR:
855        case SIOCSIFADDR:
856                ether_ioctl (ifp, command, data);
857                break;
858
859        case SIOCSIFFLAGS:
860                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
861                case IFF_RUNNING:
862                        scc_stop (sc);
863                        break;
864
865                case IFF_UP:
866                        scc_init (sc);
867                        break;
868
869                case IFF_UP | IFF_RUNNING:
870                        scc_stop (sc);
871                        scc_init (sc);
872                        break;
873
874                default:
875                        break;
876                }
877                break;
878
879        case SIO_RTEMS_SHOW_STATS:
880                scc_stats (sc);
881                break;
882
883        /*
884         * FIXME: All sorts of multicast commands need to be added here!
885         */
886        default:
887                error = EINVAL;
888                break;
889        }
890        return error;
891
892}
893
894/*
895 * Attach an SCC driver to the system
896 */
897int
898rtems_ether1_driver_attach (struct rtems_bsdnet_ifconfig *config)
899{
900        struct scc_softc *sc;
901        struct ifnet *ifp;
902        int mtu;
903        int unitNumber;
904        char *unitName;
905
906        a_m68302_imp = (struct m68302_imp *)0x700000L;
907        /*
908         * Parse driver name
909         */
910        if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
911                return 0;
912
913        /*
914         * Is driver free?
915         */
916        if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
917                printf ("Bad SCC unit number.\r\n");
918                return 0;
919        }
920        sc = &scc_softc[unitNumber - 1];
921        ifp = &sc->arpcom.ac_if;
922        if (ifp->if_softc != NULL) {
923                printf ("Driver already in use.\r\n");
924                return 0;
925        }
926
927        /*
928         * Process options
929         */
930        if (config->hardware_address) {
931                memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
932        }
933
934        if (config->mtu)
935                mtu = config->mtu;
936        else
937                mtu = ETHERMTU;
938        if (config->rbuf_count)
939                sc->rxBdCount = config->rbuf_count;
940        else
941                sc->rxBdCount = RX_BUF_COUNT;
942        if (config->xbuf_count)
943                sc->txBdCount = config->xbuf_count;
944        else
945                sc->txBdCount = TX_BUF_COUNT;
946        sc->acceptBroadcast = !config->ignore_broadcast;
947
948        /*
949         * Set up network interface values
950         */
951        ifp->if_softc = sc;
952        ifp->if_unit = unitNumber;
953        ifp->if_name = unitName;
954        ifp->if_mtu = mtu;
955        ifp->if_init = scc_init;
956        ifp->if_ioctl = scc_ioctl;
957        ifp->if_start = scc_start;
958        ifp->if_output = ether_output;
959        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
960        if (ifp->if_snd.ifq_maxlen == 0)
961                ifp->if_snd.ifq_maxlen = ifqmaxlen;
962
963        /*
964         * Attach the interface
965         */
966        if_attach (ifp);
967        ether_ifattach (ifp);
968        return 1;
969};
Note: See TracBrowser for help on using the repository browser.