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

4.115
Last change on this file since f0e748c was f0e748c, checked in by Sebastian Huber <sebastian.huber@…>, on 11/10/11 at 08:44:37

2011-11-10 Sebastian Huber <sebastian.huber@…>

PR 1927/bsps:

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