source: rtems/c/src/lib/libcpu/powerpc/mpc83xx/network/tsec.c @ 185da08

4.104.114.84.95
Last change on this file since 185da08 was f610e83f, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 07/10/07 at 16:00:28

compilable release of virtex/gen83xx/gen5200 powerpc adaptations. Merged many different versions of new exception handling code to shared sources.

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