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 03/23/18 at 14:54:12

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
RevLine 
[f610e83f]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|                                                                 |
[c499856]14| http://www.rtems.org/license/LICENSE.                           |
[f610e83f]15|                                                                 |
16+-----------------------------------------------------------------+
17| this file contains the MPC83xx TSEC networking driver           |
18\*===============================================================*/
[f2c8c34]19
[d8d6a08]20#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
21
[f610e83f]22#include <stdlib.h>
23#include <bsp.h>
24#include <bsp/irq.h>
[1e86d1e]25#include <bsp/tsec.h>
[f610e83f]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
[f2c8c34]46#ifdef DEBUG
47  #define PF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__)
48#else
49  #define PF(...)
50#endif
51
[f610e83f]52/*
53 * Device data
54 */
[1e86d1e]55struct tsec_struct {
[f610e83f]56  struct arpcom           arpcom;
57  int                     acceptBroadcast;
58
59  /*
60   * HW links: (filled from rtems_bsdnet_ifconfig
61   */
[f2c8c34]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;
[359e537]67
[509040f0]68  rtems_interrupt_lock lock;
69
[359e537]70  /*
[f610e83f]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         */
[359e537]86  /*
87   * Daemon IDs
[f610e83f]88   */
[359e537]89  rtems_id                rxDaemonTid;
[f610e83f]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;
[55a685b]102  unsigned long           rxErrors;
[f610e83f]103  /*
104   * statistic counters Tx
105   */
106  unsigned long           txInterrupts;
[55a685b]107  unsigned long           txErrors;
[f610e83f]108  };
109
[1e86d1e]110static struct tsec_struct tsec_driver[TSEC_COUNT];
[f610e83f]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 */
[1e86d1e]121#define IEVENT_TXALL (TSEC_IEVENT_GTSC  \
122                            | TSEC_IEVENT_TXC   \
123                            /*| TSEC_IEVENT_TXB*/       \
124                            | TSEC_IEVENT_TXF )
[f610e83f]125
126/*
127 * mask for all Rx interrupts
128 */
[1e86d1e]129#define IEVENT_RXALL (TSEC_IEVENT_RXC   \
130                            /* | TSEC_IEVENT_RXB */     \
131                            | TSEC_IEVENT_GRSC  \
132                            | TSEC_IEVENT_RXF  )
[f610e83f]133
134/*
135 * mask for all Error interrupts
136 */
[1e86d1e]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
[509040f0]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);
[f610e83f]155}
156
[1e86d1e]157#define TSEC_ALIGN_BUFFER(buf,align)            \
[f610e83f]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
[1e86d1e]174static int tsec_ioctl
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]184static void tsec_hwinit
[f610e83f]185(
186/*-------------------------------------------------------------------------*\
187| Purpose:                                                                  |
188|   initialize hardware register                                            |
189+---------------------------------------------------------------------------+
190| Input Parameters:                                                         |
191\*-------------------------------------------------------------------------*/
[1e86d1e]192 struct tsec_struct *sc        /* control structure                */
[f610e83f]193)
194/*-------------------------------------------------------------------------*\
195| Return Value:                                                             |
196|    <none>                                                                 |
197\*=========================================================================*/
198{
[1e86d1e]199  volatile tsec_registers *reg_ptr = sc->reg_ptr; /* pointer to TSEC registers*/
[f610e83f]200  uint8_t *mac_addr;
[574fb67]201  size_t i;
[f610e83f]202
[4b23c94]203  /* Clear interrupt mask and all pending events */
204  reg_ptr->imask = 0;
205  reg_ptr->ievent = 0xffffffff;
206
[f610e83f]207  /*
208   * init ECNTL register
209   * - clear statistics counters
210   * - enable statistics
211   * NOTE: do not clear bits set in BSP init function
212   */
[1e86d1e]213  reg_ptr->ecntrl = ((reg_ptr->ecntrl & ~TSEC_ECNTRL_AUTOZ)
214                     | TSEC_ECNTRL_CLRCNT
215                     | TSEC_ECNTRL_STEN
216                     | TSEC_ECNTRL_R100M);
[f610e83f]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   */
[1e86d1e]224  reg_ptr->dmactrl = (TSEC_DMACTL_TDSEN
225                      | TSEC_DMACTL_TBDSEN
226                      | TSEC_DMACTL_WWR
227                      | TSEC_DMACTL_WOP);
[f610e83f]228
229  /*
230   * init Attribute register:
231   * - enable read snooping for data and BD
232   */
[1e86d1e]233  reg_ptr->attr = (TSEC_ATTR_RDSEN
234                   | TSEC_ATTR_RBDSEN);
[f610e83f]235
236
[359e537]237  reg_ptr->mrblr  = MCLBYTES-64; /* take care of buffer size lost
[f610e83f]238                                  * due to alignment              */
239
240  /*
[55a685b]241   * init EDIS register: disable all error reportings
[f610e83f]242   */
[1e86d1e]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);
[f610e83f]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   */
[1e86d1e]264  reg_ptr->txic = (TSEC_TXIC_ICEN
265                   | TSEC_TXIC_ICFCT(2)
266                   | TSEC_TXIC_ICTT(32));
[f610e83f]267  /*
268   * init receive interrupt coalescing register
269   */
[41d7c0fe]270#if 0
[1e86d1e]271  reg_ptr->rxic = (TSEC_RXIC_ICEN
272                   | TSEC_RXIC_ICFCT(2)
273                   | TSEC_RXIC_ICTT(32));
[41d7c0fe]274#else
275  reg_ptr->rxic = 0;
276#endif
[f610e83f]277  /*
278   * init MACCFG1 register
279   */
[1e86d1e]280  reg_ptr->maccfg1 = (TSEC_MACCFG1_RX_FLOW
281                      | TSEC_MACCFG1_TX_FLOW);
[359e537]282
[f610e83f]283  /*
284   * init MACCFG2 register
285   */
[1e86d1e]286  reg_ptr->maccfg2 = ((reg_ptr->maccfg2 & TSEC_MACCFG2_IFMODE_MSK)
[06280c35]287                      | TSEC_MACCFG2_IFMODE_BYT
[1e86d1e]288                      | TSEC_MACCFG2_PRELEN( 7)
289                      | TSEC_MACCFG2_FULLDUPLEX);
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]324static void tsec_mdio_init
[f610e83f]325(
326/*-------------------------------------------------------------------------*\
327| Purpose:                                                                  |
328|   initialize the MIIM interface                                           |
329+---------------------------------------------------------------------------+
330| Input Parameters:                                                         |
331\*-------------------------------------------------------------------------*/
[1e86d1e]332 struct tsec_struct *sc        /* control structure                */
[f610e83f]333)
334/*-------------------------------------------------------------------------*\
335| Return Value:                                                             |
336|    <none>                                                                 |
337\*=========================================================================*/
338{
[f0e748c]339  static const uint8_t divider [] = { 32, 32, 48, 64, 80, 112, 160, 224 };
[06280c35]340  size_t n = sizeof(divider) / sizeof(divider [0]);
341  size_t i = 0;
[f0e748c]342  uint32_t mii_clock = UINT32_MAX;
343  uint32_t tsec_system_clock = BSP_bus_frequency / 2;
[574fb67]344
345  /* Set TSEC registers for MDIO communication */
346
[f610e83f]347  /*
348   * set clock divider
349   */
[f0e748c]350  for (i = 0; i < n && mii_clock > 2500000; ++i) {
351    mii_clock = tsec_system_clock / divider [i];
[06280c35]352  }
353
354  sc->mdio_ptr->miimcfg = i;
[f610e83f]355}
356
357/*=========================================================================*\
358| Function:                                                                 |
359\*-------------------------------------------------------------------------*/
[1e86d1e]360static int tsec_mdio_read
[f610e83f]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{
[1e86d1e]378  struct tsec_struct *sc = uarg;/* control structure                */
[f610e83f]379
[574fb67]380  /* pointer to TSEC registers */
[1e86d1e]381  volatile tsec_registers *reg_ptr = sc->mdio_ptr;
[f2c8c34]382  PF("%u\n", reg);
[f610e83f]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  /*
[359e537]397   * set PHY/reg address
[f610e83f]398   */
[1e86d1e]399  reg_ptr->miimadd = (TSEC_MIIMADD_PHY(phy)
400                      | TSEC_MIIMADD_REGADDR(reg));
[f610e83f]401  /*
402   * start read cycle
403   */
404  reg_ptr->miimcom = 0;
[1e86d1e]405  reg_ptr->miimcom = TSEC_MIIMCOM_READ;
[f610e83f]406
407  /*
408   * wait for cycle to terminate
409   */
410  do {
411    rtems_task_wake_after(2);
[1e86d1e]412  }  while (0 != (reg_ptr->miimind & TSEC_MIIMIND_BUSY));
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]426static int tsec_mdio_write
[f610e83f]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{
[1e86d1e]444  struct tsec_struct *sc = uarg;/* control structure                */
[f610e83f]445
[574fb67]446  /* pointer to TSEC registers */
[1e86d1e]447  volatile tsec_registers *reg_ptr = sc->mdio_ptr;
[f2c8c34]448  PF("%u\n", reg);
[f610e83f]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  /*
[359e537]466   * set PHY/reg address
[f610e83f]467   */
[1e86d1e]468  reg_ptr->miimadd = (TSEC_MIIMADD_PHY(phy)
469                      | TSEC_MIIMADD_REGADDR(reg));
[f610e83f]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);
[1e86d1e]480  }  while (0 != (reg_ptr->miimind & TSEC_MIIMIND_BUSY));
[f610e83f]481  reg_ptr->miimcom = 0;
482  return 0;
483}
484
485
486/***************************************************************************\
487|  RX receive functions                                                     |
488\***************************************************************************/
489
490/*=========================================================================*\
491| Function:                                                                 |
492\*-------------------------------------------------------------------------*/
[1e86d1e]493static rtems_event_set tsec_rx_wait_for_events
[f610e83f]494(
495/*-------------------------------------------------------------------------*\
496| Purpose:                                                                  |
497|   handle all rx events                                                    |
498+---------------------------------------------------------------------------+
499| Input Parameters:                                                         |
500\*-------------------------------------------------------------------------*/
[1e86d1e]501 struct tsec_struct *sc,       /* control structure                */
[f610e83f]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  */
[509040f0]513 TSEC_IMASK_SET(sc,IEVENT_RXALL,~0);
[359e537]514
[f610e83f]515 /*
516  * wait for events to come in
517  */
[359e537]518 rtems_bsdnet_event_receive(event_mask,
519                            RTEMS_EVENT_ANY | RTEMS_WAIT,
520                            RTEMS_NO_TIMEOUT,
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]536 struct tsec_struct *sc        /* control structure                */
[f610e83f]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;
[359e537]561
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]579static void tsec_receive_packets
[f610e83f]580(
581/*-------------------------------------------------------------------------*\
582| Purpose:                                                                  |
583|   process any received packets                                            |
584+---------------------------------------------------------------------------+
585| Input Parameters:                                                         |
586\*-------------------------------------------------------------------------*/
[1e86d1e]587 struct tsec_struct *sc        /* control structure                */
[f610e83f]588)
589/*-------------------------------------------------------------------------*\
590| Return Value:                                                             |
591|    <none>                                                                 |
592\*=========================================================================*/
593{
594  PQBufferDescriptor_t *BD_ptr;
595  struct mbuf *m,*n;
[bcd5368]596  bool finished = false;
[f610e83f]597  uint16_t status;
598  struct ether_header *eh;
599  int bd_idx;
600
601  BD_ptr = sc->Rx_NxtUsed_BD;
602
[1e86d1e]603  while ((0 == ((status = BD_ptr->status) & BD_EMPTY)) &&
[f610e83f]604         !finished &&
[359e537]605         (BD_ptr->buffer != NULL)) {
[f610e83f]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     */
[1e86d1e]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 ) ) {
[f610e83f]624      /*
625       * send mbuf of this buffer to ether_input()
626       */
[359e537]627      m->m_len   = m->m_pkthdr.len = (BD_ptr->length
628                                    - sizeof(uint32_t)
[f610e83f]629                                    - sizeof(struct ether_header));
630      eh         = mtod(m, struct ether_header *);
631      m->m_data += sizeof(struct ether_header);
[f2c8c34]632      PF("RX[%08x] (%i)\n", BD_ptr, m->m_len);
[f610e83f]633      ether_input(&sc->arpcom.ac_if,eh,m);
634    }
635    else {
636      /*
637       * throw away mbuf
638       */
639      MFREE(m,n);
[fca58924]640      (void) n;
[f610e83f]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     */
[359e537]649    BD_ptr = ((BD_ptr == sc->Rx_Last_BD)
650             ? sc->Rx_Frst_BD
[f610e83f]651             : BD_ptr+1);
652  }
653  sc->Rx_NxtUsed_BD = BD_ptr;
654}
655
656/*=========================================================================*\
657| Function:                                                                 |
658\*-------------------------------------------------------------------------*/
[1e86d1e]659static void tsec_refill_rxbds
[f610e83f]660(
661/*-------------------------------------------------------------------------*\
662| Purpose:                                                                  |
663|   link new buffers to rx BDs                                              |
664+---------------------------------------------------------------------------+
665| Input Parameters:                                                         |
666\*-------------------------------------------------------------------------*/
[1e86d1e]667 struct tsec_struct *sc        /* control structure                */
[f610e83f]668)
669/*-------------------------------------------------------------------------*\
670| Return Value:                                                             |
671|    <none>                                                                 |
672\*=========================================================================*/
673{
674  PQBufferDescriptor_t *BD_ptr;
675  struct mbuf *m,*n;
[bcd5368]676  bool finished = false;
[f610e83f]677  int bd_idx;
678
679  BD_ptr = sc->Rx_NxtFill_BD;
[359e537]680  while ((BD_ptr->buffer == NULL) &&
[f610e83f]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);
[fca58924]690        (void) n;
[f610e83f]691        m = NULL;
692      }
693    }
694    if (m == NULL) {
[bcd5368]695      finished = true;
[f610e83f]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;
[1e86d1e]702      m->m_data        = TSEC_ALIGN_BUFFER(m->m_ext.ext_buf,64);
[f610e83f]703      BD_ptr->buffer   = m->m_data;
704      BD_ptr->length   = 0;
[1e86d1e]705      BD_ptr->status   = (BD_EMPTY
706                          | BD_INTERRUPT
[359e537]707                          | ((BD_ptr == sc->Rx_Last_BD)
[1e86d1e]708                             ? BD_WRAP
[f610e83f]709                             : 0));
710      /*
711       * Advance BD_ptr to next BD
712       */
[359e537]713      BD_ptr = ((BD_ptr == sc->Rx_Last_BD)
714                ? sc->Rx_Frst_BD
[f610e83f]715                : BD_ptr+1);
716    }
717  }
718  sc->Rx_NxtFill_BD = BD_ptr;
719}
720
721/*=========================================================================*\
722| Function:                                                                 |
723\*-------------------------------------------------------------------------*/
[1e86d1e]724static void tsec_rxDaemon
[f610e83f]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{
[1e86d1e]739  struct tsec_struct *sc =
740    (struct tsec_struct *)arg;
[bcd5368]741  bool finished = false;
[f610e83f]742#if !defined(CLREVENT_IN_IRQ)
743  uint32_t irq_events;
744#endif
745  /*
746   * enable Rx in MACCFG1 register
747   */
[1e86d1e]748  sc->reg_ptr->maccfg1 |= TSEC_MACCFG1_RXEN;
[f610e83f]749  while (!finished) {
750    /*
751     * fetch MBufs, associate them to RxBDs
752     */
[1e86d1e]753    tsec_refill_rxbds(sc);
[f610e83f]754    /*
755     * wait for events to come in
756     */
[fca58924]757    tsec_rx_wait_for_events(sc,INTERRUPT_EVENT);
[f610e83f]758#if !defined(CLREVENT_IN_IRQ)
759    /*
760     * clear any pending RX events
761     */
[1e86d1e]762    irq_events = sc->reg_ptr->ievent & IEVENT_RXALL;
[f610e83f]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     */
[1e86d1e]769    tsec_receive_packets(sc);
[f610e83f]770  }
771  /*
772   * disable Rx in MACCFG1 register
773   */
[1e86d1e]774  sc->reg_ptr->maccfg1 &= ~TSEC_MACCFG1_RXEN;
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]797 struct tsec_struct *sc        /* control structure                */
[f610e83f]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;
[359e537]822
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]840static void tsec_tx_start
[f610e83f]841(
842/*-------------------------------------------------------------------------*\
843| Purpose:                                                                  |
844|   start transmission                                                      |
845+---------------------------------------------------------------------------+
846| Input Parameters:                                                         |
847\*-------------------------------------------------------------------------*/
848struct ifnet *ifp
849)
850/*-------------------------------------------------------------------------*\
851| Return Value:                                                             |
852|    <none>                                                                 |
853\*=========================================================================*/
854{
[1e86d1e]855  struct tsec_struct *sc = ifp->if_softc;
[f610e83f]856
857  ifp->if_flags |= IFF_OACTIVE;
858
[26e90fb1]859  rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
[f610e83f]860}
861
862/*=========================================================================*\
863| Function:                                                                 |
864\*-------------------------------------------------------------------------*/
[1e86d1e]865static rtems_event_set tsec_tx_wait_for_events
[f610e83f]866(
867/*-------------------------------------------------------------------------*\
868| Purpose:                                                                  |
869|   handle all tx events                                                    |
870+---------------------------------------------------------------------------+
871| Input Parameters:                                                         |
872\*-------------------------------------------------------------------------*/
[1e86d1e]873 struct tsec_struct *sc,       /* control structure                */
[f610e83f]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  */
[509040f0]885 TSEC_IMASK_SET(sc,IEVENT_TXALL,~0);
[359e537]886
[f610e83f]887 /*
888  * wait for events to come in
889  */
[359e537]890 rtems_bsdnet_event_receive(event_mask,
891                            RTEMS_EVENT_ANY | RTEMS_WAIT,
892                            RTEMS_NO_TIMEOUT,
[f610e83f]893                            &events);
894 return events;
895}
896
897/*=========================================================================*\
898| Function:                                                                 |
899\*-------------------------------------------------------------------------*/
[1e86d1e]900static void tsec_tx_retire
[f610e83f]901(
902/*-------------------------------------------------------------------------*\
903| Purpose:                                                                  |
904|   handle all tx events                                                    |
905+---------------------------------------------------------------------------+
906| Input Parameters:                                                         |
907\*-------------------------------------------------------------------------*/
[1e86d1e]908 struct tsec_struct *sc        /* control structure                */
[f610e83f]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      */
[1e86d1e]923         && (0 == (RetBD->status & BD_READY ))) {/* BD no longer ready*/
[f610e83f]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);
[fca58924]930    (void) n;
[f610e83f]931    RetBD->buffer = NULL;
932    /*
933     * Advance CurrBD to next BD
934     */
[359e537]935    RetBD = ((RetBD == sc->Tx_Last_BD)
936             ? sc->Tx_Frst_BD
[f610e83f]937             : RetBD+1);
938  }
939  sc->Tx_NxtUsed_BD = RetBD;
940}
941
942/*=========================================================================*\
943| Function:                                                                 |
944\*-------------------------------------------------------------------------*/
[1e86d1e]945static void tsec_sendpacket
[f610e83f]946(
947/*-------------------------------------------------------------------------*\
948| Purpose:                                                                  |
949|   handle all tx events                                                    |
950+---------------------------------------------------------------------------+
951| Input Parameters:                                                         |
952\*-------------------------------------------------------------------------*/
[1e86d1e]953 struct tsec_struct *sc,       /* control structure                */
[f610e83f]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);
[359e537]977      m = n;
[f610e83f]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      /*
[359e537]987       * Is CurrBD still in Use/not yet retired?
[f610e83f]988       */
989      while (CurrBD->buffer != NULL) {
990        /*
991         * Then try to retire it
992         * and to return its mbuf
993         */
[1e86d1e]994        tsec_tx_retire(sc);
[f610e83f]995        if (CurrBD->buffer != NULL) {
996          /*
997           * Wait for anything to happen...
998           */
[1e86d1e]999          tsec_tx_wait_for_events(sc,INTERRUPT_EVENT);
[f610e83f]1000        }
1001      }
[1e86d1e]1002      status = ((BD_PAD_CRC | BD_TX_CRC)
[359e537]1003                | ((m->m_next == NULL)
[1e86d1e]1004                   ? BD_LAST | BD_INTERRUPT
[f610e83f]1005                   : 0)
[1e86d1e]1006                | ((CurrBD == sc->Tx_Last_BD) ? BD_WRAP : 0));
[359e537]1007
[f610e83f]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          */
[f2c8c34]1014      PF("TX[%08x] (%i)\n", CurrBD, m->m_len);
[f610e83f]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?
[359e537]1022       * then don't set it to "READY" state,
[f610e83f]1023       * and remember this BD position
1024       */
1025      if (FrstBD == NULL) {
1026        FrstBD = CurrBD;
1027      }
1028      else {
[1e86d1e]1029        status |= BD_READY;
[f610e83f]1030      }
1031      CurrBD->status = status;
1032      /*
1033       * Advance CurrBD to next BD
1034       */
[359e537]1035      CurrBD = ((CurrBD == sc->Tx_Last_BD)
1036                ? sc->Tx_Frst_BD
[f610e83f]1037                : CurrBD+1);
1038    }
1039  }
1040  /*
[359e537]1041   * mbuf chain of this packet
1042   * has been translated
[f610e83f]1043   * to BD chain, so set first BD ready now
1044   */
1045  if (FrstBD != NULL) {
[1e86d1e]1046    FrstBD->status |= BD_READY;
[f610e83f]1047  }
1048  sc->Tx_NxtFill_BD = CurrBD;
1049  /*
1050   * wake up transmitter (clear TSTAT[THLT])
1051   */
[1e86d1e]1052  sc->reg_ptr->tstat = TSEC_TSTAT_THLT;
[f610e83f]1053}
1054
1055/*=========================================================================*\
1056| Function:                                                                 |
1057\*-------------------------------------------------------------------------*/
[1e86d1e]1058static void tsec_txDaemon
[f610e83f]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{
[1e86d1e]1073  struct tsec_struct *sc =
1074    (struct tsec_struct *)arg;
[f610e83f]1075  struct ifnet *ifp = &sc->arpcom.ac_if;
1076  struct mbuf *m;
[bcd5368]1077  bool finished = false;
[f610e83f]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   */
[1e86d1e]1086  sc->reg_ptr->maccfg1 |= TSEC_MACCFG1_TXEN;
[f610e83f]1087  while (!finished) {
1088    /*
1089     * wait for events to come in
1090     */
[fca58924]1091    tsec_tx_wait_for_events(sc,
[359e537]1092                                             START_TRANSMIT_EVENT
[f610e83f]1093                                             | INTERRUPT_EVENT);
1094#if !defined(CLREVENT_IN_IRQ)
1095    /*
1096     * clear any pending TX events
1097     */
[1e86d1e]1098    irq_events = sc->reg_ptr->ievent & IEVENT_TXALL;
[f610e83f]1099    sc->reg_ptr->ievent = irq_events;
1100#endif
1101    /*
1102     * retire any sent tx BDs
1103     */
[1e86d1e]1104    tsec_tx_retire(sc);
[f610e83f]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);
[359e537]1113
[f610e83f]1114      if (m) {
[1e86d1e]1115        tsec_sendpacket(sc,m);
[f610e83f]1116      }
1117    } while (m != NULL);
1118
[359e537]1119    ifp->if_flags &= ~IFF_OACTIVE;
[f610e83f]1120  }
1121  /*
1122   * disable Tx in MACCFG1 register
1123   */
[1e86d1e]1124  sc->reg_ptr->maccfg1 &= ~TSEC_MACCFG1_TXEN;
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]1139static void tsec_tx_irq_handler
[f610e83f]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{
[1e86d1e]1154  struct tsec_struct *sc =
1155    (struct tsec_struct *)handle;
[f610e83f]1156#if defined(CLREVENT_IN_IRQ)
1157  uint32_t irq_events;
1158#endif
1159
[f2c8c34]1160  PF("TXIRQ\n");
[f610e83f]1161  sc->txInterrupts++;
1162  /*
1163   * disable tx interrupts
1164   */
[509040f0]1165  TSEC_IMASK_SET(sc,IEVENT_TXALL,0);
[f610e83f]1166
1167#if defined(CLREVENT_IN_IRQ)
1168  /*
1169   * clear any pending TX events
1170   */
[1e86d1e]1171  irq_events = sc->reg_ptr->ievent & IEVENT_TXALL;
[f610e83f]1172  sc->reg_ptr->ievent = irq_events;
1173#endif
1174  /*
1175   * wake up tx Daemon
1176   */
[26e90fb1]1177  rtems_bsdnet_event_send(sc->txDaemonTid, INTERRUPT_EVENT);
[f610e83f]1178}
1179
1180/*=========================================================================*\
1181| Function:                                                                 |
1182\*-------------------------------------------------------------------------*/
[1e86d1e]1183static void tsec_rx_irq_handler
[f610e83f]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{
[1e86d1e]1198  struct tsec_struct *sc =
1199    (struct tsec_struct *)handle;
[f610e83f]1200#if defined(CLREVENT_IN_IRQ)
1201  uint32_t irq_events;
1202#endif
1203
1204  sc->rxInterrupts++;
[f2c8c34]1205  PF("RXIRQ\n");
[f610e83f]1206  /*
1207   * disable rx interrupts
1208   */
[509040f0]1209  TSEC_IMASK_SET(sc,IEVENT_RXALL,0);
[f610e83f]1210#if defined(CLREVENT_IN_IRQ)
1211  /*
1212   * clear any pending RX events
1213   */
[1e86d1e]1214  irq_events = sc->reg_ptr->ievent & IEVENT_RXALL;
[f610e83f]1215  sc->reg_ptr->ievent = irq_events;
1216#endif
1217  /*
1218   * wake up rx Daemon<
1219   */
[26e90fb1]1220  rtems_bsdnet_event_send(sc->rxDaemonTid, INTERRUPT_EVENT);
[f610e83f]1221}
1222
1223
1224/*=========================================================================*\
1225| Function:                                                                 |
1226\*-------------------------------------------------------------------------*/
[1e86d1e]1227static void tsec_err_irq_handler
[f610e83f]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{
[1e86d1e]1242  struct tsec_struct *sc =
1243    (struct tsec_struct *)handle;
[f2c8c34]1244  PF("ERIRQ\n");
[f610e83f]1245  /*
[55a685b]1246   * clear error events in IEVENT
[f610e83f]1247   */
[1e86d1e]1248  sc->reg_ptr->ievent = IEVENT_ERRALL;
[f610e83f]1249  /*
[55a685b]1250   * has Rx been stopped? then restart it
[f610e83f]1251   */
[1e86d1e]1252  if (0 != (sc->reg_ptr->rstat & TSEC_RSTAT_QHLT)) {
[55a685b]1253    sc->rxErrors++;
[1e86d1e]1254    sc->reg_ptr->rstat = TSEC_RSTAT_QHLT;
[55a685b]1255  }
[f610e83f]1256  /*
[55a685b]1257   * has Tx been stopped? then restart it
[f610e83f]1258   */
[1e86d1e]1259  if (0 != (sc->reg_ptr->tstat & TSEC_TSTAT_THLT)) {
[55a685b]1260    sc->txErrors++;
[1e86d1e]1261    sc->reg_ptr->tstat = TSEC_TSTAT_THLT;
[55a685b]1262  }
[f610e83f]1263}
1264
1265
1266/*=========================================================================*\
1267| Function:                                                                 |
1268\*-------------------------------------------------------------------------*/
[1e86d1e]1269static uint32_t tsec_irq_mask
[f610e83f]1270(
1271/*-------------------------------------------------------------------------*\
1272| Purpose:                                                                  |
1273|   determine irq mask for given interrupt number                           |
1274+---------------------------------------------------------------------------+
1275| Input Parameters:                                                         |
[359e537]1276\*-------------------------------------------------------------------------*/
[f610e83f]1277 int irqnum,
[1e86d1e]1278 struct tsec_struct *sc
[f610e83f]1279)
1280/*-------------------------------------------------------------------------*\
1281| Return Value:                                                             |
1282|    interrupt mask (for ievent/imask register)                             |
1283\*=========================================================================*/
1284{
1285  return ((irqnum == sc->irq_num_tx)
[1e86d1e]1286          ? IEVENT_TXALL
[f610e83f]1287          : ((irqnum == sc->irq_num_rx)
[1e86d1e]1288             ? IEVENT_RXALL
[f610e83f]1289             : ((irqnum == sc->irq_num_err)
[1e86d1e]1290                ? IEVENT_ERRALL
[f610e83f]1291                : 0)));
1292}
1293/*=========================================================================*\
1294| Function:                                                                 |
1295\*-------------------------------------------------------------------------*/
[1e86d1e]1296static void tsec_irq_on
[f610e83f]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{
[1e86d1e]1312  struct tsec_struct *sc =
1313    (struct tsec_struct *)(irq_conn_data->handle);
[f610e83f]1314
[509040f0]1315  TSEC_IMASK_SET(sc,
[1e86d1e]1316                       tsec_irq_mask(irq_conn_data->name,sc),
[f610e83f]1317                       ~0);
1318}
1319
1320/*=========================================================================*\
1321| Function:                                                                 |
1322\*-------------------------------------------------------------------------*/
[1e86d1e]1323static void tsec_irq_off
[f610e83f]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{
[1e86d1e]1339  struct tsec_struct *sc =
1340    (struct tsec_struct *)irq_conn_data->handle;
[f610e83f]1341
[509040f0]1342  TSEC_IMASK_SET(sc,
[1e86d1e]1343                       tsec_irq_mask(irq_conn_data->name,sc),
[f610e83f]1344                       0);
1345}
1346
1347/*=========================================================================*\
1348| Function:                                                                 |
1349\*-------------------------------------------------------------------------*/
[1e86d1e]1350static int tsec_irq_isOn
[f610e83f]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{
[1e86d1e]1366  struct tsec_struct *sc =
1367    (struct tsec_struct *)irq_conn_data->handle;
[f610e83f]1368
[359e537]1369  return (0 != (sc->reg_ptr->imask
[1e86d1e]1370                & tsec_irq_mask(irq_conn_data->name,sc)));
[f610e83f]1371}
1372
1373/*=========================================================================*\
1374| Function:                                                                 |
1375\*-------------------------------------------------------------------------*/
[1e86d1e]1376static void tsec_install_irq_handlers
[f610e83f]1377(
1378/*-------------------------------------------------------------------------*\
1379| Purpose:                                                                  |
1380|   (un-)install the interrupt handlers                                     |
1381+---------------------------------------------------------------------------+
1382| Input Parameters:                                                         |
1383\*-------------------------------------------------------------------------*/
[1e86d1e]1384 struct tsec_struct *sc,        /* ptr to control structure        */
[bcd5368]1385 bool   install                         /* true: install, false: remove    */
[f610e83f]1386)
1387/*-------------------------------------------------------------------------*\
1388| Return Value:                                                             |
1389|    <none>                                                                 |
1390\*=========================================================================*/
1391{
[bcd5368]1392  size_t i;
[f610e83f]1393
1394  rtems_irq_connect_data irq_conn_data[3] = {
1395    {
1396      sc->irq_num_tx,
[1e86d1e]1397      tsec_tx_irq_handler, /* rtems_irq_hdl           */
[f610e83f]1398      (rtems_irq_hdl_param)sc,     /* (rtems_irq_hdl_param)   */
[1e86d1e]1399      tsec_irq_on,         /* (rtems_irq_enable)      */
1400      tsec_irq_off,        /* (rtems_irq_disable)     */
1401      tsec_irq_isOn        /* (rtems_irq_is_enabled)  */
[f610e83f]1402    },{
1403      sc->irq_num_rx,
[1e86d1e]1404      tsec_rx_irq_handler, /* rtems_irq_hdl           */
[f610e83f]1405      (rtems_irq_hdl_param)sc,     /* (rtems_irq_hdl_param)   */
[1e86d1e]1406      tsec_irq_on,         /* (rtems_irq_enable)      */
1407      tsec_irq_off,        /* (rtems_irq_disable)     */
1408      tsec_irq_isOn        /* (rtems_irq_is_enabled)  */
[f610e83f]1409    },{
1410      sc->irq_num_err,
[1e86d1e]1411      tsec_err_irq_handler, /* rtems_irq_hdl           */
[f610e83f]1412      (rtems_irq_hdl_param)sc,      /* (rtems_irq_hdl_param)   */
[1e86d1e]1413      tsec_irq_on,          /* (rtems_irq_enable)      */
1414      tsec_irq_off,         /* (rtems_irq_disable)     */
1415      tsec_irq_isOn         /* (rtems_irq_is_enabled)  */
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]1445static void tsec_init
[f610e83f]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{
[1e86d1e]1460  struct tsec_struct *sc = (struct tsec_struct *)arg;
[f610e83f]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 *));
[359e537]1475    sc->Tx_mBuf_Ptr = calloc(sc->txBdCount,sizeof(struct mbuf *));
[f610e83f]1476    if ((sc->Rx_mBuf_Ptr == NULL) ||
1477        (sc->Tx_mBuf_Ptr == NULL)) {
1478        rtems_panic("TSEC: cannot allocate buffers for mbuf management");
[359e537]1479
[f610e83f]1480    }
1481
1482    /*
1483     * initialize TSEC hardware:
1484     * - set interrupt coalescing to BDCount/8, Time of 8 frames
1485     * - enable DMA snooping
1486     */
[1e86d1e]1487    tsec_hwinit(sc);
[f610e83f]1488    /*
1489     * init access to phys
1490     */
[1e86d1e]1491    tsec_mdio_init(sc);
[f610e83f]1492    /*
1493     * Start driver tasks
1494     */
[359e537]1495    sc->txDaemonTid = rtems_bsdnet_newproc("TStx",
1496                                           4096,
[1e86d1e]1497                                           tsec_txDaemon,
[f610e83f]1498                                           sc);
[359e537]1499    sc->rxDaemonTid = rtems_bsdnet_newproc("TSrx", 4096,
[1e86d1e]1500                                           tsec_rxDaemon,
[f610e83f]1501                                           sc);
1502    /*
1503     * install interrupt handlers
1504     */
[1e86d1e]1505    tsec_install_irq_handlers(sc,true);
[f610e83f]1506  }
1507  /*
1508   * Set flags appropriately
1509   */
1510  if(ifp->if_flags & IFF_PROMISC) {
[1e86d1e]1511    sc->reg_ptr->rctrl |=  TSEC_RCTRL_PROM;
[f610e83f]1512  }
1513  else {
[1e86d1e]1514    sc->reg_ptr->rctrl &= ~TSEC_RCTRL_PROM;
[f610e83f]1515  }
1516
[c2bc9ef]1517#if defined(MPC83XX_BOARD_HSC_CM01)
[59be902]1518  /*
1519   * for HSC CM01: we need to configure the PHY to use maximum skew adjust
1520   */
[359e537]1521
[1e86d1e]1522  tsec_mdio_write(-1,sc,23,0x0100);
[59be902]1523#endif
1524
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]1538static void tsec_off
[f610e83f]1539(
1540/*-------------------------------------------------------------------------*\
1541| Purpose:                                                                  |
1542|   deinitialize the driver and the hardware                                |
1543+---------------------------------------------------------------------------+
1544| Input Parameters:                                                         |
1545\*-------------------------------------------------------------------------*/
[1e86d1e]1546 struct tsec_struct *sc         /* ptr to control structure        */
[f610e83f]1547)
1548/*-------------------------------------------------------------------------*\
1549| Return Value:                                                             |
1550|    <none>                                                                 |
1551\*=========================================================================*/
1552{
1553  /*
[55a685b]1554   * deinitialize driver?
[f610e83f]1555   */
1556}
1557
1558/*=========================================================================*\
1559| Function:                                                                 |
1560\*-------------------------------------------------------------------------*/
[1e86d1e]1561static void tsec_stats
[f610e83f]1562(
1563/*-------------------------------------------------------------------------*\
1564| Purpose:                                                                  |
[55a685b]1565|   print statistics                                                        |
[f610e83f]1566+---------------------------------------------------------------------------+
1567| Input Parameters:                                                         |
1568\*-------------------------------------------------------------------------*/
[1e86d1e]1569 struct tsec_struct *sc         /* ptr to control structure        */
[f610e83f]1570)
1571/*-------------------------------------------------------------------------*\
1572| Return Value:                                                             |
1573|    <none>                                                                 |
1574\*=========================================================================*/
1575{
[06280c35]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    }
[f610e83f]1593  }
[41d7c0fe]1594#if 0 /* print all PHY registers */
[42bf1b9]1595  {
1596    int reg;
1597    uint32_t reg_val;
1598    printf("****** PHY register values****\n");
1599    for (reg = 0;reg <= 31;reg++) {
[1e86d1e]1600      tsec_mdio_read(-1,sc,reg,&reg_val);
[42bf1b9]1601      printf("%02d:0x%04x%c",reg,reg_val,
1602             (((reg % 4) == 3) ? '\n' : ' '));
1603    }
1604  }
[359e537]1605#endif
[f610e83f]1606  /*
1607   * print some statistics
1608   */
[55a685b]1609  printf ("   Rx Interrupts:%-8lu",   sc->rxInterrupts);
1610  printf ("       Rx Errors:%-8lu",   sc->rxErrors);
[359e537]1611  printf ("      Rx packets:%-8lu\n",
[1e86d1e]1612          sc->reg_ptr->rmon_mib[TSEC_RMON_RPKT]);
[359e537]1613  printf ("   Rx broadcasts:%-8lu",
[1e86d1e]1614          sc->reg_ptr->rmon_mib[TSEC_RMON_RBCA]);
[359e537]1615  printf ("   Rx multicasts:%-8lu",
[1e86d1e]1616          sc->reg_ptr->rmon_mib[TSEC_RMON_RMCA]);
[55a685b]1617  printf ("           Giant:%-8lu\n",
[1e86d1e]1618          sc->reg_ptr->rmon_mib[TSEC_RMON_ROVR]);
[55a685b]1619  printf ("       Non-octet:%-8lu",
[1e86d1e]1620          sc->reg_ptr->rmon_mib[TSEC_RMON_RALN]);
[55a685b]1621  printf ("         Bad CRC:%-8lu",
[1e86d1e]1622          sc->reg_ptr->rmon_mib[TSEC_RMON_RFCS]);
[55a685b]1623  printf ("         Overrun:%-8lu\n",
[1e86d1e]1624          sc->reg_ptr->rmon_mib[TSEC_RMON_RDRP]);
[359e537]1625
[55a685b]1626  printf ("   Tx Interrupts:%-8lu",   sc->txInterrupts);
1627  printf ("       Tx Errors:%-8lu",   sc->txErrors);
[359e537]1628  printf ("      Tx packets:%-8lu\n",
[1e86d1e]1629          sc->reg_ptr->rmon_mib[TSEC_RMON_TPKT]);
[55a685b]1630  printf ("        Deferred:%-8lu",
[1e86d1e]1631          sc->reg_ptr->rmon_mib[TSEC_RMON_TDFR]);
[55a685b]1632  printf ("  Late Collision:%-8lu",
[1e86d1e]1633          sc->reg_ptr->rmon_mib[TSEC_RMON_TLCL]);
[55a685b]1634  printf ("Retransmit Limit:%-8lu\n",
[1e86d1e]1635          sc->reg_ptr->rmon_mib[TSEC_RMON_TEDF]);
[55a685b]1636  printf ("        Underrun:%-8lu\n",
[1e86d1e]1637          sc->reg_ptr->rmon_mib[TSEC_RMON_TUND]);
[f610e83f]1638}
1639
1640/*=========================================================================*\
1641| Function:                                                                 |
1642\*-------------------------------------------------------------------------*/
[1e86d1e]1643static int tsec_ioctl
[f610e83f]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{
[1e86d1e]1660  struct tsec_struct *sc = ifp->if_softc;
[f610e83f]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) {
[1e86d1e]1684      tsec_off(sc);
[f610e83f]1685    }
1686    if (ifp->if_flags & IFF_UP) {
[1e86d1e]1687      tsec_init(sc);
[f610e83f]1688    }
1689    break;
1690
1691  case SIO_RTEMS_SHOW_STATS:
1692    /*
1693     * show interface statistics
1694     */
[1e86d1e]1695    tsec_stats(sc);
[f610e83f]1696    break;
1697
1698    /*
[55a685b]1699     * All sorts of multicast commands need to be added here!
[f610e83f]1700     */
1701  default:
1702    error = EINVAL;
1703    break;
1704  }
1705
1706  return error;
1707}
1708
1709/*=========================================================================*\
1710| Function:                                                                 |
1711\*-------------------------------------------------------------------------*/
[1e86d1e]1712static int tsec_mode_adapt
[f610e83f]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{
[574fb67]1727  int result = 0;
[1e86d1e]1728  struct tsec_struct *sc = ifp->if_softc;
[574fb67]1729  int media = IFM_MAKEWORD( 0, 0, 0, sc->phy_default);
[f610e83f]1730
[f2c8c34]1731  /* In case no PHY is available stop now */
1732  if (sc->phy_default < 0) {
1733    return 0;
1734  }
1735
[f610e83f]1736  /*
1737   * fetch media status
1738   */
[1e86d1e]1739  result = tsec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
[f610e83f]1740  if (result != 0) {
1741    return result;
1742  }
[f2c8c34]1743
[f610e83f]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);
[1e86d1e]1758    result = tsec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media);
[f610e83f]1759    if (result != 0) {
1760      return result;
1761    }
1762    /*
[06280c35]1763     * check auto-negotiation status
[f610e83f]1764     */
[06280c35]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    }
[f610e83f]1770  }
1771
1772  /*
1773   * now set HW according to media results:
1774   */
1775  /*
[42bf1b9]1776   * if we are 1000MBit, then switch IF to byte mode
[f610e83f]1777   */
1778  if (IFM_1000_T == IFM_SUBTYPE(media)) {
[359e537]1779    sc->reg_ptr->maccfg2 =
[1e86d1e]1780      ((sc->reg_ptr->maccfg2 & ~TSEC_MACCFG2_IFMODE_MSK)
1781       | TSEC_MACCFG2_IFMODE_BYT);
[f610e83f]1782  }
1783  else {
[359e537]1784    sc->reg_ptr->maccfg2 =
[1e86d1e]1785      ((sc->reg_ptr->maccfg2 & ~TSEC_MACCFG2_IFMODE_MSK)
1786       | TSEC_MACCFG2_IFMODE_NIB);
[f610e83f]1787  }
[42bf1b9]1788  /*
1789   * if we are 10MBit, then switch rate to 10M
1790   */
1791  if (IFM_10_T == IFM_SUBTYPE(media)) {
[1e86d1e]1792    sc->reg_ptr->ecntrl &= ~TSEC_ECNTRL_R100M;
[42bf1b9]1793  }
1794  else {
[1e86d1e]1795    sc->reg_ptr->ecntrl |= TSEC_ECNTRL_R100M;
[42bf1b9]1796  }
[f610e83f]1797  /*
1798   * if we are half duplex then switch to half duplex
1799   */
1800  if (0 == (IFM_FDX & IFM_OPTIONS(media))) {
[1e86d1e]1801    sc->reg_ptr->maccfg2 &= ~TSEC_MACCFG2_FULLDUPLEX;
[f610e83f]1802  }
1803  else {
[1e86d1e]1804    sc->reg_ptr->maccfg2 |=  TSEC_MACCFG2_FULLDUPLEX;
[359e537]1805  }
[f610e83f]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\*-------------------------------------------------------------------------*/
[1e86d1e]1817static void tsec_watchdog
[f610e83f]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{
[1e86d1e]1833  tsec_mode_adapt(ifp);
[359e537]1834  ifp->if_timer    = TSEC_WATCHDOG_TIMEOUT;
[f610e83f]1835}
1836
[f2c8c34]1837static int tsec_driver_attach(struct rtems_bsdnet_ifconfig *config)
[f610e83f]1838{
[f2c8c34]1839  tsec_config *tsec_cfg = config->drv_ctrl;
1840  int unitNumber = tsec_cfg->unit_number;
1841  char *unitName = tsec_cfg->unit_name;
[1e86d1e]1842  struct tsec_struct *sc;
[f610e83f]1843  struct ifnet *ifp;
1844
1845 /*
1846  * Is driver free?
1847  */
[1e86d1e]1848  if ((unitNumber <= 0) || (unitNumber > TSEC_COUNT)) {
[f610e83f]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 */
[f2c8c34]1878  sc->reg_ptr         = tsec_cfg->reg_ptr;
1879  sc->mdio_ptr        = tsec_cfg->mdio_ptr;
[574fb67]1880
[f2c8c34]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;
[574fb67]1885
[f610e83f]1886  /*
1887   * setup info about mdio interface
1888   */
[1e86d1e]1889  sc->mdio_info.mdio_r   = tsec_mdio_read;
1890  sc->mdio_info.mdio_w   = tsec_mdio_write;
[f610e83f]1891  sc->mdio_info.has_gmii = 1; /* we support gigabit IF */
[574fb67]1892
[f2c8c34]1893  /* PHY address */
1894  sc->phy_default = tsec_cfg->phy_default;
[574fb67]1895
[f610e83f]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;
[1e86d1e]1903  ifp->if_init    = tsec_init;
1904  ifp->if_ioctl   = tsec_ioctl;
1905  ifp->if_start   = tsec_tx_start;
[f610e83f]1906  ifp->if_output  = ether_output;
[1e86d1e]1907  ifp->if_watchdog =  tsec_watchdog; /* XXX: timer is set in "init" */
[f610e83f]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
[1e86d1e]1926int tsec_driver_attach_detach(
1927  struct rtems_bsdnet_ifconfig *config,
1928  int attaching
[f610e83f]1929)
1930{
1931  if (attaching) {
[f2c8c34]1932    return tsec_driver_attach(config);
[1e86d1e]1933  } else {
[f610e83f]1934    return 0;
1935  }
1936}
Note: See TracBrowser for help on using the repository browser.