source: rtems/c/src/lib/libcpu/powerpc/mpc83xx/network/tsec.c @ 42bf1b9

4.104.114.95
Last change on this file since 42bf1b9 was 42bf1b9, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 05/15/08 at 15:10:38

adapted gen83xx to new board

  • Property mode set to 100644
File size: 69.6 KB
RevLine 
[f610e83f]1/*===============================================================*\
2| Project: RTEMS support for MPC83xx                              |
3+-----------------------------------------------------------------+
4|                    Copyright (c) 2007                           |
5|                    Embedded Brains GmbH                         |
6|                    Obere Lagerstr. 30                           |
7|                    D-82178 Puchheim                             |
8|                    Germany                                      |
9|                    rtems@embedded-brains.de                     |
10+-----------------------------------------------------------------+
11| The license and distribution terms for this file may be         |
12| found in the file LICENSE in this distribution or at            |
13|                                                                 |
14| http://www.rtems.com/license/LICENSE.                           |
15|                                                                 |
16+-----------------------------------------------------------------+
17| this file contains the MPC83xx TSEC networking driver           |
18\*===============================================================*/
19/*
20 * this driver has the following HW assumptions:
21 * - PHY for TSEC1 uses address 0
22 * - PHY for TSEC2 uses address 1
23 * - PHY uses GMII for 1000Base-T and MII for the rest of the modes
24 */
25#include <stdlib.h>
26#include <bsp.h>
27#include <bsp/irq.h>
28#include <mpc83xx/mpc83xx.h>
29#include <mpc83xx/tsec.h>
30#include <rtems/error.h>
31#include <rtems/bspIo.h>
32#include <rtems/rtems_bsdnet.h>
33#include <rtems/rtems_mii_ioctl.h>
34#include <errno.h>
35
36#include <sys/param.h>
37#include <sys/socket.h>
38#include <sys/sockio.h>
39#include <sys/mbuf.h>
40#include <net/if.h>
41#include <net/if_arp.h>
42#include <netinet/in.h>
43#include <netinet/if_ether.h>
44#include <stdio.h>
45
46#define CLREVENT_IN_IRQ
47
48#define TSEC_WATCHDOG_TIMEOUT 5 /* check media every 5 seconds */
49
50/*
51 * Device data
52 */
53struct mpc83xx_tsec_struct {
54  struct arpcom           arpcom;
55  int                     acceptBroadcast;
56
57  /*
58   * HW links: (filled from rtems_bsdnet_ifconfig
59   */
60  m83xxTSEC_Registers_t  *reg_ptr;     /* pointer to TSEC register block */
61  int                    irq_num_tx;  /* tx irq number                  */
62  int                    irq_num_rx;  /* rx irq number                  */
63  int                    irq_num_err; /* error irq number               */
64 
65  /*
66   * BD management
67   */
68  int                     rxBdCount;
69  int                     txBdCount;
70  PQBufferDescriptor_t    *Rx_Frst_BD;
71  PQBufferDescriptor_t    *Rx_Last_BD;
72  PQBufferDescriptor_t    *Rx_NxtUsed_BD; /* First BD, which is in Use */
73  PQBufferDescriptor_t    *Rx_NxtFill_BD; /* BD to be filled next      */
74  struct mbuf             **Rx_mBuf_Ptr;  /* Storage for mbufs         */
75
76  PQBufferDescriptor_t    *Tx_Frst_BD;
77  PQBufferDescriptor_t    *Tx_Last_BD;
78  PQBufferDescriptor_t    *Tx_NxtUsed_BD; /* First BD, which is in Use */
79  PQBufferDescriptor_t    *Tx_NxtFill_BD; /* BD to be filled next      */
80  struct mbuf             **Tx_mBuf_Ptr;  /* Storage for mbufs         */
81  /*
82   * Daemon IDs
83   */
84  rtems_id                rxDaemonTid;
85  rtems_id                txDaemonTid;
86
87  /*
88   * MDIO/Phy info
89   */
90  struct rtems_mdio_info mdio_info;
91  int phy_default;
92  int media_state; /* (last detected) state of media */
93  /*
94   * statistic counters Rx
95   */
96  unsigned long           rxInterrupts;
[55a685b]97  unsigned long           rxErrors;
[f610e83f]98  /*
99   * statistic counters Tx
100   */
101  unsigned long           txInterrupts;
[55a685b]102  unsigned long           txErrors;
[f610e83f]103  };
104
105static struct mpc83xx_tsec_struct tsec_driver[M83xx_TSEC_NIFACES];
106
107/*
108 * default numbers for buffers
109 */
110#define RX_BUF_COUNT 64
111#define TX_BUF_COUNT 64
112
113/*
114 * mask for all Tx interrupts
115 */
116#define M83xx_IEVENT_TXALL (M83xx_TSEC_IEVENT_GTSC      \
117                            | M83xx_TSEC_IEVENT_TXC     \
[42bf1b9]118                            /*| M83xx_TSEC_IEVENT_TXB*/ \
[f610e83f]119                            | M83xx_TSEC_IEVENT_TXF )
120
121/*
122 * mask for all Rx interrupts
123 */
124#define M83xx_IEVENT_RXALL (M83xx_TSEC_IEVENT_RXC       \
[42bf1b9]125                            /* | M83xx_TSEC_IEVENT_RXB */       \
[f610e83f]126                            | M83xx_TSEC_IEVENT_GRSC    \
127                            | M83xx_TSEC_IEVENT_RXF  )
128
129/*
130 * mask for all Error interrupts
131 */
132#define M83xx_IEVENT_ERRALL (M83xx_TSEC_IEVENT_BABR             \
133                            | M83xx_TSEC_IEVENT_BSY             \
134                            | M83xx_TSEC_IEVENT_EBERR           \
135                            | M83xx_TSEC_IEVENT_MSRO            \
136                            | M83xx_TSEC_IEVENT_BABT            \
137                            | M83xx_TSEC_IEVENT_TXE             \
138                            | M83xx_TSEC_IEVENT_LC              \
139                            | M83xx_TSEC_IEVENT_CRL_XDA         \
140                            | M83xx_TSEC_IEVENT_XFUN   )
141
142#define M83xx_TSEC_IMASK_SET(reg,mask,val) {    \
143  rtems_interrupt_level level;                  \
144                                                \
145  rtems_interrupt_disable(level);               \
146  (reg) = (((reg) & ~(mask)) |                  \
147           ((val) &  (mask)));                  \
148  rtems_interrupt_enable(level);                \
149}
150
151#define M83xx_TSEC_ALIGN_BUFFER(buf,align)              \
152  ((void *)( (((uint32_t)(buf))+(align)-1)              \
153             -(((uint32_t)(buf))+(align)-1)%align))
154
155/*
156 * RTEMS event used by interrupt handler to signal daemons.
157 * This must *not* be the same event used by the TCP/IP task synchronization.
158 */
159#define INTERRUPT_EVENT RTEMS_EVENT_1
160#define FATAL_INT_EVENT RTEMS_EVENT_3
161
162/*
163 * RTEMS event used to start transmit daemon.
164 * This must not be the same as INTERRUPT_EVENT.
165 */
166#define START_TRANSMIT_EVENT RTEMS_EVENT_2
167
168static int mpc83xx_tsec_ioctl
169(
170 struct ifnet *ifp,                    /* interface information            */
171 ioctl_command_t command,              /* ioctl command code               */
172 caddr_t data                          /* optional data                    */
173 );
174
175/*=========================================================================*\
176| Function:                                                                 |
177\*-------------------------------------------------------------------------*/
178static void mpc83xx_tsec_hwinit
179(
180/*-------------------------------------------------------------------------*\
181| Purpose:                                                                  |
182|   initialize hardware register                                            |
183+---------------------------------------------------------------------------+
184| Input Parameters:                                                         |
185\*-------------------------------------------------------------------------*/
186 struct mpc83xx_tsec_struct *sc        /* control structure                */
187)
188/*-------------------------------------------------------------------------*\
189| Return Value:                                                             |
190|    <none>                                                                 |
191\*=========================================================================*/
192{
193  m83xxTSEC_Registers_t  *reg_ptr = sc->reg_ptr; /* pointer to TSEC registers*/
194  uint8_t *mac_addr;
195  int i;
196
197  /*
198   * init ECNTL register
199   * - clear statistics counters
200   * - enable statistics
201   * NOTE: do not clear bits set in BSP init function
202   */
203  reg_ptr->ecntrl = ((reg_ptr->ecntrl & ~M83xx_TSEC_ECNTRL_AUTOZ)
204                     | M83xx_TSEC_ECNTRL_CLRCNT
205                     | M83xx_TSEC_ECNTRL_STEN);
206
207  /*
208   * init DMA control register:
209   * - enable snooping
210   * - write BD status before interrupt request
211   * - do not poll TxBD, but wait for TSTAT[THLT] to be written
212   */
213  reg_ptr->dmactrl = (M83xx_TSEC_DMACTL_TDSEN
214                      | M83xx_TSEC_DMACTL_TBDSEN
215                      | M83xx_TSEC_DMACTL_WWR
216                      | M83xx_TSEC_DMACTL_WOP);
217
218  /*
219   * init Attribute register:
220   * - enable read snooping for data and BD
221   */
222  reg_ptr->attr = (M83xx_TSEC_ATTR_RDSEN
223                   | M83xx_TSEC_ATTR_RBDSEN);
224
225
226  reg_ptr->mrblr  = MCLBYTES-64; /* take care of buffer size lost
227                                  * due to alignment              */
228
229  /*
[55a685b]230   * init EDIS register: disable all error reportings
[f610e83f]231   */
[55a685b]232  reg_ptr->edis = (M83xx_TSEC_EDIS_BSYDIS    |
233                   M83xx_TSEC_EDIS_EBERRDIS  |
234                   M83xx_TSEC_EDIS_TXEDIS    |
235                   M83xx_TSEC_EDIS_LCDIS     |
236                   M83xx_TSEC_EDIS_CRLXDADIS |
237                   M83xx_TSEC_EDIS_FUNDIS);
[f610e83f]238  /*
239   * init minimum frame length register
240   */
241  reg_ptr->minflr = 64;
242  /*
243   * init maximum frame length register
244   */
245  reg_ptr->maxfrm = 1536;
246  /*
247   * define physical address of TBI
248   */
249  reg_ptr->tbipa = 0x1e;
250  /*
251   * init transmit interrupt coalescing register
252   */
253  reg_ptr->txic = (M83xx_TSEC_TXIC_ICEN
[42bf1b9]254                   | M83xx_TSEC_TXIC_ICFCT(2)
255                   | M83xx_TSEC_TXIC_ICTT(32));
[f610e83f]256  /*
257   * init receive interrupt coalescing register
258   */
259  reg_ptr->rxic = (M83xx_TSEC_RXIC_ICEN
[42bf1b9]260                   | M83xx_TSEC_RXIC_ICFCT(2)
261                   | M83xx_TSEC_RXIC_ICTT(32));
[f610e83f]262  /*
263   * init MACCFG1 register
264   */
265  reg_ptr->maccfg1 = (M83xx_TSEC_MACCFG1_RX_FLOW
266                      | M83xx_TSEC_MACCFG1_TX_FLOW);
267                     
268  /*
269   * init MACCFG2 register
270   */
271  reg_ptr->maccfg2 = ((reg_ptr->maccfg2 & M83xx_TSEC_MACCFG2_IFMODE_MSK)
272                      | M83xx_TSEC_MACCFG2_PRELEN(7)
273                      | M83xx_TSEC_MACCFG2_FULLDUPLEX);
274
275  /*
276   * init station address register
277   */
278  mac_addr = sc->arpcom.ac_enaddr;
279
280  reg_ptr->macstnaddr[0] = ((mac_addr[5] << 24)
281                            | (mac_addr[4] << 16)
282                            | (mac_addr[3] <<  8)
283                            | (mac_addr[2] <<  0));
284  reg_ptr->macstnaddr[1] = ((mac_addr[1] << 24)
285                            | (mac_addr[0] << 16));
286  /*
287   * clear hash filters
288   */
289  for (i = 0;
290       i < sizeof(reg_ptr->iaddr)/sizeof(reg_ptr->iaddr[0]);
291       i++) {
292    reg_ptr->iaddr[i] = 0;
293  }
294  for (i = 0;
295       i < sizeof(reg_ptr->gaddr)/sizeof(reg_ptr->gaddr[0]);
296       i++) {
297    reg_ptr->gaddr[i] = 0;
298  }
299}
300
301/***************************************************************************\
302|  MII Management access functions                                          |
303\***************************************************************************/
304
305/*=========================================================================*\
306| Function:                                                                 |
307\*-------------------------------------------------------------------------*/
308static void mpc83xx_tsec_mdio_init
309(
310/*-------------------------------------------------------------------------*\
311| Purpose:                                                                  |
312|   initialize the MIIM interface                                           |
313+---------------------------------------------------------------------------+
314| Input Parameters:                                                         |
315\*-------------------------------------------------------------------------*/
316 struct mpc83xx_tsec_struct *sc        /* control structure                */
317)
318/*-------------------------------------------------------------------------*\
319| Return Value:                                                             |
320|    <none>                                                                 |
321\*=========================================================================*/
322{
323  /*
324   * set clock divider
325   */
326  sc->reg_ptr->miimcfg = 3;
327}
328
329/*=========================================================================*\
330| Function:                                                                 |
331\*-------------------------------------------------------------------------*/
332int mpc83xx_tsec_mdio_read
333(
334/*-------------------------------------------------------------------------*\
335| Purpose:                                                                  |
336|   read register of a phy                                                  |
337+---------------------------------------------------------------------------+
338| Input Parameters:                                                         |
339\*-------------------------------------------------------------------------*/
340 int phy,                              /* PHY number to access or -1       */
341 void *uarg,                           /* unit argument                    */
342 unsigned reg,                         /* register address                 */
343 uint32_t *pval                        /* ptr to read buffer               */
344 )
345/*-------------------------------------------------------------------------*\
346| Return Value:                                                             |
347|    0, if ok, else error                                                   |
348\*=========================================================================*/
349{
350 struct mpc83xx_tsec_struct *sc = uarg;/* control structure                */
351  m83xxTSEC_Registers_t  *reg_ptr;     /* pointer to TSEC registers        */
352
353  reg_ptr = sc->reg_ptr;
354
355  /*
356   * make sure we work with a valid phy
357   */
358  if (phy == -1) {
359    /*
360     * set default phy number: 0 for TSEC1, 1 for TSEC2
361     */
362    phy = sc->phy_default;
363  }
364  if ( (phy < 0) || (phy > 31)) {
365    /*
366     * invalid phy number
367     */
368    return EINVAL;
369  }
370  /*
371   * set PHY/reg address
372   */
373  reg_ptr->miimadd = (M83xx_TSEC_MIIMADD_PHY(phy)
374                      | M83xx_TSEC_MIIMADD_REGADDR(reg));
375  /*
376   * start read cycle
377   */
378  reg_ptr->miimcom = 0;
379  reg_ptr->miimcom = M83xx_TSEC_MIIMCOM_READ;
380
381  /*
382   * wait for cycle to terminate
383   */
384  do {
385    rtems_task_wake_after(2);
386  }  while (0 != (reg_ptr->miimind & M83xx_TSEC_MIIMIND_BUSY));
387  reg_ptr->miimcom = 0;
388  /*
389   * fetch read data, if available
390   */
391  if (pval != NULL) {
392    *pval = reg_ptr->miimstat;
393  }
394  return 0;
395}
396
397/*=========================================================================*\
398| Function:                                                                 |
399\*-------------------------------------------------------------------------*/
400int mpc83xx_tsec_mdio_write
401(
402/*-------------------------------------------------------------------------*\
403| Purpose:                                                                  |
404|   write register of a phy                                                 |
405+---------------------------------------------------------------------------+
406| Input Parameters:                                                         |
407\*-------------------------------------------------------------------------*/
408 int phy,                              /* PHY number to access or -1       */
409 void *uarg,                           /* unit argument                    */
410 unsigned reg,                         /* register address                 */
411 uint32_t val                          /* write value                      */
412 )
413/*-------------------------------------------------------------------------*\
414| Return Value:                                                             |
415|    0, if ok, else error                                                   |
416\*=========================================================================*/
417{
418 struct mpc83xx_tsec_struct *sc = uarg;/* control structure                */
419  m83xxTSEC_Registers_t  *reg_ptr;     /* pointer to TSEC registers        */
420
421  reg_ptr = sc->reg_ptr;
422
423  /*
424   * make sure we work with a valid phy
425   */
426  if (phy == -1) {
427    /*
428     * set default phy number: 0 for TSEC1, 1 for TSEC2
429     */
430    phy = sc->phy_default;
431  }
432  if ( (phy < 0) || (phy > 31)) {
433    /*
434     * invalid phy number
435     */
436    return EINVAL;
437  }
438  /*
439   * set PHY/reg address
440   */
441  reg_ptr->miimadd = (M83xx_TSEC_MIIMADD_PHY(phy)
442                      | M83xx_TSEC_MIIMADD_REGADDR(reg));
443  /*
444   * start write cycle
445   */
446  reg_ptr->miimcon = val;
447
448  /*
449   * wait for cycle to terminate
450   */
451  do {
452    rtems_task_wake_after(2);
453  }  while (0 != (reg_ptr->miimind & M83xx_TSEC_MIIMIND_BUSY));
454  reg_ptr->miimcom = 0;
455  return 0;
456}
457
458
459/***************************************************************************\
460|  RX receive functions                                                     |
461\***************************************************************************/
462
463/*=========================================================================*\
464| Function:                                                                 |
465\*-------------------------------------------------------------------------*/
466static rtems_event_set mpc83xx_tsec_rx_wait_for_events
467(
468/*-------------------------------------------------------------------------*\
469| Purpose:                                                                  |
470|   handle all rx events                                                    |
471+---------------------------------------------------------------------------+
472| Input Parameters:                                                         |
473\*-------------------------------------------------------------------------*/
474 struct mpc83xx_tsec_struct *sc,       /* control structure                */
475 rtems_event_set event_mask            /* events to wait for               */
476)
477/*-------------------------------------------------------------------------*\
478| Return Value:                                                             |
479|    event set received                                                     |
480\*=========================================================================*/
481{
482 rtems_event_set events;            /* events received                     */
483 /*
484  * enable Rx interrupts, make sure this is not interrupted :-)
485  */
486 M83xx_TSEC_IMASK_SET(sc->reg_ptr->imask,M83xx_IEVENT_RXALL,~0);
487 
488 /*
489  * wait for events to come in
490  */
491 rtems_bsdnet_event_receive(event_mask,
492                            RTEMS_EVENT_ANY | RTEMS_WAIT,
493                            RTEMS_NO_TIMEOUT,
494                            &events);
495 return events;
496}
497
498/*=========================================================================*\
499| Function:                                                                 |
500\*-------------------------------------------------------------------------*/
501static void mpc83xx_rxbd_alloc_clear
502(
503/*-------------------------------------------------------------------------*\
504| Purpose:                                                                  |
505|   allocate space for Rx BDs, clear them                                   |
506+---------------------------------------------------------------------------+
507| Input Parameters:                                                         |
508\*-------------------------------------------------------------------------*/
509 struct mpc83xx_tsec_struct *sc        /* control structure                */
510)
511/*-------------------------------------------------------------------------*\
512| Return Value:                                                             |
513|    <none>                                                                 |
514\*=========================================================================*/
515{
516  char *alloc_ptr;
517  PQBufferDescriptor_t *BD_ptr;
518  /*
519   * allocate proper space for Rx BDs
520   */
521  alloc_ptr = calloc((sc->rxBdCount+1),sizeof(PQBufferDescriptor_t));
522  if (alloc_ptr == NULL) {
523    rtems_panic("TSEC: cannot allocate space for Rx BDs");
524  }
525  alloc_ptr = (void *)((uint32_t )((alloc_ptr + (sizeof(PQBufferDescriptor_t)-1)))
526                       & ~(sizeof(PQBufferDescriptor_t)-1));
527  /*
528   * store pointers to certain positions in BD chain
529   */
530  sc->Rx_Last_BD = ((PQBufferDescriptor_t *)alloc_ptr)+sc->rxBdCount-1;
531  sc->Rx_Frst_BD = (PQBufferDescriptor_t *)alloc_ptr;
532  sc->Rx_NxtUsed_BD = sc->Rx_Frst_BD;
533  sc->Rx_NxtFill_BD = sc->Rx_Frst_BD;
534 
535  /*
536   * clear all BDs
537   */
538  for (BD_ptr  = sc->Rx_Frst_BD;
539       BD_ptr <= sc->Rx_Last_BD;
540       BD_ptr++) {
541    BD_ptr->status = 0;
542  }
543  /*
544   * Init BD chain registers
545   */
546  sc->reg_ptr->rbase = (uint32_t) (sc->Rx_Frst_BD);
547}
548
549/*=========================================================================*\
550| Function:                                                                 |
551\*-------------------------------------------------------------------------*/
552static void mpc83xx_tsec_receive_packets
553(
554/*-------------------------------------------------------------------------*\
555| Purpose:                                                                  |
556|   process any received packets                                            |
557+---------------------------------------------------------------------------+
558| Input Parameters:                                                         |
559\*-------------------------------------------------------------------------*/
560 struct mpc83xx_tsec_struct *sc        /* control structure                */
561)
562/*-------------------------------------------------------------------------*\
563| Return Value:                                                             |
564|    <none>                                                                 |
565\*=========================================================================*/
566{
567  PQBufferDescriptor_t *BD_ptr;
568  struct mbuf *m,*n;
569  boolean finished = FALSE;
570  uint16_t status;
571  struct ether_header *eh;
572  int bd_idx;
573
574  BD_ptr = sc->Rx_NxtUsed_BD;
575
576  while ((0 == ((status = BD_ptr->status) & M83xx_BD_EMPTY)) &&
577         !finished &&
578         (BD_ptr->buffer != NULL)) {   
579    /*
580     * get mbuf associated with BD
581     */
582    bd_idx = BD_ptr - sc->Rx_Frst_BD;
583    m = sc->Rx_mBuf_Ptr[bd_idx];
584    sc->Rx_mBuf_Ptr[bd_idx] = NULL;
585
586    /*
587     * Check that packet is valid
588     */
589    if ((status & (M83xx_BD_LAST |
590                   M83xx_BD_FIRST_IN_FRAME |
591                   M83xx_BD_LONG |
592                   M83xx_BD_NONALIGNED |
593                   M83xx_BD_CRC_ERROR |
594                   M83xx_BD_OVERRUN ))
595        == (M83xx_BD_LAST |
596            M83xx_BD_FIRST_IN_FRAME ) ) {
597      /*
598       * send mbuf of this buffer to ether_input()
599       */
600      m->m_len   = m->m_pkthdr.len = (BD_ptr->length
601                                    - sizeof(uint32_t) 
602                                    - sizeof(struct ether_header));
603      eh         = mtod(m, struct ether_header *);
604      m->m_data += sizeof(struct ether_header);
605      ether_input(&sc->arpcom.ac_if,eh,m);
606    }
607    else {
608      /*
609       * throw away mbuf
610       */
611      MFREE(m,n);
612    }
613    /*
614     * mark buffer as non-allocated (for refill)
615     */
616    BD_ptr->buffer = NULL;
617    /*
618     * Advance BD_ptr to next BD
619     */
620    BD_ptr = ((BD_ptr == sc->Rx_Last_BD)
621             ? sc->Rx_Frst_BD
622             : BD_ptr+1);
623  }
624  sc->Rx_NxtUsed_BD = BD_ptr;
625}
626
627/*=========================================================================*\
628| Function:                                                                 |
629\*-------------------------------------------------------------------------*/
630static void mpc83xx_tsec_refill_rxbds
631(
632/*-------------------------------------------------------------------------*\
633| Purpose:                                                                  |
634|   link new buffers to rx BDs                                              |
635+---------------------------------------------------------------------------+
636| Input Parameters:                                                         |
637\*-------------------------------------------------------------------------*/
638 struct mpc83xx_tsec_struct *sc        /* control structure                */
639)
640/*-------------------------------------------------------------------------*\
641| Return Value:                                                             |
642|    <none>                                                                 |
643\*=========================================================================*/
644{
645  PQBufferDescriptor_t *BD_ptr;
646  struct mbuf *m,*n;
647  boolean finished = FALSE;
648  int bd_idx;
649
650  BD_ptr = sc->Rx_NxtFill_BD;
651  while ((BD_ptr->buffer == NULL) &&
652         !finished) {
653    /*
654     * get new mbuf and attach a cluster
655     */
656    MGETHDR(m,M_DONTWAIT,MT_DATA);
657    if (m != NULL) {
658      MCLGET(m,M_DONTWAIT);
659      if ((m->m_flags & M_EXT) == 0) {
660        MFREE(m,n);
661        m = NULL;
662      }
663    }
664    if (m == NULL) {
665      finished = TRUE;
666    }
667    else {
668      bd_idx = BD_ptr - sc->Rx_Frst_BD;
669      sc->Rx_mBuf_Ptr[bd_idx] = m;
670
671      m->m_pkthdr.rcvif= &sc->arpcom.ac_if;
672      m->m_data        = M83xx_TSEC_ALIGN_BUFFER(m->m_ext.ext_buf,64);
673      BD_ptr->buffer   = m->m_data;
674      BD_ptr->length   = 0;
675      BD_ptr->status   = (M83xx_BD_EMPTY
[42bf1b9]676                          | M83xx_BD_INTERRUPT
[f610e83f]677                          | ((BD_ptr == sc->Rx_Last_BD)
678                             ? M83xx_BD_WRAP
679                             : 0));
680      /*
681       * Advance BD_ptr to next BD
682       */
683      BD_ptr = ((BD_ptr == sc->Rx_Last_BD)
684                ? sc->Rx_Frst_BD
685                : BD_ptr+1);
686    }
687  }
688  sc->Rx_NxtFill_BD = BD_ptr;
689}
690
691/*=========================================================================*\
692| Function:                                                                 |
693\*-------------------------------------------------------------------------*/
694static void mpc83xx_tsec_rxDaemon
695(
696/*-------------------------------------------------------------------------*\
697| Purpose:                                                                  |
698|   handle all rx buffers and events                                        |
699+---------------------------------------------------------------------------+
700| Input Parameters:                                                         |
701\*-------------------------------------------------------------------------*/
702 void * arg                            /* argument, is sc structure ptr    */
703)
704/*-------------------------------------------------------------------------*\
705| Return Value:                                                             |
706|    <none>                                                                 |
707\*=========================================================================*/
708{
709  struct mpc83xx_tsec_struct *sc =
710    (struct mpc83xx_tsec_struct *)arg;
711  int finished = FALSE;
712  rtems_event_set events;
713#if !defined(CLREVENT_IN_IRQ)
714  uint32_t irq_events;
715#endif
716  /*
717   * enable Rx in MACCFG1 register
718   */
719  sc->reg_ptr->maccfg1 |= M83xx_TSEC_MACCFG1_RXEN;
720  while (!finished) {
721    /*
722     * fetch MBufs, associate them to RxBDs
723     */
724    mpc83xx_tsec_refill_rxbds(sc);
725    /*
726     * wait for events to come in
727     */
728    events = mpc83xx_tsec_rx_wait_for_events(sc,INTERRUPT_EVENT);
729#if !defined(CLREVENT_IN_IRQ)
730    /*
731     * clear any pending RX events
732     */
733    irq_events = sc->reg_ptr->ievent & M83xx_IEVENT_RXALL;
734    sc->reg_ptr->ievent = irq_events;
735#endif
736    /*
737     * fetch any completed buffers/packets received
738     * and stuff them into the TCP/IP Stack
739     */
740    mpc83xx_tsec_receive_packets(sc);
741  }
742  /*
743   * disable Rx in MACCFG1 register
744   */
745  sc->reg_ptr->maccfg1 &= ~M83xx_TSEC_MACCFG1_RXEN;
746  /*
747   * terminate daemon
748   */
749  sc->rxDaemonTid = 0;
750  rtems_task_delete(RTEMS_SELF);
751}
752
753/***************************************************************************\
754|  TX Transmit functions                                                    |
755\***************************************************************************/
756
757/*=========================================================================*\
758| Function:                                                                 |
759\*-------------------------------------------------------------------------*/
760static void mpc83xx_txbd_alloc_clear
761(
762/*-------------------------------------------------------------------------*\
763| Purpose:                                                                  |
764|   allocate space for Tx BDs, clear them                                   |
765+---------------------------------------------------------------------------+
766| Input Parameters:                                                         |
767\*-------------------------------------------------------------------------*/
768 struct mpc83xx_tsec_struct *sc        /* control structure                */
769)
770/*-------------------------------------------------------------------------*\
771| Return Value:                                                             |
772|    <none>                                                                 |
773\*=========================================================================*/
774{
775  char *alloc_ptr;
776  PQBufferDescriptor_t *BD_ptr;
777  /*
778   * allocate proper space for Tx BDs
779   */
780  alloc_ptr = calloc((sc->txBdCount+1),sizeof(PQBufferDescriptor_t));
781  if (alloc_ptr == NULL) {
782    rtems_panic("TSEC: cannot allocate space for Tx BDs");
783  }
784  alloc_ptr = (void *)((uint32_t )((alloc_ptr + (sizeof(PQBufferDescriptor_t)-1)))
785                       & ~(sizeof(PQBufferDescriptor_t)-1));
786  /*
787   * store pointers to certain positions in BD chain
788   */
789  sc->Tx_Last_BD = ((PQBufferDescriptor_t *)alloc_ptr)+sc->txBdCount-1;
790  sc->Tx_Frst_BD = (PQBufferDescriptor_t *)alloc_ptr;
791  sc->Tx_NxtUsed_BD = sc->Tx_Frst_BD;
792  sc->Tx_NxtFill_BD = sc->Tx_Frst_BD;
793 
794  /*
795   * clear all BDs
796   */
797  for (BD_ptr  = sc->Tx_Frst_BD;
798       BD_ptr <= sc->Tx_Last_BD;
799       BD_ptr++) {
800    BD_ptr->status = 0;
801  }
802  /*
803   * Init BD chain registers
804   */
805  sc->reg_ptr->tbase = (uint32_t)(sc->Tx_Frst_BD);
806}
807
808/*=========================================================================*\
809| Function:                                                                 |
810\*-------------------------------------------------------------------------*/
811void mpc83xx_tsec_tx_start
812(
813/*-------------------------------------------------------------------------*\
814| Purpose:                                                                  |
815|   start transmission                                                      |
816+---------------------------------------------------------------------------+
817| Input Parameters:                                                         |
818\*-------------------------------------------------------------------------*/
819struct ifnet *ifp
820)
821/*-------------------------------------------------------------------------*\
822| Return Value:                                                             |
823|    <none>                                                                 |
824\*=========================================================================*/
825{
826  struct mpc83xx_tsec_struct *sc = ifp->if_softc;
827
828  ifp->if_flags |= IFF_OACTIVE;
829
830  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
831}
832
833/*=========================================================================*\
834| Function:                                                                 |
835\*-------------------------------------------------------------------------*/
836static rtems_event_set mpc83xx_tsec_tx_wait_for_events
837(
838/*-------------------------------------------------------------------------*\
839| Purpose:                                                                  |
840|   handle all tx events                                                    |
841+---------------------------------------------------------------------------+
842| Input Parameters:                                                         |
843\*-------------------------------------------------------------------------*/
844 struct mpc83xx_tsec_struct *sc,       /* control structure                */
845 rtems_event_set event_mask            /* events to wait for               */
846)
847/*-------------------------------------------------------------------------*\
848| Return Value:                                                             |
849|    event set received                                                     |
850\*=========================================================================*/
851{
852 rtems_event_set events;            /* events received                     */
853 /*
854  * enable Tx interrupts, make sure this is not interrupted :-)
855  */
856 M83xx_TSEC_IMASK_SET(sc->reg_ptr->imask,M83xx_IEVENT_TXALL,~0);
857 
858 /*
859  * wait for events to come in
860  */
861 rtems_bsdnet_event_receive(event_mask,
862                            RTEMS_EVENT_ANY | RTEMS_WAIT,
863                            RTEMS_NO_TIMEOUT,
864                            &events);
865 return events;
866}
867
868/*=========================================================================*\
869| Function:                                                                 |
870\*-------------------------------------------------------------------------*/
871static void mpc83xx_tsec_tx_retire
872(
873/*-------------------------------------------------------------------------*\
874| Purpose:                                                                  |
875|   handle all tx events                                                    |
876+---------------------------------------------------------------------------+
877| Input Parameters:                                                         |
878\*-------------------------------------------------------------------------*/
879 struct mpc83xx_tsec_struct *sc        /* control structure                */
880)
881/*-------------------------------------------------------------------------*\
882| Return Value:                                                             |
883|    <none>                                                                 |
884\*=========================================================================*/
885{
886  PQBufferDescriptor_t *RetBD;
887  RetBD = sc->Tx_NxtUsed_BD;
888  int bd_idx;
889  struct mbuf *m,*n;
890  /*
891   * check next BDs to be empty
892   */
893  while ((RetBD->buffer != NULL)                       /* BD is filled      */
894         && (0 == (RetBD->status & M83xx_BD_READY ))) {/* BD no longer ready*/
895
896    bd_idx = RetBD - sc->Tx_Frst_BD;
897    m = sc->Tx_mBuf_Ptr[bd_idx];
898    sc->Tx_mBuf_Ptr[bd_idx] = NULL;
899
900    MFREE(m,n);
901    RetBD->buffer = NULL;
902    /*
903     * Advance CurrBD to next BD
904     */
905    RetBD = ((RetBD == sc->Tx_Last_BD)
906             ? sc->Tx_Frst_BD
907             : RetBD+1);
908  }
909  sc->Tx_NxtUsed_BD = RetBD;
910}
911
912/*=========================================================================*\
913| Function:                                                                 |
914\*-------------------------------------------------------------------------*/
915static void mpc83xx_tsec_sendpacket
916(
917/*-------------------------------------------------------------------------*\
918| Purpose:                                                                  |
919|   handle all tx events                                                    |
920+---------------------------------------------------------------------------+
921| Input Parameters:                                                         |
922\*-------------------------------------------------------------------------*/
923 struct mpc83xx_tsec_struct *sc,       /* control structure                */
924 struct mbuf *m                        /* start of packet to send          */
925)
926/*-------------------------------------------------------------------------*\
927| Return Value:                                                             |
928|    <none>                                                                 |
929\*=========================================================================*/
930{
931  PQBufferDescriptor_t *FrstBD = NULL;
932  PQBufferDescriptor_t *CurrBD;
933  uint16_t status;
934  struct mbuf *l = NULL; /* ptr to last non-freed (non-empty) mbuf */
935  int bd_idx;
936  /*
937   * get next Tx BD
938   */
939  CurrBD = sc->Tx_NxtFill_BD;
940  while (m) {
941    if(m->m_len == 0) {
942      /*
943       * Just toss empty mbufs
944       */
945      struct mbuf *n;
946      MFREE(m, n);
947      m = n;     
948      if(l != NULL) {
949        l->m_next = m;
950      }
951    }
952    else {
953      /*
954       * this mbuf is non-empty, so send it
955       */
956      /*
957       * Is CurrBD still in Use/not yet retired?
958       */
959      while (CurrBD->buffer != NULL) {
960        /*
961         * Then try to retire it
962         * and to return its mbuf
963         */
964        mpc83xx_tsec_tx_retire(sc);
965        if (CurrBD->buffer != NULL) {
966          /*
967           * Wait for anything to happen...
968           */
969          mpc83xx_tsec_tx_wait_for_events(sc,INTERRUPT_EVENT);
970        }
971      }
972      status = ((M83xx_BD_PAD_CRC | M83xx_BD_TX_CRC)
973                | ((m->m_next == NULL)       
[42bf1b9]974                   ? M83xx_BD_LAST | M83xx_BD_INTERRUPT
[f610e83f]975                   : 0)
976                | ((CurrBD == sc->Tx_Last_BD) ? M83xx_BD_WRAP : 0));
977               
978      /*
979       * link buffer to BD
980       */
981      CurrBD->buffer = mtod(m, void *);
982      CurrBD->length = (uint32_t)m->m_len;
983      l = m;       /* remember: we use this mbuf          */
984
985      bd_idx = CurrBD - sc->Tx_Frst_BD;
986      sc->Tx_mBuf_Ptr[bd_idx] = m;
987
988      m = m->m_next; /* advance to next mbuf of this packet */
989      /*
990       * is this the first BD of the packet?
991       * then don't set it to "READY" state,
992       * and remember this BD position
993       */
994      if (FrstBD == NULL) {
995        FrstBD = CurrBD;
996      }
997      else {
998        status |= M83xx_BD_READY;
999      }
1000      CurrBD->status = status;
1001      /*
1002       * Advance CurrBD to next BD
1003       */
1004      CurrBD = ((CurrBD == sc->Tx_Last_BD)
1005                ? sc->Tx_Frst_BD
1006                : CurrBD+1);
1007    }
1008  }
1009  /*
1010   * mbuf chain of this packet
1011   * has been translated
1012   * to BD chain, so set first BD ready now
1013   */
1014  if (FrstBD != NULL) {
1015    FrstBD->status |= M83xx_BD_READY;
1016  }
1017  sc->Tx_NxtFill_BD = CurrBD;
1018  /*
1019   * wake up transmitter (clear TSTAT[THLT])
1020   */
1021  sc->reg_ptr->tstat = M83xx_TSEC_TSTAT_THLT;
1022}
1023
1024/*=========================================================================*\
1025| Function:                                                                 |
1026\*-------------------------------------------------------------------------*/
1027static void mpc83xx_tsec_txDaemon
1028(
1029/*-------------------------------------------------------------------------*\
1030| Purpose:                                                                  |
1031|   handle all tx events                                                    |
1032+---------------------------------------------------------------------------+
1033| Input Parameters:                                                         |
1034\*-------------------------------------------------------------------------*/
1035 void * arg                            /* argument, is sc structure ptr    */
1036)
1037/*-------------------------------------------------------------------------*\
1038| Return Value:                                                             |
1039|    <none>                                                                 |
1040\*=========================================================================*/
1041{
1042  struct mpc83xx_tsec_struct *sc =
1043    (struct mpc83xx_tsec_struct *)arg;
1044  struct ifnet *ifp = &sc->arpcom.ac_if;
1045  struct mbuf *m;
1046  int finished = FALSE;
1047  rtems_event_set events;
1048#if !defined(CLREVENT_IN_IRQ)
1049  uint32_t irq_events;
1050#endif
1051
1052  /*
1053   * enable Tx in MACCFG1 register
1054   * FIXME: make this irq save
1055   */
1056  sc->reg_ptr->maccfg1 |= M83xx_TSEC_MACCFG1_TXEN;
1057  while (!finished) {
1058    /*
1059     * wait for events to come in
1060     */
1061    events = mpc83xx_tsec_tx_wait_for_events(sc,
1062                                             START_TRANSMIT_EVENT
1063                                             | INTERRUPT_EVENT);
1064#if !defined(CLREVENT_IN_IRQ)
1065    /*
1066     * clear any pending TX events
1067     */
1068    irq_events = sc->reg_ptr->ievent & M83xx_IEVENT_TXALL;
1069    sc->reg_ptr->ievent = irq_events;
1070#endif
1071    /*
1072     * retire any sent tx BDs
1073     */
1074    mpc83xx_tsec_tx_retire(sc);
1075    /*
1076     * Send packets till queue is empty
1077     */
1078    do {
1079      /*
1080       * Get the next mbuf chain to transmit.
1081       */
1082      IF_DEQUEUE(&ifp->if_snd, m);
1083     
1084      if (m) {
1085        mpc83xx_tsec_sendpacket(sc,m);
1086      }
1087    } while (m != NULL);
1088
1089    ifp->if_flags &= ~IFF_OACTIVE;
1090  }
1091  /*
1092   * disable Tx in MACCFG1 register
1093   */
1094  sc->reg_ptr->maccfg1 &= ~M83xx_TSEC_MACCFG1_TXEN;
1095  /*
1096   * terminate daemon
1097   */
1098  sc->txDaemonTid = 0;
1099  rtems_task_delete(RTEMS_SELF);
1100}
1101
1102/***************************************************************************\
1103|  Interrupt handlers and management routines                               |
1104\***************************************************************************/
1105
1106/*=========================================================================*\
1107| Function:                                                                 |
1108\*-------------------------------------------------------------------------*/
1109static void mpc83xx_tsec_tx_irq_handler
1110(
1111/*-------------------------------------------------------------------------*\
1112| Purpose:                                                                  |
1113|   handle tx interrupts                                                    |
1114+---------------------------------------------------------------------------+
1115| Input Parameters:                                                         |
1116\*-------------------------------------------------------------------------*/
1117 rtems_irq_hdl_param handle            /* handle, is sc structure ptr      */
1118)
1119/*-------------------------------------------------------------------------*\
1120| Return Value:                                                             |
1121|    <none>                                                                 |
1122\*=========================================================================*/
1123{
1124  struct mpc83xx_tsec_struct *sc =
1125    (struct mpc83xx_tsec_struct *)handle;
1126#if defined(CLREVENT_IN_IRQ)
1127  uint32_t irq_events;
1128#endif
1129
1130  sc->txInterrupts++;
1131  /*
1132   * disable tx interrupts
1133   */
1134  M83xx_TSEC_IMASK_SET(sc->reg_ptr->imask,M83xx_IEVENT_TXALL,0);
1135
1136#if defined(CLREVENT_IN_IRQ)
1137  /*
1138   * clear any pending TX events
1139   */
1140  irq_events = sc->reg_ptr->ievent & M83xx_IEVENT_TXALL;
1141  sc->reg_ptr->ievent = irq_events;
1142#endif
1143  /*
1144   * wake up tx Daemon
1145   */
1146  rtems_event_send(sc->txDaemonTid, INTERRUPT_EVENT);
1147}
1148
1149/*=========================================================================*\
1150| Function:                                                                 |
1151\*-------------------------------------------------------------------------*/
1152static void mpc83xx_tsec_rx_irq_handler
1153(
1154/*-------------------------------------------------------------------------*\
1155| Purpose:                                                                  |
1156|   handle rx interrupts                                                    |
1157+---------------------------------------------------------------------------+
1158| Input Parameters:                                                         |
1159\*-------------------------------------------------------------------------*/
1160 rtems_irq_hdl_param handle            /* handle, is sc structure          */
1161)
1162/*-------------------------------------------------------------------------*\
1163| Return Value:                                                             |
1164|    <none>                                                                 |
1165\*=========================================================================*/
1166{
1167  struct mpc83xx_tsec_struct *sc =
1168    (struct mpc83xx_tsec_struct *)handle;
1169#if defined(CLREVENT_IN_IRQ)
1170  uint32_t irq_events;
1171#endif
1172
1173  sc->rxInterrupts++;
1174  /*
1175   * disable rx interrupts
1176   */
1177  M83xx_TSEC_IMASK_SET(sc->reg_ptr->imask,M83xx_IEVENT_RXALL,0);
1178#if defined(CLREVENT_IN_IRQ)
1179  /*
1180   * clear any pending RX events
1181   */
1182  irq_events = sc->reg_ptr->ievent & M83xx_IEVENT_RXALL;
1183  sc->reg_ptr->ievent = irq_events;
1184#endif
1185  /*
1186   * wake up rx Daemon<
1187   */
1188  rtems_event_send(sc->rxDaemonTid, INTERRUPT_EVENT);
1189}
1190
1191
1192/*=========================================================================*\
1193| Function:                                                                 |
1194\*-------------------------------------------------------------------------*/
1195static void mpc83xx_tsec_err_irq_handler
1196(
1197/*-------------------------------------------------------------------------*\
1198| Purpose:                                                                  |
1199|   handle error interrupts                                                 |
1200+---------------------------------------------------------------------------+
1201| Input Parameters:                                                         |
1202\*-------------------------------------------------------------------------*/
1203 rtems_irq_hdl_param handle            /* handle, is sc structure          */
1204)
1205/*-------------------------------------------------------------------------*\
1206| Return Value:                                                             |
1207|    <none>                                                                 |
1208\*=========================================================================*/
1209{
[55a685b]1210  struct mpc83xx_tsec_struct *sc =
1211    (struct mpc83xx_tsec_struct *)handle;
[f610e83f]1212  /*
[55a685b]1213   * clear error events in IEVENT
[f610e83f]1214   */
[42bf1b9]1215  sc->reg_ptr->ievent = M83xx_IEVENT_ERRALL;
[f610e83f]1216  /*
[55a685b]1217   * has Rx been stopped? then restart it
[f610e83f]1218   */
[55a685b]1219  if (0 != (sc->reg_ptr->rstat & M83xx_TSEC_RSTAT_QHLT)) {
1220    sc->rxErrors++;
1221    sc->reg_ptr->rstat = M83xx_TSEC_RSTAT_QHLT;
1222  }
[f610e83f]1223  /*
[55a685b]1224   * has Tx been stopped? then restart it
[f610e83f]1225   */
[55a685b]1226  if (0 != (sc->reg_ptr->tstat & M83xx_TSEC_TSTAT_THLT)) {
1227    sc->txErrors++;
1228    sc->reg_ptr->tstat = M83xx_TSEC_TSTAT_THLT;
1229  }
[f610e83f]1230}
1231
1232
1233/*=========================================================================*\
1234| Function:                                                                 |
1235\*-------------------------------------------------------------------------*/
1236static uint32_t mpc83xx_tsec_irq_mask
1237(
1238/*-------------------------------------------------------------------------*\
1239| Purpose:                                                                  |
1240|   determine irq mask for given interrupt number                           |
1241+---------------------------------------------------------------------------+
1242| Input Parameters:                                                         |
1243\*-------------------------------------------------------------------------*/
1244 int irqnum,
1245 struct mpc83xx_tsec_struct *sc
1246)
1247/*-------------------------------------------------------------------------*\
1248| Return Value:                                                             |
1249|    interrupt mask (for ievent/imask register)                             |
1250\*=========================================================================*/
1251{
1252  return ((irqnum == sc->irq_num_tx)
1253          ? M83xx_IEVENT_TXALL
1254          : ((irqnum == sc->irq_num_rx)
1255             ? M83xx_IEVENT_RXALL
1256             : ((irqnum == sc->irq_num_err)
1257                ? M83xx_IEVENT_ERRALL
1258                : 0)));
1259}
1260/*=========================================================================*\
1261| Function:                                                                 |
1262\*-------------------------------------------------------------------------*/
1263static void mpc83xx_tsec_irq_on
1264(
1265/*-------------------------------------------------------------------------*\
1266| Purpose:                                                                  |
1267|   enable interrupts in TSEC mask register                              |
1268+---------------------------------------------------------------------------+
1269| Input Parameters:                                                         |
1270\*-------------------------------------------------------------------------*/
1271 const
1272 rtems_irq_connect_data *irq_conn_data   /* irq connect data                */
1273)
1274/*-------------------------------------------------------------------------*\
1275| Return Value:                                                             |
1276|    <none>                                                                 |
1277\*=========================================================================*/
1278{
1279  struct mpc83xx_tsec_struct *sc =
1280    (struct mpc83xx_tsec_struct *)(irq_conn_data->handle);
1281
1282  M83xx_TSEC_IMASK_SET(sc->reg_ptr->imask,
1283                       mpc83xx_tsec_irq_mask(irq_conn_data->name,sc),
1284                       ~0);
1285}
1286
1287/*=========================================================================*\
1288| Function:                                                                 |
1289\*-------------------------------------------------------------------------*/
1290static void mpc83xx_tsec_irq_off
1291(
1292/*-------------------------------------------------------------------------*\
1293| Purpose:                                                                  |
1294|   disable TX interrupts in TSEC mask register                             |
1295+---------------------------------------------------------------------------+
1296| Input Parameters:                                                         |
1297\*-------------------------------------------------------------------------*/
1298 const
1299 rtems_irq_connect_data *irq_conn_data   /* irq connect data                */
1300)
1301/*-------------------------------------------------------------------------*\
1302| Return Value:                                                             |
1303|    <none>                                                                 |
1304\*=========================================================================*/
1305{
1306  struct mpc83xx_tsec_struct *sc =
1307    (struct mpc83xx_tsec_struct *)irq_conn_data->handle;
1308
1309  M83xx_TSEC_IMASK_SET(sc->reg_ptr->imask,
1310                       mpc83xx_tsec_irq_mask(irq_conn_data->name,sc),
1311                       0);
1312}
1313
1314/*=========================================================================*\
1315| Function:                                                                 |
1316\*-------------------------------------------------------------------------*/
1317static int mpc83xx_tsec_irq_isOn
1318(
1319/*-------------------------------------------------------------------------*\
1320| Purpose:                                                                  |
1321|   check state of interrupts in TSEC mask register                         |
1322+---------------------------------------------------------------------------+
1323| Input Parameters:                                                         |
1324\*-------------------------------------------------------------------------*/
1325 const
1326 rtems_irq_connect_data *irq_conn_data  /* irq connect data                */
1327)
1328/*-------------------------------------------------------------------------*\
1329| Return Value:                                                             |
1330|    <none>                                                                 |
1331\*=========================================================================*/
1332{
1333  struct mpc83xx_tsec_struct *sc =
1334    (struct mpc83xx_tsec_struct *)irq_conn_data->handle;
1335
1336  return (0 != (sc->reg_ptr->imask
1337                & mpc83xx_tsec_irq_mask(irq_conn_data->name,sc)));
1338}
1339
1340/*=========================================================================*\
1341| Function:                                                                 |
1342\*-------------------------------------------------------------------------*/
1343static void mpc83xx_tsec_install_irq_handlers
1344(
1345/*-------------------------------------------------------------------------*\
1346| Purpose:                                                                  |
1347|   (un-)install the interrupt handlers                                     |
1348+---------------------------------------------------------------------------+
1349| Input Parameters:                                                         |
1350\*-------------------------------------------------------------------------*/
1351 struct mpc83xx_tsec_struct *sc,        /* ptr to control structure        */
1352 int install                            /* TRUE: install, FALSE: remove    */
1353)
1354/*-------------------------------------------------------------------------*\
1355| Return Value:                                                             |
1356|    <none>                                                                 |
1357\*=========================================================================*/
1358{
1359  int i;
1360
1361  rtems_irq_connect_data irq_conn_data[3] = {
1362    {
1363      sc->irq_num_tx,
1364      mpc83xx_tsec_tx_irq_handler, /* rtems_irq_hdl           */
1365      (rtems_irq_hdl_param)sc,     /* (rtems_irq_hdl_param)   */
1366      mpc83xx_tsec_irq_on,         /* (rtems_irq_enable)      */
1367      mpc83xx_tsec_irq_off,        /* (rtems_irq_disable)     */
1368      mpc83xx_tsec_irq_isOn        /* (rtems_irq_is_enabled)  */
1369    },{
1370      sc->irq_num_rx,
1371      mpc83xx_tsec_rx_irq_handler, /* rtems_irq_hdl           */
1372      (rtems_irq_hdl_param)sc,     /* (rtems_irq_hdl_param)   */
1373      mpc83xx_tsec_irq_on,         /* (rtems_irq_enable)      */
1374      mpc83xx_tsec_irq_off,        /* (rtems_irq_disable)     */
1375      mpc83xx_tsec_irq_isOn        /* (rtems_irq_is_enabled)  */
1376    },{
1377      sc->irq_num_err,
1378      mpc83xx_tsec_err_irq_handler, /* rtems_irq_hdl           */
1379      (rtems_irq_hdl_param)sc,      /* (rtems_irq_hdl_param)   */
1380      mpc83xx_tsec_irq_on,          /* (rtems_irq_enable)      */
1381      mpc83xx_tsec_irq_off,         /* (rtems_irq_disable)     */
1382      mpc83xx_tsec_irq_isOn         /* (rtems_irq_is_enabled)  */
1383    }
1384  };
1385
1386  /*
1387   * (un-)install handler for Tx/Rx/Error
1388   */
1389  for (i = 0;
1390       i < sizeof(irq_conn_data)/sizeof(irq_conn_data[0]);
1391       i++) {
1392    if (install) {
1393      if (!BSP_install_rtems_irq_handler (&irq_conn_data[i])) {
1394        rtems_panic("TSEC: cannot install IRQ handler");
1395      }
1396    }
1397    else {
1398      if (!BSP_remove_rtems_irq_handler (&irq_conn_data[i])) {
1399        rtems_panic("TSEC: cannot uninstall IRQ handler");
1400      }
1401    }
1402  }
1403}
1404
1405/***************************************************************************\
1406|  Initialization and interface routines                                    |
1407\***************************************************************************/
1408
1409/*=========================================================================*\
1410| Function:                                                                 |
1411\*-------------------------------------------------------------------------*/
1412static void mpc83xx_tsec_init
1413(
1414/*-------------------------------------------------------------------------*\
1415| Purpose:                                                                  |
1416|   initialize the driver and the hardware                                  |
1417+---------------------------------------------------------------------------+
1418| Input Parameters:                                                         |
1419\*-------------------------------------------------------------------------*/
1420 void *arg                              /* argument pointer, contains *sc  */
1421)
1422/*-------------------------------------------------------------------------*\
1423| Return Value:                                                             |
1424|    zero, if success                                                       |
1425\*=========================================================================*/
1426{
1427  struct mpc83xx_tsec_struct *sc = (struct mpc83xx_tsec_struct *)arg;
1428  struct ifnet *ifp = &sc->arpcom.ac_if;
1429  /*
1430   * check, whether device is not yet running
1431   */
1432  if (0 == sc->rxDaemonTid) {
1433    /*
1434     * allocate rx/tx BDs
1435     */
1436    mpc83xx_rxbd_alloc_clear(sc);
1437    mpc83xx_txbd_alloc_clear(sc);
1438    /*
1439     * allocate storage for mbuf ptrs
1440     */
1441    sc->Rx_mBuf_Ptr = calloc(sc->rxBdCount,sizeof(struct mbuf *));
1442    sc->Tx_mBuf_Ptr = calloc(sc->txBdCount,sizeof(struct mbuf *));   
1443    if ((sc->Rx_mBuf_Ptr == NULL) ||
1444        (sc->Tx_mBuf_Ptr == NULL)) {
1445        rtems_panic("TSEC: cannot allocate buffers for mbuf management");
1446     
1447    }
1448
1449    /*
1450     * initialize TSEC hardware:
1451     * - set interrupt coalescing to BDCount/8, Time of 8 frames
1452     * - enable DMA snooping
1453     */
1454    mpc83xx_tsec_hwinit(sc);
1455    /*
1456     * init access to phys
1457     */
1458    mpc83xx_tsec_mdio_init(sc);
1459    /*
1460     * Start driver tasks
1461     */
1462    sc->txDaemonTid = rtems_bsdnet_newproc("TStx",
1463                                           4096,
1464                                           mpc83xx_tsec_txDaemon,
1465                                           sc);
1466    sc->rxDaemonTid = rtems_bsdnet_newproc("TSrx", 4096,
1467                                           mpc83xx_tsec_rxDaemon,
1468                                           sc);
1469    /*
1470     * install interrupt handlers
1471     */
1472    mpc83xx_tsec_install_irq_handlers(sc,1);
1473  }
1474  /*
1475   * Set flags appropriately
1476   */
1477  if(ifp->if_flags & IFF_PROMISC) {
1478    sc->reg_ptr->rctrl |=  M83xx_TSEC_RCTRL_PROM;
1479  }
1480  else {
1481    sc->reg_ptr->rctrl &= ~M83xx_TSEC_RCTRL_PROM;
1482  }
1483
1484  /*
1485   * init timer so the "watchdog function gets called periodically
1486   */
1487  ifp->if_timer    = 1;
1488  /*
1489   * Tell the world that we're running.
1490   */
1491  ifp->if_flags |= IFF_RUNNING;
1492}
1493
1494/*=========================================================================*\
1495| Function:                                                                 |
1496\*-------------------------------------------------------------------------*/
1497static void mpc83xx_tsec_off
1498(
1499/*-------------------------------------------------------------------------*\
1500| Purpose:                                                                  |
1501|   deinitialize the driver and the hardware                                |
1502+---------------------------------------------------------------------------+
1503| Input Parameters:                                                         |
1504\*-------------------------------------------------------------------------*/
1505 struct mpc83xx_tsec_struct *sc         /* ptr to control structure        */
1506)
1507/*-------------------------------------------------------------------------*\
1508| Return Value:                                                             |
1509|    <none>                                                                 |
1510\*=========================================================================*/
1511{
1512  /*
[55a685b]1513   * deinitialize driver?
[f610e83f]1514   */
1515}
1516
1517/*=========================================================================*\
1518| Function:                                                                 |
1519\*-------------------------------------------------------------------------*/
1520static void mpc83xx_tsec_stats
1521(
1522/*-------------------------------------------------------------------------*\
1523| Purpose:                                                                  |
[55a685b]1524|   print statistics                                                        |
[f610e83f]1525+---------------------------------------------------------------------------+
1526| Input Parameters:                                                         |
1527\*-------------------------------------------------------------------------*/
1528 struct mpc83xx_tsec_struct *sc         /* ptr to control structure        */
1529)
1530/*-------------------------------------------------------------------------*\
1531| Return Value:                                                             |
1532|    <none>                                                                 |
1533\*=========================================================================*/
1534{
1535  int media;
1536  int result;
1537  /*
1538   * fetch/print media info
1539   */
1540  media = IFM_MAKEWORD(0,0,0,sc->phy_default); /* fetch from default phy */
1541
1542  result = mpc83xx_tsec_ioctl(&(sc->arpcom.ac_if),
1543                              SIOCGIFMEDIA,
1544                              (caddr_t)&media);
1545  if (result == 0) {
1546    rtems_ifmedia2str(media,NULL,0);
1547    printf ("\n");
1548  }
[42bf1b9]1549#if 1 /* print all PHY registers */
1550  {
1551    int reg;
1552    uint32_t reg_val;
1553    printf("****** PHY register values****\n");
1554    for (reg = 0;reg <= 31;reg++) {
1555      mpc83xx_tsec_mdio_read(-1,sc,reg,&reg_val);
1556      printf("%02d:0x%04x%c",reg,reg_val,
1557             (((reg % 4) == 3) ? '\n' : ' '));
1558    }
1559  }
1560#endif 
[f610e83f]1561  /*
1562   * print some statistics
1563   */
[55a685b]1564  printf ("   Rx Interrupts:%-8lu",   sc->rxInterrupts);
1565  printf ("       Rx Errors:%-8lu",   sc->rxErrors);
1566  printf ("      Rx packets:%-8lu\n",   
1567          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_rpkt]);
1568  printf ("   Rx broadcasts:%-8lu",   
1569          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_rbca]);
1570  printf ("   Rx multicasts:%-8lu",   
1571          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_rmca]);
1572  printf ("           Giant:%-8lu\n",
1573          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_rovr]);
1574  printf ("       Non-octet:%-8lu",
1575          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_raln]);
1576  printf ("         Bad CRC:%-8lu",
1577          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_rfcs]);
1578  printf ("         Overrun:%-8lu\n",
1579          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_rdrp]);
[f610e83f]1580 
[55a685b]1581  printf ("   Tx Interrupts:%-8lu",   sc->txInterrupts);
1582  printf ("       Tx Errors:%-8lu",   sc->txErrors);
1583  printf ("      Tx packets:%-8lu\n",   
1584          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_tpkt]);
1585  printf ("        Deferred:%-8lu",
1586          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_tdfr]);
1587  printf ("  Late Collision:%-8lu",
1588          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_tlcl]);
1589  printf ("Retransmit Limit:%-8lu\n",
1590          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_tedf]);
1591  printf ("        Underrun:%-8lu\n",
1592          sc->reg_ptr->rmon_mib[m83xx_tsec_rmon_tund]);
[f610e83f]1593}
1594
1595/*=========================================================================*\
1596| Function:                                                                 |
1597\*-------------------------------------------------------------------------*/
1598static int mpc83xx_tsec_ioctl
1599(
1600/*-------------------------------------------------------------------------*\
1601| Purpose:                                                                  |
1602|   perform io control functions                                            |
1603+---------------------------------------------------------------------------+
1604| Input Parameters:                                                         |
1605\*-------------------------------------------------------------------------*/
1606 struct ifnet *ifp,                    /* interface information            */
1607 ioctl_command_t command,              /* ioctl command code               */
1608 caddr_t data                          /* optional data                    */
1609)
1610/*-------------------------------------------------------------------------*\
1611| Return Value:                                                             |
1612|    zero, if success                                                       |
1613\*=========================================================================*/
1614{
1615  struct mpc83xx_tsec_struct *sc = ifp->if_softc;
1616  int error = 0;
1617
1618  switch(command)  {
1619    /*
1620     * access PHY via MII
1621     */
1622  case SIOCGIFMEDIA:
1623  case SIOCSIFMEDIA:
1624    rtems_mii_ioctl (&(sc->mdio_info),sc,command,(void *)data);
1625    break;
1626  case SIOCGIFADDR:
1627  case SIOCSIFADDR:
1628    /*
1629     * pass through to general ether_ioctl
1630     */
1631    ether_ioctl(ifp, command, data);
1632    break;
1633
1634  case SIOCSIFFLAGS:
1635    /*
1636     * adjust active state
1637     */
1638    if (ifp->if_flags & IFF_RUNNING) {
1639      mpc83xx_tsec_off(sc);
1640    }
1641    if (ifp->if_flags & IFF_UP) {
[55a685b]1642      mpc83xx_tsec_init(sc);
[f610e83f]1643    }
1644    break;
1645
1646  case SIO_RTEMS_SHOW_STATS:
1647    /*
1648     * show interface statistics
1649     */
1650    mpc83xx_tsec_stats(sc);
1651    break;
1652
1653    /*
[55a685b]1654     * All sorts of multicast commands need to be added here!
[f610e83f]1655     */
1656  default:
1657    error = EINVAL;
1658    break;
1659  }
1660
1661  return error;
1662}
1663
1664/* #define DEBUG */
1665
1666/*=========================================================================*\
1667| Function:                                                                 |
1668\*-------------------------------------------------------------------------*/
1669int rtems_mpc83xx_tsec_mode_adapt
1670(
1671/*-------------------------------------------------------------------------*\
1672| Purpose:                                                                  |
1673|   init the PHY and adapt TSEC settings                                    |
1674+---------------------------------------------------------------------------+
1675| Input Parameters:                                                         |
1676\*-------------------------------------------------------------------------*/
1677 struct ifnet *ifp
1678)
1679/*-------------------------------------------------------------------------*\
1680| Return Value:                                                             |
1681|    0, if success                                                       |
1682\*=========================================================================*/
1683{
1684  int result;
1685  int media;
1686  struct mpc83xx_tsec_struct *sc = ifp->if_softc;
1687
1688#ifdef DEBUG
1689  printf("c");
1690#endif
1691  /*
1692   * fetch media status
1693   */
1694  result = mpc83xx_tsec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1695  if (result != 0) {
1696    return result;
1697  }
1698#ifdef DEBUG
1699  printf("C");
1700#endif
1701  /*
1702   * status is unchanged? then do nothing
1703   */
1704  if (media == sc->media_state) {
1705    return 0;
1706  }
1707  /*
1708   * otherwise: for the first call, try to negotiate mode
1709   */
1710  if (sc->media_state == 0) {
1711    /*
1712     * set media status: set auto negotiation -> start auto-negotiation
1713     */
1714    media = IFM_MAKEWORD(0,IFM_AUTO,0,sc->phy_default);
1715    result = mpc83xx_tsec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media);
1716    if (result != 0) {
1717      return result;
1718    }
1719    /*
1720     * wait for auto-negotiation to terminate
1721     */
1722    do {
1723      media = IFM_MAKEWORD(0,0,0,sc->phy_default);
1724      result = mpc83xx_tsec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1725      if (result != 0) {
1726        return result;
1727      }
1728    } while (IFM_NONE == IFM_SUBTYPE(media));
1729  }
1730
1731  /*
1732   * now set HW according to media results:
1733   */
1734  /*
[42bf1b9]1735   * if we are 1000MBit, then switch IF to byte mode
[f610e83f]1736   */
1737  if (IFM_1000_T == IFM_SUBTYPE(media)) {
1738    sc->reg_ptr->maccfg2 =
1739      ((sc->reg_ptr->maccfg2 & ~M83xx_TSEC_MACCFG2_IFMODE_MSK)
1740       | M83xx_TSEC_MACCFG2_IFMODE_BYT);
1741  }
1742  else {
1743    sc->reg_ptr->maccfg2 =
1744      ((sc->reg_ptr->maccfg2 & ~M83xx_TSEC_MACCFG2_IFMODE_MSK)
1745       | M83xx_TSEC_MACCFG2_IFMODE_NIB);
1746  }
[42bf1b9]1747  /*
1748   * if we are 10MBit, then switch rate to 10M
1749   */
1750  if (IFM_10_T == IFM_SUBTYPE(media)) {
1751    sc->reg_ptr->ecntrl &= ~M83xx_TSEC_ECNTRL_R100M;
1752  }
1753  else {
1754    sc->reg_ptr->ecntrl |= M83xx_TSEC_ECNTRL_R100M;
1755  }
[f610e83f]1756  /*
1757   * if we are half duplex then switch to half duplex
1758   */
1759  if (0 == (IFM_FDX & IFM_OPTIONS(media))) {
1760    sc->reg_ptr->maccfg2 &= ~M83xx_TSEC_MACCFG2_FULLDUPLEX;
1761  }
1762  else {
1763    sc->reg_ptr->maccfg2 |=  M83xx_TSEC_MACCFG2_FULLDUPLEX;
1764  }   
1765  /*
1766   * store current media state for future compares
1767   */
1768  sc->media_state = media;
1769
1770  return 0;
1771}
1772
1773/*=========================================================================*\
1774| Function:                                                                 |
1775\*-------------------------------------------------------------------------*/
1776static void mpc83xx_tsec_watchdog
1777(
1778/*-------------------------------------------------------------------------*\
1779| Purpose:                                                                  |
1780|   periodically poll the PHY. if mode has changed,                         |
1781|  then adjust the TSEC settings                                            |
1782+---------------------------------------------------------------------------+
1783| Input Parameters:                                                         |
1784\*-------------------------------------------------------------------------*/
1785 struct ifnet *ifp
1786)
1787/*-------------------------------------------------------------------------*\
1788| Return Value:                                                             |
1789|    1, if success                                                       |
1790\*=========================================================================*/
1791{
1792  rtems_mpc83xx_tsec_mode_adapt(ifp);
1793  ifp->if_timer    = TSEC_WATCHDOG_TIMEOUT;
1794}
1795
1796/*=========================================================================*\
1797| Function:                                                                 |
1798\*-------------------------------------------------------------------------*/
1799static int mpc83xx_tsec_driver_attach
1800(
1801/*-------------------------------------------------------------------------*\
1802| Purpose:                                                                  |
1803|   attach the driver                                                       |
1804+---------------------------------------------------------------------------+
1805| Input Parameters:                                                         |
1806\*-------------------------------------------------------------------------*/
1807 struct rtems_bsdnet_ifconfig *config  /* interface configuration          */
1808)
1809/*-------------------------------------------------------------------------*\
1810| Return Value:                                                             |
[55a685b]1811|    1, if success                                                          |
[f610e83f]1812\*=========================================================================*/
1813{
1814  struct mpc83xx_tsec_struct *sc;
1815  struct ifnet *ifp;
1816  int    unitNumber;
1817  char   *unitName;
1818
1819 /*
1820  * Parse driver name
1821  */
1822  if((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
1823    return 0;
1824  }
1825
1826 /*
1827  * Is driver free?
1828  */
1829  if ((unitNumber <= 0) || (unitNumber > M83xx_TSEC_NIFACES)) {
1830
1831    printk ("Bad TSEC unit number.\n");
1832    return 0;
1833
1834    }
1835
1836  sc = &tsec_driver[unitNumber - 1];
1837  ifp = &sc->arpcom.ac_if;
1838  /*
1839   * add sc to config
1840   */
1841  config->drv_ctrl = sc;
1842
1843  if(ifp->if_softc != NULL) {
1844    printk ("Driver already in use.\n");
1845    return 0;
1846  }
1847
1848  /*
1849   * Process options
1850   */
1851  if(config->hardware_address) {
1852    memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1853  }
1854  else {
1855      rtems_panic("TSEC: No Ethernet address specified!\n");
1856  }
1857
1858  sc->rxBdCount       = (config->rbuf_count > 0) ? config->rbuf_count :  RX_BUF_COUNT;
1859  sc->txBdCount       = (config->xbuf_count > 0) ? config->xbuf_count :  TX_BUF_COUNT;
1860  sc->acceptBroadcast = !config->ignore_broadcast;
1861
1862  /* get pointer to TSEC register block */
1863  sc->reg_ptr         = &mpc83xx.tsec[unitNumber-1];
1864  /* get base interrupt number (for Tx irq, Rx=base+1,Err=base+2) */
1865  sc->irq_num_tx      = config->irno + 0;  /* tx  irq number from BSP */
1866  sc->irq_num_rx      = config->irno + 1;  /* rx  irq number from BSP */
1867  sc->irq_num_err     = config->irno + 2;  /* err irq number from BSP */
1868  if (config->irno  == 0) {
1869    rtems_panic("TSEC: interupt base number irno not defined");
1870  }
1871  /*
1872   * setup info about mdio interface
1873   */
1874  sc->mdio_info.mdio_r   = mpc83xx_tsec_mdio_read;
1875  sc->mdio_info.mdio_w   = mpc83xx_tsec_mdio_write;
1876  sc->mdio_info.has_gmii = 1; /* we support gigabit IF */
1877  /*
1878   * XXX: Although most hardware builders will assign the PHY addresses
1879   * like this, this should be more configurable
1880   */
1881  sc->phy_default = unitNumber-1;
1882 /*
1883  * Set up network interface values
1884  */
1885  ifp->if_softc   = sc;
1886  ifp->if_unit    = unitNumber;
1887  ifp->if_name    = unitName;
1888  ifp->if_mtu     = (config->mtu > 0) ? config->mtu : ETHERMTU;
1889  ifp->if_init    = mpc83xx_tsec_init;
1890  ifp->if_ioctl   = mpc83xx_tsec_ioctl;
1891  ifp->if_start   = mpc83xx_tsec_tx_start;
1892  ifp->if_output  = ether_output;
1893  ifp->if_watchdog =  mpc83xx_tsec_watchdog; /* XXX: timer is set in "init" */
1894
1895  ifp->if_flags   = (config->ignore_broadcast) ? 0 : IFF_BROADCAST;
1896  /*ifp->if_flags   = IFF_BROADCAST | IFF_SIMPLEX;*/
1897
1898  if(ifp->if_snd.ifq_maxlen == 0) {
1899    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1900  }
1901
[42bf1b9]1902#if defined(HSC_CM01)
1903  /*
1904   * for HSC CM01: we need to configure the PHY to use maximum skew adjust
1905   */
1906 
1907  mpc83xx_tsec_mdio_write(-1,sc,31,1);
1908  mpc83xx_tsec_mdio_write(-1,sc,28,0xf000);
1909  mpc83xx_tsec_mdio_write(-1,sc,31,0);
1910#endif
[f610e83f]1911  /*
1912   * Attach the interface
1913   */
1914  if_attach(ifp);
1915
1916  ether_ifattach(ifp);
1917
1918  return 1;
1919}
1920
1921/*=========================================================================*\
1922| Function:                                                                 |
1923\*-------------------------------------------------------------------------*/
1924int rtems_mpc83xx_tsec_driver_attach_detach
1925(
1926/*-------------------------------------------------------------------------*\
1927| Purpose:                                                                  |
1928|   attach or detach the driver                                             |
1929+---------------------------------------------------------------------------+
1930| Input Parameters:                                                         |
1931\*-------------------------------------------------------------------------*/
1932 struct rtems_bsdnet_ifconfig *config, /* interface configuration          */
1933 int attaching                         /* 0 = detach, else attach          */
1934)
1935/*-------------------------------------------------------------------------*\
1936| Return Value:                                                             |
1937|    1, if success                                                       |
1938\*=========================================================================*/
1939{
1940  if (attaching) {
1941    return mpc83xx_tsec_driver_attach(config);
1942  }
1943  else {
1944    return 0;
1945  }
1946}
1947
Note: See TracBrowser for help on using the repository browser.