source: rtems/c/src/lib/libcpu/powerpc/mpc83xx/network/tsec.c @ 41d7c0fe

4.104.114.95
Last change on this file since 41d7c0fe was 41d7c0fe, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on May 27, 2008 at 10:34:55 AM

speed inprovements in mpc83xx tsec driver

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