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

5
Last change on this file since f3b29236 was 4c02385, checked in by Christian Mauderer <Christian.Mauderer@…>, on 06/24/16 at 06:52:48

libnetworking: Import current <arpa/inet.h>

Import the <arpa/inet.h> from current FreeBSD. Necessary due to changes
in <netinet/in.h>. Remove BSD hack from <arpa/inet.h>.

Clean up problems with htonl(). These functions are defined in
<arpa/inet.h>. This lead to some problems because they are defined in
<rtems/endian.h> too. Add NTOHL, ... to
<rtems/rtems_bsdnet_internal.h>.

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