source: rtems/bsps/powerpc/shared/net/tsec.c @ 0cab067

5
Last change on this file since 0cab067 was 0cab067, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 23, 2018 at 2:54:12 PM

bsps/powerpc: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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