source: rtems/c/src/lib/libcpu/powerpc/mpc83xx/network/tsec.c @ 06280c35

4.115
Last change on this file since 06280c35 was 06280c35, checked in by Sebastian Huber <sebastian.huber@…>, on 02/25/11 at 13:34:41

2011-02-25 Sebastian Huber <sebastian.huber@…>

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