source: rtems/c/src/lib/libcpu/powerpc/mpc83xx/network/tsec.c @ 509040f0

4.115
Last change on this file since 509040f0 was 509040f0, checked in by Sebastian Huber <sebastian.huber@…>, on 04/14/14 at 15:11:12

bsps/powerpc: SMP support for one TSEC driver

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