source: rtems/c/src/lib/libbsp/powerpc/mpc8260ads/network/network.c @ 00d8424e

4.104.114.84.95
Last change on this file since 00d8424e was 00d8424e, checked in by Jennifer Averett <Jennifer.Averett@…>, on 04/15/05 at 18:05:34

2005-04-15 Jennifer Averett <jennifer.averett@…>

PR 779/bsp

  • clock/p_clock.c, irq/irq.c, irq/irq.h, irq/irq_init.c, network/network.c: add parameter to new exception interrupt handlers in powerpc bsps
  • Property mode set to 100644
File size: 23.9 KB
RevLine 
[5edbffe]1/*
2 * RTEMS/TCPIP driver for MPC8260 SCC
3 *
4 * Modified for MPC8260 by Andy Dachs <a.dachs@sstl.co.uk>
5 * Surrey Satellite Technology Limited
6 *
7 *   On the ADS board the ethernet interface is connected to FCC2
8 *   but in my application I want TCP over HDLC (see README)
9 *   so will use SCC3 as the network interface. I have other plans
10 *   for the FCCs so am unlikely to add true ethernet support to
11 *   this BSP.  Contributions welcome!
12 *
13 * Modified for MPC860 by Jay Monkman (jmonkman@frasca.com)
14 *
15 *  This supports ethernet on either SCC1 or the FEC of the MPC860T.
16 *  Right now, we only do 10 Mbps, even with the FEC. The function
17 *  rtems_m860_enet_driver_attach determines which one to use. Currently,
18 *  only one may be used at a time.
19 *
20 * W. Eric Norum
21 * Saskatchewan Accelerator Laboratory
22 * University of Saskatchewan
23 * Saskatoon, Saskatchewan, CANADA
24 * eric@skatter.usask.ca
25 *
26 *  $Id$
27 */
28#include <bsp.h>
29#include <bsp/irq.h>
30#include <mpc8260.h>
31#include <mpc8260/cpm.h>
32#include <stdio.h>
33#include <rtems/error.h>
34#include <rtems/rtems_bsdnet.h>
[1628414]35#include <rtems/bspIo.h>
[5edbffe]36
37#include <sys/param.h>
38#include <sys/mbuf.h>
39#include <sys/socket.h>
40#include <sys/sockio.h>
[888bc77]41#include <sys/errno.h>
[5edbffe]42
43#include <net/if.h>
44
45#include <netinet/in.h>
46#include <netinet/if_ether.h>
47
48#include "if_hdlcsubr.h"
49
50/*
51 * Number of interfaces supported by this driver
52 */
53#define NIFACES 1
54
55/*
56 * Default number of buffer descriptors set aside for this driver.
57 * The number of transmit buffer descriptors has to be quite large
58 * since a single frame often uses four or more buffer descriptors.
59 */
60#define RX_BUF_COUNT     32
61#define TX_BUF_COUNT     8
62#define TX_BD_PER_BUF    4
63
64#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
65
66extern void m8xx_dump_brgs( void );
67
68/*
69 * RTEMS event used by interrupt handler to signal daemons.
70 * This must *not* be the same event used by the TCP/IP task synchronization.
71 */
72#define INTERRUPT_EVENT RTEMS_EVENT_1
73
74/*
75 * RTEMS event used to start transmit daemon.
76 * This must not be the same as INTERRUPT_EVENT.
77 */
78#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
79
80/*
81 * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
82 * Round off to nearest multiple of RBUF_ALIGN.
83 */
84#define MAX_MTU_SIZE    1518
85/*#define MAX_MTU_SIZE  2050*/
86#define RBUF_ALIGN      4
87#define RBUF_SIZE       ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
88
89#if (MCLBYTES < RBUF_SIZE)
90# error "Driver must have MCLBYTES > RBUF_SIZE"
91#endif
92
93/*
94 * Per-device data
95 */
96struct m8260_hdlc_struct {
97        struct ifnet            ac_if;
98        struct mbuf             **rxMbuf;
99        struct mbuf             **txMbuf;
100        int                     acceptBroadcast;
101        int                     rxBdCount;
102        int                     txBdCount;
103        int                     txBdHead;
104        int                     txBdTail;
105        int                     txBdActiveCount;
106        m8260BufferDescriptor_t  *rxBdBase;
107        m8260BufferDescriptor_t  *txBdBase;
108        rtems_id                rxDaemonTid;
109        rtems_id                txDaemonTid;
110
111        /*
112         * Statistics
113         */
114        unsigned long   rxNotFirst;
115        unsigned long   rxNotLast;
116        unsigned long   rxInterrupts;
117        unsigned long   rxGiant;
118        unsigned long   rxNonOctet;
119        unsigned long   rxAbort;
120        unsigned long   rxBadCRC;
121        unsigned long   rxOverrun;
122        unsigned long   rxLostCarrier;
123        unsigned long   txInterrupts;
124        unsigned long   txUnderrun;
125        unsigned long   txLostCarrier;
126        unsigned long   txRawWait;
127};
128static struct m8260_hdlc_struct hdlc_driver[NIFACES];
129
130static void  m8xx_scc3_hdlc_on(const rtems_irq_connect_data* ptr)
131{
132}
133
134static void  m8xx_scc3_hdlc_off(const rtems_irq_connect_data* ptr)
135{
136  /*
137   * Please put relevant code there
138   */
139}
140
141static int  m8xx_scc3_hdlc_isOn(const rtems_irq_connect_data* ptr)
142{
143  return BSP_irq_enabled_at_cpm (ptr->name);
144}
145
146/*
147 * SCC interrupt handler
148 * TBD: Can we work out which SCC generated the interrupt from the
149 *      value of v? If so we can use the same handler for multiple
150 *      SCCs.
151 */
152static void
[00d8424e]153m8xx_scc3_interrupt_handler (rtems_irq_hdl_param unused)
[5edbffe]154{
155  /*
156   * Frame received?
157   */
158  if ((m8260.scc3.sccm & M8260_SCCE_RXF) &&
159      (m8260.scc3.scce & M8260_SCCE_RXF) ) {
160    m8260.scc3.scce = M8260_SCCE_RXF;
161/*    m8260.scc3.sccm &= ~M8260_SCCE_RXF; */
162    hdlc_driver[0].rxInterrupts++;
163    rtems_event_send (hdlc_driver[0].rxDaemonTid, INTERRUPT_EVENT);
164/*
165    printk( "Rx " );
166*/
167  }
168
169  /*
170   * Buffer transmitted or transmitter error?
171   */
172  if ((m8260.scc3.sccm & (M8260_SCCE_TX | M8260_SCCE_TXE) ) &&
173      (m8260.scc3.scce & (M8260_SCCE_TX | M8260_SCCE_TXE) )) {
174    m8260.scc3.scce = M8260_SCCE_TX | M8260_SCCE_TXE;
175/*    m8260.scc3.sccm &= ~(M8260_SCCE_TX | M8260_SCCE_TXE); */
176    hdlc_driver[0].txInterrupts++;
177    rtems_event_send (hdlc_driver[0].txDaemonTid, INTERRUPT_EVENT);
178/*
179    printk( "Tx " );
180*/
181  }
182
183#if 0
184  m8260.sipnr_l = M8260_SIMASK_SCC3; /* Clear SCC3 interrupt-in-service bit */
185#endif
186}
187
188static rtems_irq_connect_data hdlcSCC3IrqData = {
189  BSP_CPM_IRQ_SCC3,
190  (rtems_irq_hdl) m8xx_scc3_interrupt_handler,
[00d8424e]191  NULL,
[5edbffe]192  (rtems_irq_enable) m8xx_scc3_hdlc_on,
193  (rtems_irq_disable) m8xx_scc3_hdlc_off,
194  (rtems_irq_is_enabled)m8xx_scc3_hdlc_isOn
195};
196
197/*
198 * Initialize the SCC hardware
199 * Configure I/O ports for SCC3
200 * Internal Tx clock, External Rx clock
201 */
202static void
203m8260_scc_initialize_hardware (struct m8260_hdlc_struct *sc)
204{
205  int i;
206  int brg;
207
208/*
209  unsigned char *hwaddr;
210*/
211  rtems_status_code status;
212/*
213  rtems_isr_entry old_handler;
214*/
215
216  /* RxD PB14 */
217  m8260.pparb |=  0x00020000;
218  m8260.psorb &= ~0x00020000;
219  m8260.pdirb &= ~0x00020000;
220
221  /* RxC (CLK5) PC27 */
222  m8260.pparc |=  0x00000010;
223  m8260.psorc &= ~0x00000010;
224  m8260.pdirc &= ~0x00000010;
225
226  /* TxD PD24 and TxC PD10 (BRG4) */
227  m8260.ppard |=  0x00200080;
228  m8260.psord |=  0x00200000;
229  m8260.psord &= ~0x00000080;
230  m8260.pdird |=  0x00200080;
231
232  /* External Rx Clock from CLK5 */
233  if( m8xx_get_clk( M8xx_CLK_5 ) == -1 )
234    printk( "Error allocating CLK5 for network device.\n" );
235  else
236    m8260.cmxscr |= 0x00002000;
237
238  /* Internal Tx Clock from BRG4 */
239  if( (brg = m8xx_get_brg(M8xx_BRG_4, 8000000 )) == -1 )
240    printk( "Error allocating BRG for network device\n" );
241  else
242    m8260.cmxscr |= ((unsigned)brg << 8);
243
244  /*
245   * Allocate mbuf pointers
246   */
[6128a4a]247  sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
[5edbffe]248                       M_MBUF, M_NOWAIT);
[6128a4a]249  sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
[5edbffe]250                       M_MBUF, M_NOWAIT);
251  if (!sc->rxMbuf || !sc->txMbuf)
252    rtems_panic ("No memory for mbuf pointers");
[6128a4a]253
[5edbffe]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
260  m8260.scc3p.rbase = (char *)sc->rxBdBase - (char *)&m8260;
261  m8260.scc3p.tbase = (char *)sc->txBdBase - (char *)&m8260;
[6128a4a]262
[5edbffe]263  /*
264   * Send "Init parameters" command
265   */
266
267  m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC3 );
268
269  /*
270   * Set receive and transmit function codes
271   */
272  m8260.scc3p.rfcr = M8260_RFCR_MOT | M8260_RFCR_60X_BUS;
273  m8260.scc3p.tfcr = M8260_TFCR_MOT | M8260_TFCR_60X_BUS;
[6128a4a]274
[5edbffe]275  /*
276   * Set maximum receive buffer length
277   */
278  m8260.scc3p.mrblr = RBUF_SIZE;
279
280  m8260.scc3p.un.hdlc.c_mask = 0xF0B8;
281  m8260.scc3p.un.hdlc.c_pres = 0xFFFF;
282  m8260.scc3p.un.hdlc.disfc  = 0;
283  m8260.scc3p.un.hdlc.crcec  = 0;
284  m8260.scc3p.un.hdlc.abtsc  = 0;
285  m8260.scc3p.un.hdlc.nmarc  = 0;
286  m8260.scc3p.un.hdlc.retrc  = 0;
287  m8260.scc3p.un.hdlc.rfthr  = 1;
288  m8260.scc3p.un.hdlc.mflr   = RBUF_SIZE;
289
290  m8260.scc3p.un.hdlc.hmask  = 0x0000;  /* promiscuous */
291
292  m8260.scc3p.un.hdlc.haddr1 = 0xFFFF;  /* Broadcast address */
293  m8260.scc3p.un.hdlc.haddr2 = 0xFFFF;  /* Station address */
294  m8260.scc3p.un.hdlc.haddr3 = 0xFFFF;  /* Dummy */
295  m8260.scc3p.un.hdlc.haddr4 = 0xFFFF;  /* Dummy */
296
297  /*
298   * Send "Init parameters" command
299   */
300/*
301  m8xx_cp_execute_cmd (M8260_CR_OP_INIT_RX_TX | M8260_CR_SCC3 );
302*/
303
304  /*
305   * Set up receive buffer descriptors
306   */
307  for (i = 0 ; i < sc->rxBdCount ; i++) {
308    (sc->rxBdBase + i)->status = 0;
309  }
310
311  /*
312   * Set up transmit buffer descriptors
313   */
314  for (i = 0 ; i < sc->txBdCount ; i++) {
315    (sc->txBdBase + i)->status = 0;
316    sc->txMbuf[i] = NULL;
317  }
318  sc->txBdHead = sc->txBdTail = 0;
319  sc->txBdActiveCount = 0;
320
321  m8260.scc3.sccm = 0;     /* No interrupts unmasked till necessary */
322
323  /*
324   * Clear any outstanding events
325   */
326  m8260.scc3.scce = 0xFFFF;
327
328  /*
329   * Set up interrupts
330   */
331  status = BSP_install_rtems_irq_handler (&hdlcSCC3IrqData);
332/*
333  printk( "status = %d, Success = %d\n", status, RTEMS_SUCCESSFUL );
334*/
335  if (status != 1 /*RTEMS_SUCCESSFUL*/ ) {
336    rtems_panic ("Can't attach M8260 SCC3 interrupt handler: %s\n",
337                 rtems_status_text (status));
338  }
339  m8260.scc3.sccm = 0;     /* No interrupts unmasked till necessary */
340
341#if 0
342  /*
343   * Set up interrupts
344   */
345  status = rtems_interrupt_catch (m8260_scc3_interrupt_handler,
346                                  PPC_IRQ_CPM_SCC3,
347                                  &old_handler);
348  if (status != RTEMS_SUCCESSFUL) {
349    rtems_panic ("Can't attach M8260 SCC3 interrupt handler: %s\n",
350                 rtems_status_text (status));
351  }
352
353  m8260.sipnr_l = M8260_SIMASK_SCC3; /* clear pending event */
354  m8260.simr_l |= M8260_SIMASK_SCC3; /* Enable SCC interrupt */
355
356#endif
357
358  m8260.scc3.gsmr_h  = 0;
359  m8260.scc3.gsmr_l  = 0x10000000;
360  m8260.scc3.dsr     = 0x7E7E;  /* flag character */
361  m8260.scc3.psmr    = 0x2000;  /* 2 flags between Tx'd frames */
362
363/*  printk("scc3 init\n" ); */
364
365  m8260.scc3.gsmr_l |=  0x00000030;  /* Set ENR and ENT to enable Rx and Tx */
366
367}
368
369/*
370 * Soak up buffer descriptors that have been sent
371 * Note that a buffer descriptor can't be retired as soon as it becomes
372 * ready.  The MC68360 Errata (May 96) says that, "If an Ethernet frame is
373 *  made up of multiple buffers, the user should not reuse the first buffer
374 * descriptor until the last buffer descriptor of the frame has had its
375 * ready bit cleared by the CPM".
376 */
377static void
378m8260Enet_retire_tx_bd (struct m8260_hdlc_struct *sc)
379{
[2a832d8]380  uint16_t         status;
[5edbffe]381  int i;
382  int nRetired;
383  struct mbuf *m, *n;
[6128a4a]384
[5edbffe]385  i = sc->txBdTail;
386  nRetired = 0;
387  while ((sc->txBdActiveCount != 0)
388         &&  (((status = (sc->txBdBase + i)->status) & M8260_BD_READY) == 0)) {
389    /*
390     * See if anything went wrong
391     */
392    if (status & (M8260_BD_UNDERRUN |
393                  M8260_BD_CTS_LOST)) {
394      /*
395       * Check for errors which stop the transmitter.
396       */
397      if( status & M8260_BD_UNDERRUN ) {
398          hdlc_driver[0].txUnderrun++;
[6128a4a]399
[5edbffe]400        /*
401         * Restart the transmitter
402         */
403        /* FIXME: this should get executed only if using the SCC */
404        m8xx_cp_execute_cmd (M8260_CR_OP_RESTART_TX | M8260_CR_SCC3);
405      }
406      if (status & M8260_BD_CTS_LOST)
407        hdlc_driver[0].txLostCarrier++;
408    }
409    nRetired++;
410    if (status & M8260_BD_LAST) {
411      /*
412       * A full frame has been transmitted.
413       * Free all the associated buffer descriptors.
414       */
415      sc->txBdActiveCount -= nRetired;
416      while (nRetired) {
417        nRetired--;
418        m = sc->txMbuf[sc->txBdTail];
419        MFREE (m, n);
420        if (++sc->txBdTail == sc->txBdCount)
421          sc->txBdTail = 0;
422      }
423    }
424    if (++i == sc->txBdCount)
425      i = 0;
426  }
427}
428
429/*
430 * reader task
431 */
432static void
433scc_rxDaemon (void *arg)
434{
435  struct m8260_hdlc_struct *sc = (struct m8260_hdlc_struct *)arg;
436  struct ifnet *ifp = &sc->ac_if;
437  struct mbuf *m;
[2a832d8]438  uint16_t         status;
[5edbffe]439  m8260BufferDescriptor_t *rxBd;
440  int rxBdIndex;
[6128a4a]441
[5edbffe]442  /*
443   * Allocate space for incoming packets and start reception
444   */
445  for (rxBdIndex = 0 ; ;) {
446    rxBd = sc->rxBdBase + rxBdIndex;
447    MGETHDR (m, M_WAIT, MT_DATA);
448    MCLGET (m, M_WAIT);
449    m->m_pkthdr.rcvif = ifp;
450    sc->rxMbuf[rxBdIndex] = m;
451    rxBd->buffer = mtod (m, void *);
452    rxBd->status = M8260_BD_EMPTY | M8260_BD_INTERRUPT;
453    if (++rxBdIndex == sc->rxBdCount) {
454      rxBd->status |= M8260_BD_WRAP;
455      break;
456    }
457  }
458
459/*
460  m8260.scc3.sccm |= M8260_SCCE_RXF;
461*/
462
463  /*
464   * Input packet handling loop
465   */
466  rxBdIndex = 0;
467  for (;;) {
468    rxBd = sc->rxBdBase + rxBdIndex;
[6128a4a]469
[5edbffe]470    /*
471     * Wait for packet if there's not one ready
472     */
473    if ((status = rxBd->status) & M8260_BD_EMPTY) {
474      /*
475       * Clear old events
476       */
477
478      m8260.scc3.scce = M8260_SCCE_RXF;
479
480      /*
481       * Wait for packet
482       * Note that the buffer descriptor is checked
483       * *before* the event wait -- this catches the
484       * possibility that a packet arrived between the
485       * `if' above, and the clearing of the event register.
486       */
487      while ((status = rxBd->status) & M8260_BD_EMPTY) {
488        rtems_event_set events;
489
490        /*
491         * Unmask RXF (Full frame received) event
492         */
493        m8260.scc3.sccm |= M8260_SCCE_RXF;
494
495/*        printk( "Rxdwait "); */
[6128a4a]496
[5edbffe]497        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
498                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
499                                    RTEMS_NO_TIMEOUT,
500                                    &events);
501
502/*        printk( "Rxd " ); */
503      }
504    }
[6128a4a]505
[5edbffe]506    /*
507     * Check that packet is valid
508     */
509    if ((status & (M8260_BD_LAST |
510                   M8260_BD_FIRST_IN_FRAME |
511                   M8260_BD_LONG |
512                   M8260_BD_NONALIGNED |
513                   M8260_BD_ABORT |
514                   M8260_BD_CRC_ERROR |
515                   M8260_BD_OVERRUN /*|
516                   M8260_BD_CARRIER_LOST*/)) ==
517                   (M8260_BD_LAST |
518                   M8260_BD_FIRST_IN_FRAME ) ) {
519
520/*      printk( "RxV " ); */
521
522/*
523 * Invalidate the buffer for this descriptor
524 */
525
[37a25cf]526      rtems_cache_invalidate_multiple_data_lines((void *)rxBd->buffer, rxBd->length);
[5edbffe]527
528      m = sc->rxMbuf[rxBdIndex];
529
530      /* strip off HDLC CRC */
[2a832d8]531      m->m_len = m->m_pkthdr.len = rxBd->length - sizeof(uint16_t);
[5edbffe]532
533      hdlc_input( ifp, m );
534
535      /*
536       * Allocate a new mbuf
537       */
538      MGETHDR (m, M_WAIT, MT_DATA);
539      MCLGET (m, M_WAIT);
540      m->m_pkthdr.rcvif = ifp;
541      sc->rxMbuf[rxBdIndex] = m;
542      rxBd->buffer = mtod (m, void *);
543    }
544    else {
545      printk( "RxErr[%04X,%d]", status, rxBd->length );
546      /*
547       * Something went wrong with the reception
548       */
549      if (!(status & M8260_BD_LAST))
550        sc->rxNotLast++;
551      if (!(status & M8260_BD_FIRST_IN_FRAME))
552        sc->rxNotFirst++;
553
554      if (status & M8260_BD_LONG)
555        sc->rxGiant++;
556      if (status & M8260_BD_NONALIGNED)
557        sc->rxNonOctet++;
558      if (status & M8260_BD_ABORT)
559        sc->rxAbort++;
560      if (status & M8260_BD_CRC_ERROR)
561        sc->rxBadCRC++;
562      if (status & M8260_BD_OVERRUN)
563        sc->rxOverrun++;
564      if (status & M8260_BD_CARRIER_LOST)
565        sc->rxLostCarrier++;
566    }
[6128a4a]567
[5edbffe]568    /*
569     * Reenable the buffer descriptor
570     */
571    rxBd->status = (status & (M8260_BD_WRAP | M8260_BD_INTERRUPT)) |
572                    M8260_BD_EMPTY;
[6128a4a]573
[5edbffe]574    /*
575     * Move to next buffer descriptor
576     */
577    if (++rxBdIndex == sc->rxBdCount)
578      rxBdIndex = 0;
579  }
580}
581
582static void
583scc_sendpacket (struct ifnet *ifp, struct mbuf *m)
584{
585  struct m8260_hdlc_struct *sc = ifp->if_softc;
586  volatile m8260BufferDescriptor_t *firstTxBd, *txBd;
587  struct mbuf *l = NULL;
[2a832d8]588  uint16_t         status;
[5edbffe]589  int nAdded;
[6128a4a]590
[5edbffe]591  /*
592   * Free up buffer descriptors
593   */
594  m8260Enet_retire_tx_bd (sc);
[6128a4a]595
[5edbffe]596  /*
597   * Set up the transmit buffer descriptors.
598   * No need to pad out short packets since the
599   * hardware takes care of that automatically.
600   * No need to copy the packet to a contiguous buffer
601   * since the hardware is capable of scatter/gather DMA.
602   */
603  nAdded = 0;
604  txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
605
606/*
607  m8260.scc3.sccm |= (M8260_SCCE_TX | M8260_SCCE_TXE);
608*/
609
610  for (;;) {
611    /*
612     * Wait for buffer descriptor to become available.
613     */
614    if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
615      /*
616       * Clear old events
617       */
618      m8260.scc3.scce = M8260_SCCE_TX | M8260_SCCE_TXE;
[6128a4a]619
[5edbffe]620      /*
621       * Wait for buffer descriptor to become available.
622       * Note that the buffer descriptors are checked
623       * *before* * entering the wait loop -- this catches
624       * the possibility that a buffer descriptor became
625       * available between the `if' above, and the clearing
626       * of the event register.
627       * This is to catch the case where the transmitter
628       * stops in the middle of a frame -- and only the
629       * last buffer descriptor in a frame can generate
630       * an interrupt.
631       */
632      m8260Enet_retire_tx_bd (sc);
633      while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
634        rtems_event_set events;
[6128a4a]635
[5edbffe]636        /*
637         * Unmask TX (buffer transmitted) event
638         */
639        m8260.scc3.sccm |= (M8260_SCCE_TX | M8260_SCCE_TXE);
640
641        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
642                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
643                                    RTEMS_NO_TIMEOUT,
644                                    &events);
645        m8260Enet_retire_tx_bd (sc);
646      }
647    }
[6128a4a]648
[5edbffe]649    /*
650     * Don't set the READY flag till the
651     * whole packet has been readied.
652     */
653    status = nAdded ? M8260_BD_READY : 0;
[6128a4a]654
[5edbffe]655    /*
656     *  FIXME: Why not deal with empty mbufs at at higher level?
657     * The IP fragmentation routine in ip_output
658     * can produce packet fragments with zero length.
659     * I think that ip_output should be changed to get
660     * rid of these zero-length mbufs, but for now,
661     * I'll deal with them here.
662     */
663    if (m->m_len) {
664      /*
665       * Fill in the buffer descriptor
666       */
667
668      txBd->buffer = mtod (m, void *);
669      txBd->length = m->m_len;
670
671      /*
672       * Flush the buffer for this descriptor
673       */
674
[37a25cf]675      rtems_cache_flush_multiple_data_lines((void *)txBd->buffer, txBd->length);
[5edbffe]676
677/* throw off the header for Ethernet Emulation mode */
678/*
679      txBd->buffer = mtod (m, void *);
680      txBd->buffer += sizeof( struct ether_header ) + 2;
681      txBd->length = m->m_len - sizeof( struct ether_header ) - 2;
682*/
683      sc->txMbuf[sc->txBdHead] = m;
684      nAdded++;
685      if (++sc->txBdHead == sc->txBdCount) {
686        status |= M8260_BD_WRAP;
687        sc->txBdHead = 0;
688      }
689      l = m;
690      m = m->m_next;
691    }
692    else {
693      /*
694       * Just toss empty mbufs
695       */
696      struct mbuf *n;
697      MFREE (m, n);
698      m = n;
699      if (l != NULL)
700        l->m_next = m;
701    }
[6128a4a]702
[5edbffe]703    /*
704     * Set the transmit buffer status.
705     * Break out of the loop if this mbuf is the last in the frame.
706     */
707    if (m == NULL) {
708      if (nAdded) {
709        status |= M8260_BD_LAST | M8260_BD_TX_CRC | M8260_BD_INTERRUPT;
710        txBd->status = status;
711        firstTxBd->status |= M8260_BD_READY;
712        sc->txBdActiveCount += nAdded;
713      }
714      break;
715    }
716    txBd->status = status;
717    txBd = sc->txBdBase + sc->txBdHead;
718  }
719}
720
721/*
722 * Driver transmit daemon
723 */
724void
725scc_txDaemon (void *arg)
726{
727  struct m8260_hdlc_struct *sc = (struct m8260_hdlc_struct *)arg;
728  struct ifnet *ifp = &sc->ac_if;
729  struct mbuf *m;
730  rtems_event_set events;
[6128a4a]731
[5edbffe]732  for (;;) {
733    /*
734     * Wait for packet
735     */
736    rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
[6128a4a]737
[5edbffe]738    /*
739     * Send packets till queue is empty
740     */
741    for (;;) {
742      /*
743       * Get the next mbuf chain to transmit.
744       */
745      IF_DEQUEUE(&ifp->if_snd, m);
746      if (!m)
747        break;
748
749      scc_sendpacket (ifp, m);
750
751    }
752    ifp->if_flags &= ~IFF_OACTIVE;
753  }
754}
755
756/*
757 * Send packet (caller provides header).
758 */
759static void
760m8260_hdlc_start (struct ifnet *ifp)
761{
762  struct m8260_hdlc_struct *sc = ifp->if_softc;
[6128a4a]763
[5edbffe]764  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
765  ifp->if_flags |= IFF_OACTIVE;
766}
767
768/*
769 * Initialize and start the device
770 */
771static void
772scc_init (void *arg)
773{
774  struct m8260_hdlc_struct *sc = arg;
775  struct ifnet *ifp = &sc->ac_if;
[6128a4a]776
[5edbffe]777  if (sc->txDaemonTid == 0) {
[6128a4a]778
[5edbffe]779    /*
780     * Set up SCC hardware
781     */
782    m8260_scc_initialize_hardware (sc);
[6128a4a]783
[5edbffe]784    /*
785     * Start driver tasks
786     */
787    sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
788    sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
[6128a4a]789
[5edbffe]790  }
[6128a4a]791
[5edbffe]792#if 0
793  /*
794   * Set flags appropriately
795   */
796  if (ifp->if_flags & IFF_PROMISC)
797    m8260.scc3.psmr |= 0x200;
798  else
799    m8260.scc3.psmr &= ~0x200;
800#endif
801
802  /*
803   * Tell the world that we're running.
804   */
805  ifp->if_flags |= IFF_RUNNING;
[6128a4a]806
[5edbffe]807  /*
808   * Enable receiver and transmitter
809   */
810  m8260.scc3.gsmr_l |= 0x30;
811}
812
813/*
814 * Stop the device
815 */
816static void
817scc_stop (struct m8260_hdlc_struct *sc)
818{
819  struct ifnet *ifp = &sc->ac_if;
[6128a4a]820
[5edbffe]821  ifp->if_flags &= ~IFF_RUNNING;
[6128a4a]822
[5edbffe]823  /*
824   * Shut down receiver and transmitter
825   */
826  m8260.scc3.gsmr_l &= ~0x30;
827}
828
829/*
830 * Show interface statistics
831 */
832static void
833hdlc_stats (struct m8260_hdlc_struct *sc)
834{
835  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
836  printf ("              Giant:%-8lu", sc->rxGiant);
837  printf ("          Non-octet:%-8lu\n", sc->rxNonOctet);
838  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
839  printf ("            Overrun:%-8lu", sc->rxOverrun);
840  printf ("         No Carrier:%-8lu\n", sc->rxLostCarrier);
841  printf ("          Discarded:%-8lu\n", (unsigned long)m8260.scc3p.un.hdlc.disfc);
[6128a4a]842
[5edbffe]843  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
844  printf ("         No Carrier:%-8lu", sc->txLostCarrier);
845  printf ("           Underrun:%-8lu\n", sc->txUnderrun);
846  printf ("    Raw output wait:%-8lu\n", sc->txRawWait);
847}
848
849/*
850 * Driver ioctl handler
851 */
852static int
853scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
854{
855  struct m8260_hdlc_struct *sc = ifp->if_softc;
856  int error = 0;
[6128a4a]857
[5edbffe]858  switch (command) {
859  case SIOCGIFADDR:
860  case SIOCSIFADDR:
861    hdlc_ioctl (ifp, command, data);
862    break;
[6128a4a]863
[5edbffe]864  case SIOCSIFFLAGS:
865    switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
866    case IFF_RUNNING:
867      scc_stop (sc);
868      break;
[6128a4a]869
[5edbffe]870    case IFF_UP:
871      scc_init (sc);
872      break;
[6128a4a]873
[5edbffe]874    case IFF_UP | IFF_RUNNING:
875      scc_stop (sc);
876      scc_init (sc);
877      break;
[6128a4a]878
[5edbffe]879    default:
880      break;
881    }
882    break;
[6128a4a]883
[5edbffe]884  case SIO_RTEMS_SHOW_STATS:
885    hdlc_stats (sc);
886    break;
[6128a4a]887
[5edbffe]888    /*
889     * FIXME: All sorts of multicast commands need to be added here!
890     */
891  default:
892    error = EINVAL;
893    break;
894  }
895  return error;
896}
897
898/*
899 * Attach an SCC driver to the system
900 */
901int
902rtems_scc3_driver_attach (struct rtems_bsdnet_ifconfig *config)
903{
904  struct m8260_hdlc_struct *sc;
905  struct ifnet *ifp;
906  int mtu;
907  int i;
[6128a4a]908
[5edbffe]909  /*
910   * Find a free driver
911   */
912  for (i = 0 ; i < NIFACES ; i++) {
913    sc = &hdlc_driver[i];
914    ifp = &sc->ac_if;
915    if (ifp->if_softc == NULL)
916      break;
917  }
918  if (i >= NIFACES) {
919    printf ("Too many SCC drivers.\n");
920    return 0;
921  }
922
923#if 0
924  /*
925   * Process options
926   */
927
928  if (config->hardware_address) {
929    memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
930  }
931  else {
932    sc->arpcom.ac_enaddr[0] = 0x44;
933    sc->arpcom.ac_enaddr[1] = 0x22;
934    sc->arpcom.ac_enaddr[2] = 0x33;
935    sc->arpcom.ac_enaddr[3] = 0x33;
936    sc->arpcom.ac_enaddr[4] = 0x22;
937    sc->arpcom.ac_enaddr[5] = 0x44;
938  }
939#endif
940
941  if (config->mtu)
942    mtu = config->mtu;
943  else
944    mtu = ETHERMTU;
945  if (config->rbuf_count)
946    sc->rxBdCount = config->rbuf_count;
947  else
948    sc->rxBdCount = RX_BUF_COUNT;
949  if (config->xbuf_count)
950    sc->txBdCount = config->xbuf_count;
951  else
952    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
953  sc->acceptBroadcast = !config->ignore_broadcast;
[6128a4a]954
[5edbffe]955  /*
956   * Set up network interface values
957   */
958  ifp->if_softc = sc;
959  ifp->if_unit = i + 1;
960  ifp->if_name = "eth";
961  ifp->if_mtu = mtu;
962  ifp->if_init = scc_init;
963  ifp->if_ioctl = scc_ioctl;
964  ifp->if_start = m8260_hdlc_start;
965  ifp->if_output = hdlc_output;
966  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | /*IFF_PROMISC |*/ IFF_NOARP;
967  if (ifp->if_snd.ifq_maxlen == 0)
968    ifp->if_snd.ifq_maxlen = ifqmaxlen;
[6128a4a]969
[5edbffe]970  /*
971   * Attach the interface
972   */
973  if_attach (ifp);
974  hdlc_ifattach (ifp);
975  return 1;
976};
977
978int
979rtems_enet_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
980{
981  return rtems_scc3_driver_attach( config );
982
983/*
984  if ((m8260.fec.mii_data & 0xffff) == 0x2000) {
985    return rtems_fec_driver_attach(config);
986  }
987  else {
988    return rtems_scc1_driver_attach(config);
989  }
990*/
991}
Note: See TracBrowser for help on using the repository browser.