source: rtems/c/src/lib/libbsp/powerpc/tqm8xx/network/network_scc.c @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

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