source: rtems/bsps/powerpc/tqm8xx/net/network_scc.c @ 762fa62

5
Last change on this file since 762fa62 was 031df391, checked in by Sebastian Huber <sebastian.huber@…>, on 04/23/18 at 07:53:31

bsps: Move legacy network drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 26.5 KB
Line 
1/*===============================================================*\
2| Project: RTEMS TQM8xx BSP                                       |
3+-----------------------------------------------------------------+
4| This file has been adapted to MPC8xx by                         |
5|    Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>         |
6|                    Copyright (c) 2008                           |
7|                    Embedded Brains GmbH                         |
8|                    Obere Lagerstr. 30                           |
9|                    D-82178 Puchheim                             |
10|                    Germany                                      |
11|                    rtems@embedded-brains.de                     |
12|                                                                 |
13| See the other copyright notice below for the original parts.    |
14+-----------------------------------------------------------------+
15| The license and distribution terms for this file may be         |
16| found in the file LICENSE in this distribution or at            |
17|                                                                 |
18| http://www.rtems.org/license/LICENSE.                           |
19|                                                                 |
20+-----------------------------------------------------------------+
21| this file contains the console driver                           |
22\*===============================================================*/
23/* derived from: */
24/*
25 * RTEMS/TCPIP driver for MPC8xx SCC1 Ethernet
26 *
27 *  Modified for MPC860 by Jay Monkman (jmonkman@frasca.com)
28 *
29 *  This supports Ethernet on either SCC1 or the FEC of the MPC860T.
30 *  Right now, we only do 10 Mbps, even with the FEC. The function
31 *  rtems_enet_driver_attach determines which one to use. Currently,
32 *  only one may be used at a time.
33 *
34 *  Based on the MC68360 network driver by
35 *  W. Eric Norum
36 *  Saskatchewan Accelerator Laboratory
37 *  University of Saskatchewan
38 *  Saskatoon, Saskatchewan, CANADA
39 *  eric@skatter.usask.ca
40 *
41 *  This supports ethernet on SCC1. Right now, we only do 10 Mbps.
42 *
43 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
44 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
45 *  Copyright (c) 1999, National Research Council of Canada
46 */
47
48#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
49
50#include <bsp.h>
51#include <stdio.h>
52#include <errno.h>
53#include <rtems/error.h>
54#include <rtems/rtems_bsdnet.h>
55
56#include <sys/param.h>
57#include <sys/mbuf.h>
58#include <sys/socket.h>
59#include <sys/sockio.h>
60
61#include <net/if.h>
62
63#include <netinet/in.h>
64#include <netinet/if_ether.h>
65#include <bsp/irq.h>
66
67#include <sys/types.h>
68#include <sys/socket.h>
69
70/*
71 * Number of interfaces supported by this driver
72 */
73#define NIFACES 1
74
75/*
76 * Default number of buffer descriptors set aside for this driver.
77 * The number of transmit buffer descriptors has to be quite large
78 * since a single frame often uses four or more buffer descriptors.
79 */
80#define RX_BUF_COUNT     32
81#define TX_BUF_COUNT     8
82#define TX_BD_PER_BUF    4
83
84#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
85
86/*
87 * RTEMS event used by interrupt handler to signal daemons.
88 * This must *not* be the same event used by the TCP/IP task synchronization.
89 */
90#define INTERRUPT_EVENT RTEMS_EVENT_1
91
92/*
93 * RTEMS event used to start transmit daemon.
94 * This must not be the same as INTERRUPT_EVENT.
95 */
96#define START_TRANSMIT_EVENT RTEMS_EVENT_2
97
98/*
99 * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
100 * Round off to nearest multiple of RBUF_ALIGN.
101 */
102#define MAX_MTU_SIZE    1518
103#define RBUF_ALIGN              4
104#define RBUF_SIZE       ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
105
106#if (MCLBYTES < RBUF_SIZE)
107# error "Driver must have MCLBYTES > RBUF_SIZE"
108#endif
109
110/*
111 * Per-device data
112 */
113struct m8xx_enet_struct {
114  struct arpcom           arpcom;
115  struct mbuf             **rxMbuf;
116  struct mbuf             **txMbuf;
117  int                     acceptBroadcast;
118  int                     rxBdCount;
119  int                     txBdCount;
120  int                     txBdHead;
121  int                     txBdTail;
122  int                     txBdActiveCount;
123  m8xxBufferDescriptor_t  *rxBdBase;
124  m8xxBufferDescriptor_t  *txBdBase;
125  rtems_id                rxDaemonTid;
126  rtems_id                txDaemonTid;
127
128  /*
129   * Statistics
130   */
131  unsigned long   rxInterrupts;
132  unsigned long   rxNotFirst;
133  unsigned long   rxNotLast;
134  unsigned long   rxGiant;
135  unsigned long   rxNonOctet;
136  unsigned long   rxRunt;
137  unsigned long   rxBadCRC;
138  unsigned long   rxOverrun;
139  unsigned long   rxCollision;
140
141  unsigned long   txInterrupts;
142  unsigned long   txDeferred;
143  unsigned long   txHeartbeat;
144  unsigned long   txLateCollision;
145  unsigned long   txRetryLimit;
146  unsigned long   txUnderrun;
147  unsigned long   txLostCarrier;
148  unsigned long   txRawWait;
149};
150static struct m8xx_enet_struct enet_driver[NIFACES];
151
152static void  m8xx_scc1_ethernet_on(const rtems_irq_connect_data* ptr)
153{
154}
155
156static void  m8xx_scc1_ethernet_off(const rtems_irq_connect_data* ptr)
157{
158  /*
159   * Please put relevant code there
160   */
161}
162
163static int  m8xx_scc1_ethernet_isOn(const rtems_irq_connect_data* ptr)
164{
165  /*
166   * Assume, that we are on
167   */
168  return 1;
169}
170
171/*
172 * SCC1 interrupt handler
173 */
174static void m8xx_scc1_interrupt_handler (void *unused)
175{
176  /* Frame received? */
177  if ((m8xx.scc1.sccm & 0x8) && (m8xx.scc1.scce & 0x8)) {
178    m8xx.scc1.scce = 0x8;               /* Clear receive frame int */
179    m8xx.scc1.sccm &= ~0x8;     /* Disable receive frame ints */
180    enet_driver[0].rxInterrupts++; /* Rx int has occurred */
181    rtems_bsdnet_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
182  }
183
184  /* Buffer transmitted or transmitter error? */
185  if ((m8xx.scc1.sccm & 0x12) && (m8xx.scc1.scce & 0x12)) {
186    m8xx.scc1.scce = 0x12;              /* Clear Tx int */
187    m8xx.scc1.sccm &= ~0x12;    /* Disable Tx ints */
188    enet_driver[0].txInterrupts++; /* Tx int has occurred */
189    rtems_bsdnet_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
190  }
191}
192
193
194static rtems_irq_connect_data ethernetSCC1IrqData = {
195  BSP_CPM_IRQ_SCC1,
196  (rtems_irq_hdl) m8xx_scc1_interrupt_handler,
197  NULL,
198  m8xx_scc1_ethernet_on,
199  m8xx_scc1_ethernet_off,
200  m8xx_scc1_ethernet_isOn
201};
202
203/*
204 * Initialize the ethernet hardware
205 */
206static void
207m8xx_enet_initialize (struct m8xx_enet_struct *sc)
208{
209  int i;
210  unsigned char *hwaddr;
211
212  /*
213   * Configure port A
214   * PA15 is enet RxD. Set PAPAR(15) to 1, PADIR(15) to 0.
215   * PA14 is enet TxD. Set PAPAR(14) to 1, PADIR(14) to 0, PAODR(14) to 0.
216   * PA7 is input CLK1. Set PAPAR(7) to 1, PADIR(7) to 0.
217   * PA6 is input CLK2. Set PAPAR(6) to 1, PADIR(6) to 0.
218   */
219  m8xx.papar |=  0x303;
220  m8xx.padir &= ~0x303;
221  m8xx.paodr &= ~0x2;
222
223  /*
224   * Configure port C
225   * PC11 is CTS1*. Set PCPAR(11) to 0, PCDIR(11) to 0, and PCSO(11) to 1.
226   * PC10 is CD1*. Set PCPAR(10) to 0, PCDIR(10) to 0, and PCSO(10) to 1.
227   */
228  m8xx.pcpar &= ~0x30;
229  m8xx.pcdir &= ~0x30;
230  m8xx.pcso  |=  0x30;
231
232  /*
233   * Connect CLK1 and CLK2 to SCC1 in the SICR.
234   * CLK1 is TxClk, CLK2 is RxClk. No grant mechanism, SCC1 is directly
235   * connected to the NMSI pins.
236   * R1CS = 0b101 (CLK2)
237   * T1CS = 0b100 (CLK1)
238   */
239  m8xx.sicr |= 0x2C;
240
241  /*
242   * Initialize SDMA configuration register
243   */
244  m8xx.sdcr = 1;
245
246  /*
247   * Allocate mbuf pointers
248   */
249  sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
250                       M_MBUF, M_NOWAIT);
251  sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
252                       M_MBUF, M_NOWAIT);
253  if (!sc->rxMbuf || !sc->txMbuf)
254    rtems_panic ("No memory for mbuf pointers");
255
256  /*
257   * Set receiver and transmitter buffer descriptor bases
258   */
259  sc->rxBdBase = m8xx_bd_allocate(sc->rxBdCount);
260  sc->txBdBase = m8xx_bd_allocate(sc->txBdCount);
261  m8xx.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m8xx;
262  m8xx.scc1p.tbase = (char *)sc->txBdBase - (char *)&m8xx;
263
264  /*
265   * Send "Init parameters" command
266   */
267  m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC1);
268
269  /*
270   * Set receive and transmit function codes
271   */
272  m8xx.scc1p.rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
273  m8xx.scc1p.tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0);
274
275  /*
276   * Set maximum receive buffer length
277   */
278  m8xx.scc1p.mrblr = RBUF_SIZE;
279
280  /*
281   * Set CRC parameters
282   */
283  m8xx.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
284  m8xx.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
285
286  /*
287   * Clear diagnostic counters
288   */
289  m8xx.scc1p.un.ethernet.crcec = 0;
290  m8xx.scc1p.un.ethernet.alec = 0;
291  m8xx.scc1p.un.ethernet.disfc = 0;
292
293  /*
294   * Set pad value
295   */
296  m8xx.scc1p.un.ethernet.pads = 0x8888;
297
298  /*
299   * Set retry limit
300   */
301  m8xx.scc1p.un.ethernet.ret_lim = 15;
302
303  /*
304   * Set maximum and minimum frame length
305   */
306  m8xx.scc1p.un.ethernet.mflr = 1518;
307  m8xx.scc1p.un.ethernet.minflr = 64;
308  m8xx.scc1p.un.ethernet.maxd1 = MAX_MTU_SIZE;
309  m8xx.scc1p.un.ethernet.maxd2 = MAX_MTU_SIZE;
310
311  /*
312   * Clear group address hash table
313   */
314  m8xx.scc1p.un.ethernet.gaddr1 = 0;
315  m8xx.scc1p.un.ethernet.gaddr2 = 0;
316  m8xx.scc1p.un.ethernet.gaddr3 = 0;
317  m8xx.scc1p.un.ethernet.gaddr4 = 0;
318
319  /*
320   * Set our physical address
321   */
322  hwaddr = sc->arpcom.ac_enaddr;
323
324  m8xx.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
325  m8xx.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
326  m8xx.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
327
328  /*
329   * Aggressive retry
330   */
331  m8xx.scc1p.un.ethernet.p_per = 0;
332
333  /*
334   * Clear individual address hash table
335   */
336  m8xx.scc1p.un.ethernet.iaddr1 = 0;
337  m8xx.scc1p.un.ethernet.iaddr2 = 0;
338  m8xx.scc1p.un.ethernet.iaddr3 = 0;
339  m8xx.scc1p.un.ethernet.iaddr4 = 0;
340
341  /*
342   * Clear temp address
343   */
344  m8xx.scc1p.un.ethernet.taddr_l = 0;
345  m8xx.scc1p.un.ethernet.taddr_m = 0;
346  m8xx.scc1p.un.ethernet.taddr_h = 0;
347
348  /*
349   * Set up receive buffer descriptors
350   */
351  for (i = 0 ; i < sc->rxBdCount ; i++) {
352    (sc->rxBdBase + i)->status = 0;
353  }
354
355  /*
356   * Set up transmit buffer descriptors
357   */
358  for (i = 0 ; i < sc->txBdCount ; i++) {
359    (sc->txBdBase + i)->status = 0;
360    sc->txMbuf[i] = NULL;
361  }
362  sc->txBdHead = sc->txBdTail = 0;
363  sc->txBdActiveCount = 0;
364
365  /*
366   * Clear any outstanding events
367   */
368  m8xx.scc1.scce = 0xFFFF;
369
370  /*
371   * Set up interrupts
372   */
373  if (!BSP_install_rtems_irq_handler (&ethernetSCC1IrqData)) {
374    rtems_panic ("Can't attach M8xx SCC1 interrupt handler\n");
375  }
376  m8xx.scc1.sccm = 0;     /* No interrupts unmasked till necessary */
377
378  /*
379   * Set up General SCC Mode Register
380   * Ethernet configuration
381   */
382  m8xx.scc1.gsmr_h = 0x0;
383  m8xx.scc1.gsmr_l = 0x1088000c;
384
385  /*
386   * Set up data synchronization register
387   * Ethernet synchronization pattern
388   */
389  m8xx.scc1.dsr = 0xd555;
390
391  /*
392   * Set up protocol-specific mode register
393   *      No Heartbeat check
394   *      No force collision
395   *      Discard short frames
396   *      Individual address mode
397   *      Ethernet CRC
398   *      Not promisuous
399   *      Ignore/accept broadcast packets as specified
400   *      Normal backoff timer
401   *      No loopback
402   *      No input sample at end of frame
403   *      64-byte limit for late collision
404   *      Wait 22 bits before looking for start of frame delimiter
405   *      Disable full-duplex operation
406   */
407  m8xx.scc1.psmr = 0x080A | (sc->acceptBroadcast ? 0 : 0x100);
408
409  /*
410   * Enable the TENA (RTS1*) pin
411   */
412  m8xx.pcpar |=  0x1;
413  m8xx.pcdir &= ~0x1;
414
415  /*
416   * Enable receiver and transmitter
417   */
418  m8xx.scc1.gsmr_l = 0x1088003c;
419}
420
421
422/*
423 * Soak up buffer descriptors that have been sent.
424 * Note that a buffer descriptor can't be retired as soon as it becomes
425 * ready. The MPC860 manual (MPC860UM/AD 07/98 Rev.1) and the MPC821
426 * manual state that, "If an Ethernet frame is made up of multiple
427 * buffers, the user should not reuse the first buffer descriptor until
428 * the last buffer descriptor of the frame has had its ready bit cleared
429 * by the CPM".
430 */
431static void
432m8xx_Enet_retire_tx_bd (struct m8xx_enet_struct *sc)
433{
434  uint16_t   status;
435  int i;
436  int nRetired;
437  struct mbuf *m, *n;
438
439  i = sc->txBdTail;
440  nRetired = 0;
441  while ((sc->txBdActiveCount != 0)
442         &&  (((status = (sc->txBdBase + i)->status) & M8xx_BD_READY) == 0)) {
443    /*
444     * See if anything went wrong
445     */
446    if (status & (M8xx_BD_DEFER |
447                  M8xx_BD_HEARTBEAT |
448                  M8xx_BD_LATE_COLLISION |
449                  M8xx_BD_RETRY_LIMIT |
450                  M8xx_BD_UNDERRUN |
451                  M8xx_BD_CARRIER_LOST)) {
452      /*
453       * Check for errors which stop the transmitter.
454       */
455      if (status & (M8xx_BD_LATE_COLLISION |
456                    M8xx_BD_RETRY_LIMIT |
457                    M8xx_BD_UNDERRUN)) {
458        if (status & M8xx_BD_LATE_COLLISION)
459          enet_driver[0].txLateCollision++;
460        if (status & M8xx_BD_RETRY_LIMIT)
461          enet_driver[0].txRetryLimit++;
462        if (status & M8xx_BD_UNDERRUN)
463          enet_driver[0].txUnderrun++;
464
465        /*
466         * Restart the transmitter
467         */
468        m8xx_cp_execute_cmd (M8xx_CR_OP_RESTART_TX | M8xx_CR_CHAN_SCC1);
469      }
470      if (status & M8xx_BD_DEFER)
471        enet_driver[0].txDeferred++;
472      if (status & M8xx_BD_HEARTBEAT)
473        enet_driver[0].txHeartbeat++;
474      if (status & M8xx_BD_CARRIER_LOST)
475        enet_driver[0].txLostCarrier++;
476    }
477    nRetired++;
478    if (status & M8xx_BD_LAST) {
479      /*
480       * A full frame has been transmitted.
481       * Free all the associated buffer descriptors.
482       */
483      sc->txBdActiveCount -= nRetired;
484      while (nRetired) {
485        nRetired--;
486        m = sc->txMbuf[sc->txBdTail];
487        MFREE (m, n);
488        if (++sc->txBdTail == sc->txBdCount)
489          sc->txBdTail = 0;
490      }
491    }
492    if (++i == sc->txBdCount)
493      i = 0;
494  }
495}
496
497/*
498 * reader task
499 */
500static void
501scc_rxDaemon (void *arg)
502{
503  struct m8xx_enet_struct *sc = (struct m8xx_enet_struct *)arg;
504  struct ifnet *ifp = &sc->arpcom.ac_if;
505  struct mbuf *m;
506  uint16_t   status;
507  m8xxBufferDescriptor_t *rxBd;
508  int rxBdIndex;
509
510  /*
511   * Allocate space for incoming packets and start reception
512   */
513  for (rxBdIndex = 0 ; ;) {
514    rxBd = sc->rxBdBase + rxBdIndex;
515    MGETHDR (m, M_WAIT, MT_DATA);
516    MCLGET (m, M_WAIT);
517    m->m_pkthdr.rcvif = ifp;
518    sc->rxMbuf[rxBdIndex] = m;
519    rxBd->buffer = mtod (m, void *);
520    rxBd->status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT;
521    if (++rxBdIndex == sc->rxBdCount) {
522      rxBd->status |= M8xx_BD_WRAP;
523      break;
524    }
525  }
526
527  /*
528   * Input packet handling loop
529   */
530  rxBdIndex = 0;
531  for (;;) {
532    rxBd = sc->rxBdBase + rxBdIndex;
533
534    /*
535     * Wait for packet if there's not one ready
536     */
537    if ((status = rxBd->status) & M8xx_BD_EMPTY) {
538      /*
539       * Clear old events
540       */
541      m8xx.scc1.scce = 0x8;
542
543      /*
544       * Wait for packet
545       * Note that the buffer descriptor is checked
546       * *before* the event wait -- this catches the
547       * possibility that a packet arrived between the
548       * `if' above, and the clearing of the event register.
549       */
550      while ((status = rxBd->status) & M8xx_BD_EMPTY) {
551        rtems_event_set events;
552
553        /*
554         * Unmask RXF (Full frame received) event
555         */
556        m8xx.scc1.sccm |= 0x8;
557
558        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
559                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
560                                    RTEMS_NO_TIMEOUT,
561                                    &events);
562      }
563    }
564
565    /*
566     * Check that packet is valid
567     */
568    if ((status & (M8xx_BD_LAST |
569                   M8xx_BD_FIRST_IN_FRAME |
570                   M8xx_BD_LONG |
571                   M8xx_BD_NONALIGNED |
572                   M8xx_BD_SHORT |
573                   M8xx_BD_CRC_ERROR |
574                   M8xx_BD_OVERRUN |
575                   M8xx_BD_COLLISION)) ==
576        (M8xx_BD_LAST |
577         M8xx_BD_FIRST_IN_FRAME)) {
578      /*
579       * Pass the packet up the chain.
580       * FIXME: Packet filtering hook could be done here.
581       */
582      struct ether_header *eh;
583
584      /*
585       * Invalidate the buffer for this descriptor
586       */
587      rtems_cache_invalidate_multiple_data_lines((const void *)rxBd->buffer, rxBd->length);
588
589      m = sc->rxMbuf[rxBdIndex];
590      m->m_len = m->m_pkthdr.len = rxBd->length -
591        sizeof(uint32_t) -
592        sizeof(struct ether_header);
593      eh = mtod (m, struct ether_header *);
594      m->m_data += sizeof(struct ether_header);
595      ether_input (ifp, eh, m);
596
597      /*
598       * Allocate a new mbuf
599       */
600      MGETHDR (m, M_WAIT, MT_DATA);
601      MCLGET (m, M_WAIT);
602      m->m_pkthdr.rcvif = ifp;
603      sc->rxMbuf[rxBdIndex] = m;
604      rxBd->buffer = mtod (m, void *);
605    }
606    else {
607      /*
608       * Something went wrong with the reception
609       */
610      if (!(status & M8xx_BD_LAST))
611        sc->rxNotLast++;
612      if (!(status & M8xx_BD_FIRST_IN_FRAME))
613        sc->rxNotFirst++;
614      if (status & M8xx_BD_LONG)
615        sc->rxGiant++;
616      if (status & M8xx_BD_NONALIGNED)
617        sc->rxNonOctet++;
618      if (status & M8xx_BD_SHORT)
619        sc->rxRunt++;
620      if (status & M8xx_BD_CRC_ERROR)
621        sc->rxBadCRC++;
622      if (status & M8xx_BD_OVERRUN)
623        sc->rxOverrun++;
624      if (status & M8xx_BD_COLLISION)
625        sc->rxCollision++;
626    }
627
628    /*
629     * Reenable the buffer descriptor
630     */
631    rxBd->status = (status & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT)) |
632      M8xx_BD_EMPTY;
633
634    /*
635     * Move to next buffer descriptor
636     */
637    if (++rxBdIndex == sc->rxBdCount)
638      rxBdIndex = 0;
639  }
640}
641
642
643static void
644scc_sendpacket (struct ifnet *ifp, struct mbuf *m)
645{
646  struct m8xx_enet_struct *sc = ifp->if_softc;
647  volatile m8xxBufferDescriptor_t *firstTxBd, *txBd;
648  struct mbuf *l = NULL;
649  uint16_t   status;
650  int nAdded;
651
652  /*
653   * Free up buffer descriptors
654   */
655  m8xx_Enet_retire_tx_bd (sc);
656
657  /*
658   * Set up the transmit buffer descriptors.
659   * No need to pad out short packets since the
660   * hardware takes care of that automatically.
661   * No need to copy the packet to a contiguous buffer
662   * since the hardware is capable of scatter/gather DMA.
663   */
664  nAdded = 0;
665  txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
666  for (;;) {
667    /*
668     * Wait for buffer descriptor to become available.
669     */
670    if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
671      /*
672       * Clear old events
673       */
674      m8xx.scc1.scce = 0x12;
675
676      /*
677       * Wait for buffer descriptor to become available.
678       * Note that the buffer descriptors are checked
679       * *before* * entering the wait loop -- this catches
680       * the possibility that a buffer descriptor became
681       * available between the `if' above, and the clearing
682       * of the event register.
683       * This is to catch the case where the transmitter
684       * stops in the middle of a frame -- and only the
685       * last buffer descriptor in a frame can generate
686       * an interrupt.
687       */
688      m8xx_Enet_retire_tx_bd (sc);
689      while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
690        rtems_event_set events;
691
692        /*
693         * Unmask TXB (buffer transmitted) and
694         * TXE (transmitter error) events.
695         */
696        m8xx.scc1.sccm |= 0x12;
697        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
698                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
699                                    RTEMS_NO_TIMEOUT,
700                                    &events);
701        m8xx_Enet_retire_tx_bd (sc);
702      }
703    }
704
705    /*
706     * Don't set the READY flag till the
707     * whole packet has been readied.
708     */
709    status = nAdded ? M8xx_BD_READY : 0;
710
711    /*
712     *  FIXME: Why not deal with empty mbufs at at higher level?
713     * The IP fragmentation routine in ip_output
714     * can produce packet fragments with zero length.
715     * I think that ip_output should be changed to get
716     * rid of these zero-length mbufs, but for now,
717     * I'll deal with them here.
718     */
719    if (m->m_len) {
720      /*
721       * Fill in the buffer descriptor
722       */
723      txBd->buffer = mtod (m, void *);
724      txBd->length = m->m_len;
725
726      /*
727       * Flush the buffer for this descriptor
728       */
729      rtems_cache_flush_multiple_data_lines((const void *)txBd->buffer, txBd->length);
730
731      sc->txMbuf[sc->txBdHead] = m;
732      nAdded++;
733      if (++sc->txBdHead == sc->txBdCount) {
734        status |= M8xx_BD_WRAP;
735        sc->txBdHead = 0;
736      }
737      l = m;
738      m = m->m_next;
739    }
740    else {
741      /*
742       * Just toss empty mbufs
743       */
744      struct mbuf *n;
745      MFREE (m, n);
746      m = n;
747      if (l != NULL)
748        l->m_next = m;
749    }
750
751    /*
752     * Set the transmit buffer status.
753     * Break out of the loop if this mbuf is the last in the frame.
754     */
755    if (m == NULL) {
756      if (nAdded) {
757        status |= M8xx_BD_PAD | M8xx_BD_LAST | M8xx_BD_TX_CRC | M8xx_BD_INTERRUPT;
758        txBd->status = status;
759        firstTxBd->status |= M8xx_BD_READY;
760        sc->txBdActiveCount += nAdded;
761      }
762      break;
763    }
764    txBd->status = status;
765    txBd = sc->txBdBase + sc->txBdHead;
766  }
767}
768
769
770/*
771 * Driver transmit daemon
772 */
773void
774scc_txDaemon (void *arg)
775{
776  struct m8xx_enet_struct *sc = (struct m8xx_enet_struct *)arg;
777  struct ifnet *ifp = &sc->arpcom.ac_if;
778  struct mbuf *m;
779  rtems_event_set events;
780
781  for (;;) {
782    /*
783     * Wait for packet
784     */
785    rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
786
787    /*
788     * Send packets till queue is empty
789     */
790    for (;;) {
791      /*
792       * Get the next mbuf chain to transmit.
793       */
794      IF_DEQUEUE(&ifp->if_snd, m);
795      if (!m)
796        break;
797      scc_sendpacket (ifp, m);
798    }
799    ifp->if_flags &= ~IFF_OACTIVE;
800  }
801}
802
803
804/*
805 * Send packet (caller provides header).
806 */
807static void
808m8xx_enet_start (struct ifnet *ifp)
809{
810  struct m8xx_enet_struct *sc = ifp->if_softc;
811
812  rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
813  ifp->if_flags |= IFF_OACTIVE;
814}
815
816/*
817 * Initialize and start the device
818 */
819static void
820scc_init (void *arg)
821{
822  struct m8xx_enet_struct *sc = arg;
823  struct ifnet *ifp = &sc->arpcom.ac_if;
824
825  if (sc->txDaemonTid == 0) {
826
827    /*
828     * Set up SCC hardware
829     */
830    m8xx_enet_initialize (sc);
831
832    /*
833     * Start driver tasks
834     */
835    sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
836    sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
837
838  }
839
840  /*
841   * Set flags appropriately
842   */
843  if (ifp->if_flags & IFF_PROMISC)
844    m8xx.scc1.psmr |= 0x200;
845  else
846    m8xx.scc1.psmr &= ~0x200;
847
848  /*
849   * Tell the world that we're running.
850   */
851  ifp->if_flags |= IFF_RUNNING;
852
853  /*
854   * Enable receiver and transmitter
855   */
856  m8xx.scc1.gsmr_l |= 0x30;
857}
858
859
860/*
861 * Stop the device
862 */
863static void
864scc_stop (struct m8xx_enet_struct *sc)
865{
866  struct ifnet *ifp = &sc->arpcom.ac_if;
867
868  ifp->if_flags &= ~IFF_RUNNING;
869
870  /*
871   * Shut down receiver and transmitter
872   */
873  m8xx.scc1.gsmr_l &= ~0x30;
874}
875
876
877/*
878 * Show interface statistics
879 */
880static void
881enet_stats (struct m8xx_enet_struct *sc)
882{
883  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
884  printf ("       Not First:%-8lu", sc->rxNotFirst);
885  printf ("        Not Last:%-8lu\n", sc->rxNotLast);
886  printf ("              Giant:%-8lu", sc->rxGiant);
887  printf ("            Runt:%-8lu", sc->rxRunt);
888  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
889  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
890  printf ("         Overrun:%-8lu", sc->rxOverrun);
891  printf ("       Collision:%-8lu\n", sc->rxCollision);
892  printf ("          Discarded:%-8lu\n", (unsigned long)m8xx.scc1p.un.ethernet.disfc);
893
894  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
895  printf ("        Deferred:%-8lu", sc->txDeferred);
896  printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
897  printf ("         No Carrier:%-8lu", sc->txLostCarrier);
898  printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
899  printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
900  printf ("           Underrun:%-8lu", sc->txUnderrun);
901  printf (" Raw output wait:%-8lu\n", sc->txRawWait);
902}
903
904/*
905 * Driver ioctl handler
906 */
907static int
908scc_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
909{
910  struct m8xx_enet_struct *sc = ifp->if_softc;
911  int error = 0;
912
913  switch (command) {
914  case SIOCGIFADDR:
915  case SIOCSIFADDR:
916    ether_ioctl (ifp, command, data);
917    break;
918
919  case SIOCSIFFLAGS:
920    switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
921    case IFF_RUNNING:
922      scc_stop (sc);
923      break;
924
925    case IFF_UP:
926      scc_init (sc);
927      break;
928
929    case IFF_UP | IFF_RUNNING:
930      scc_stop (sc);
931      scc_init (sc);
932      break;
933
934    default:
935      break;
936    }
937    break;
938
939  case SIO_RTEMS_SHOW_STATS:
940    enet_stats (sc);
941    break;
942
943    /*
944     * FIXME: All sorts of multicast commands need to be added here!
945     */
946  default:
947    error = EINVAL;
948    break;
949  }
950  return error;
951}
952
953
954/*
955 * Attach an SCC driver to the system
956 */
957int
958rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config)
959{
960  struct m8xx_enet_struct *sc;
961  struct ifnet *ifp;
962  int mtu;
963  int unitNumber;
964  char *unitName;
965  static const uint8_t maczero[] ={0,0,0,0,0,0};
966  /*
967   * Parse driver name
968   */
969  if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
970    return 0;
971
972  /*
973   * Is driver free?
974   */
975  if ((unitNumber <= 0) || (unitNumber > NIFACES)) {
976    printf ("Bad SCC unit number.\n");
977    return 0;
978  }
979  sc = &enet_driver[unitNumber - 1];
980  ifp = &sc->arpcom.ac_if;
981  if (ifp->if_softc != NULL) {
982    printf ("Driver already in use.\n");
983    return 0;
984  }
985
986  /*
987   * Process options
988   */
989
990  /*
991   * MAC address: try to fetch it from config, else from TQMMon, else panic
992   */
993  if (config->hardware_address) {
994    memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
995  }
996#ifdef BSP_HAS_TQMMON
997  else if(0 != memcmp(maczero,TQM_BD_INFO.eth_addr,ETHER_ADDR_LEN)) {
998    memcpy (sc->arpcom.ac_enaddr, TQM_BD_INFO.eth_addr, ETHER_ADDR_LEN);
999  }
1000#endif
1001  else {
1002    /* There is no ethernet address provided, so it could be read
1003     * from the Ethernet protocol block of SCC1 in DPRAM.
1004     */
1005    rtems_panic("No Ethernet address specified!\n");
1006  }
1007
1008  if (config->mtu)
1009    mtu = config->mtu;
1010  else
1011    mtu = ETHERMTU;
1012  if (config->rbuf_count)
1013    sc->rxBdCount = config->rbuf_count;
1014  else
1015    sc->rxBdCount = RX_BUF_COUNT;
1016  if (config->xbuf_count)
1017    sc->txBdCount = config->xbuf_count;
1018  else
1019    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1020  sc->acceptBroadcast = !config->ignore_broadcast;
1021
1022  /*
1023   * Set up network interface values
1024   */
1025  ifp->if_softc = sc;
1026  ifp->if_unit = unitNumber;
1027  ifp->if_name = unitName;
1028  ifp->if_mtu = mtu;
1029  ifp->if_init = scc_init;
1030  ifp->if_ioctl = scc_ioctl;
1031  ifp->if_start = m8xx_enet_start;
1032  ifp->if_output = ether_output;
1033  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1034  if (ifp->if_snd.ifq_maxlen == 0)
1035    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1036
1037  /*
1038   * Attach the interface
1039   */
1040  if_attach (ifp);
1041  ether_ifattach (ifp);
1042  return 1;
1043};
1044
1045int
1046rtems_scc_enet_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
1047{
1048  return rtems_scc1_driver_attach(config);
1049}
Note: See TracBrowser for help on using the repository browser.