source: rtems/bsps/powerpc/haleakala/net/network.c @ 90232bc

5
Last change on this file since 90232bc was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

  • Property mode set to 100644
File size: 37.7 KB
Line 
1/*
2 *  network.c
3 *  RTEMS_490
4 *
5 *  Created by Michael Hamel on 18/11/08.
6 *
7 * This code is for the PPC405EX, 405EXr on the Haleakala board with an
8 * 88E1111 PHY.
9 * Its has some adaptations for the 405GP, and 405GPr (untested).
10 *
11 * It should handle dual interfaces correctly, but has not been tested.
12 *
13 */
14
15#include <machine/rtems-bsd-kernel-space.h>
16
17#include <bsp.h>
18#include <stdio.h>
19#include <errno.h>
20#include <rtems/error.h>
21#include <rtems/rtems_bsdnet.h>
22#include <rtems/rtems_mii_ioctl.h>
23#include <rtems/score/assert.h>
24
25#include <sys/param.h>
26#include <sys/mbuf.h>
27#include <sys/socket.h>
28#include <sys/sockio.h>
29
30#include <net/if.h>
31
32#include <netinet/in.h>
33
34#include <netinet/if_ether.h>
35#include <bsp/irq.h>
36
37#include <sys/types.h>
38#include <sys/socket.h>
39
40#include <ppc4xx/ppc405gp.h>
41#include <ppc4xx/ppc405ex.h>
42
43#define qDebug     /* General printf debugging */
44/* #define qMultiDebug */  /* Debugging for the multicast hardware filter */
45
46/*---------------------------- Hardware definitions -------------------------- */
47
48/* PHY addresses for Kilauea & Haleakala; defined by hardware */
49enum {
50  kPHY0 = 1,
51  kPHY1 = 2,
52  kMaxEMACs = 2
53};
54
55enum {
56  kMaxRxBuffers = 256,
57  kNXmtDescriptors = 256,  /* May as well use all of them */
58  kNoXmtBusy = 666    /* Arbitrary flag value outside 0..kNXmtDescriptors */
59};
60
61
62/*----------------------- Local variables for the driver -------------------------- */
63
64typedef struct MALDescriptor {
65  uint16_t ctrlBits;
66  uint16_t adrDataSize;  /* 4 bits of high address, 12 bits of length */
67  uint8_t* ptr;
68} MALDescriptor;
69
70typedef struct EMACLocals {
71    struct arpcom  arpcom;
72
73  /* Pointer to memory-mapped hardware */
74  volatile EthernetRegisters_GP*  EMAC;
75 
76    /* Transmit and receive task references */
77    rtems_id    rxDaemonTid;
78  rtems_id    txDaemonTid;
79  int        nRxBuffers;
80  int        xmtFreeIndex;
81  int        xmtBusyIndex;
82  MALDescriptor*  xmtDescTable;
83  MALDescriptor*  rcvDescTable;
84 
85  struct mbuf* rxMBufs[kMaxRxBuffers];
86  struct mbuf* txMBufs[kNXmtDescriptors];
87 
88  int      phyAddr,  /* PHY address */
89        phyState,  /* Last link state */
90        phyOUI,    /* Cached PHY type info */
91        phyModel,
92        phyRev;
93
94  /* Statistics */
95  uint32_t   rxInterrupts;
96  uint32_t   rxOverrun;
97  uint32_t   rxRunt;
98  uint32_t   rxBadCRC;
99  uint32_t   rxNonOctet;
100  uint32_t   rxGiant;
101 
102  uint32_t  txInterrupts;
103 
104  uint32_t  txLostCarrier;
105  uint32_t  txDeferred;
106  uint32_t  txOneCollision;
107  uint32_t  txMultiCollision;
108  uint32_t  txTooManyCollision;
109  uint32_t  txLateCollision;
110  uint32_t  txUnderrun;
111  uint32_t  txPoorSignal;
112} EMACLocals;
113
114
115EMACLocals gEmacs[kMaxEMACs];
116
117int ppc405_emac_phy_adapt(EMACLocals* ep);
118
119/*----------------------------------- Globals --------------------------------------*/
120
121/*
122   Pointers to the buffer descriptor tables used by the MAL. Tricky because they are both
123   read and written to by the MAL, which is unaware of the CPU data cache. As four 8-byte
124   descriptors fit into a single cache line this makes managing them in cached memory difficult.
125   Best solution is to label them as uncached using the MMU. This code assumes an appropriate
126   sized block stating at _enet_bdesc_base has been reserved by linkcmds and has been set up
127   with uncached MMU attrributes in bspstart.c */
128
129LINKER_SYMBOL(_enet_bdesc_start);    /* start of buffer descriptor space, from linkcmds */
130LINKER_SYMBOL(_enet_bdesc_end);      /* top limit, from linkcmds */
131
132static MALDescriptor* gTx0Descs = NULL;
133static MALDescriptor* gRx0Descs = NULL;
134static MALDescriptor* gTx1Descs = NULL; 
135static MALDescriptor* gRx1Descs = NULL;
136
137/*------------------------------------------------------------*/
138
139
140/*
141 * RTEMS event used by interrupt handler to signal driver tasks.
142 * This must not be any of the events used by the network task synchronization.
143 */
144#define INTERRUPT_EVENT      RTEMS_EVENT_1
145
146/*
147 * RTEMS event used to start transmit daemon.
148 * This must not be the same as INTERRUPT_EVENT.
149 */
150#define START_TRANSMIT_EVENT  RTEMS_EVENT_2
151
152#define _sync    __asm__ volatile ("sync\n"::)
153
154#define  kCacheLineMask  (PPC_CACHE_ALIGNMENT - 1)
155
156
157/*----------------------- IRQ handler glue -----------------------*/
158
159static void InstallIRQHandler(rtems_irq_number id,
160                rtems_irq_hdl handler,
161                rtems_irq_enable turnOn,
162                rtems_irq_disable turnOff)
163{
164  rtems_irq_connect_data params;
165 
166  params.name = id;
167  params.hdl = handler;
168  params.on = turnOn;
169  params.off = turnOff;
170  params.isOn = NULL;
171  params.handle = NULL;
172  if (! BSP_install_rtems_irq_handler(&params))
173    rtems_panic ("Can't install interrupt handler");
174}
175
176static void
177NoAction(const rtems_irq_connect_data* unused)
178{
179  /* printf("NoAction %d\n",unused->name); */
180}
181
182
183/*------------------------ PHY interface -------------------------- */
184/* This code recognises and works with the 88E1111 only. Other PHYs
185   will require appropriate adaptations to this code */
186   
187enum {
188  kPHYControl = 0,
189   kPHYReset = 0x8000,
190  kPHYStatus = 1,
191   kPHYLinkStatus = 0x0004,
192  kPHYID1 = 2,
193  kPHYID2 = 3,
194  kPHYAutoNegExp = 6,
195  kPHY1000BaseTCtl = 9,
196  kPHYExtStatus = 15,
197 
198  /* 88E1111 identification */
199  kMarvellOUI = 0x5043,
200  k88E1111Part = 0x0C,
201
202  /* 88E1111 register addresses */
203  k8PHYSpecStatus = 17,
204    k8PHYSpeedShift = 14,
205    k8PHYDuplex    = 0x2000,
206    k8PHYResolved  = 0x0800,
207    k8PHYLinkUp    = 0x0400,
208  k8IntStatus = 19,
209  k8IntEnable = 18,
210   k8AutoNegComplete = 0x0800,
211   k8LinkStateChanged = 0x0400,
212  k8ExtCtlReg = 20,
213    k8RcvTimingDelay = 0x0080,
214    k8XmtTimingDelay = 0x0002,
215    k8XmtEnable      = 0x0001,
216  k8LEDCtlReg = 24,
217  k8ExtStatusReg = 27,
218};
219
220
221static uint16_t ReadPHY(EMACLocals* ep, uint8_t reg)
222{
223  int n = 0;
224  uint32_t t;
225 
226  reg &= 0x1F;
227 
228  /* 405EX-specific! */
229  while ((ep->EMAC->STAcontrol & keSTARun) != 0)
230    { ; }
231  ep->EMAC->STAcontrol = keSTADirectRd + (ep->phyAddr<<5) + reg;
232  ep->EMAC->STAcontrol |= keSTARun;
233  /* Wait for the read to complete, should take ~25usec */
234  do {
235    t = ep->EMAC->STAcontrol;
236    if (++n > 200000)
237      rtems_panic("PHY read timed out");
238  } while ((t & keSTARun) != 0);
239 
240  if (t & kSTAErr)
241    rtems_panic("PHY read failed");
242  return t >> 16;
243}
244
245static void WritePHY(EMACLocals* ep, uint8_t reg, uint16_t value)
246{
247
248  reg &= 0x1F;
249 
250  /* 405EX-specific */
251  while ((ep->EMAC->STAcontrol & keSTARun) != 0)
252    { ; }
253  ep->EMAC->STAcontrol = (value<<16) | keSTADirectWr | (ep->phyAddr<<5) | reg;
254  ep->EMAC->STAcontrol |= keSTARun;
255}
256
257static void ResetPHY(EMACLocals* ep)
258{
259  int n;
260 
261  n = ReadPHY(ep, kPHYControl);
262  n |= kPHYReset;
263  WritePHY(ep, kPHYControl, n);
264  do {
265    rtems_task_wake_after( (rtems_bsdnet_ticks_per_second/20) + 1 );
266    n = ReadPHY(ep, kPHYControl);
267  } while ((n & kPHYReset)!=0);
268}
269
270enum {
271  kELinkUp = 0x80,
272  kELinkFullDuplex = 0x40,
273  kELinkSpeed10 = 0,
274  kELinkSpeed100 = 1,
275  kELinkSpeed1000 = 2,
276  kELinkSpeedMask = 3
277};
278
279static int GetPHYLinkState(EMACLocals* ep)
280/* Return link state (up/speed/duplex) as a set of flags */
281{
282  int state, result;
283 
284  /* if (ep->phyOUI==kMarvellOUI) */
285  result = 0;
286  state = ReadPHY(ep,k8PHYSpecStatus);
287  if ((state & k8PHYLinkUp) && (state & k8PHYResolved)) {
288    result |= kELinkUp;
289    if (state & k8PHYDuplex) result |= kELinkFullDuplex;
290    result |= ((state >> k8PHYSpeedShift) & 3);
291  }
292  return result;
293}
294
295/*---------------------- PHY setup ------------------------*/
296
297
298static void InitPHY(EMACLocals* ep)
299{
300  int id,id2,n;
301 
302  id = ReadPHY(ep,kPHYID1);
303  id2 = ReadPHY(ep,kPHYID2);
304  ep->phyOUI = (id<<6) + (id2>>10);
305  ep->phyModel = (id2>>4) & 0x1F;
306  ep->phyRev = id2 & 0xF;
307 
308  #ifdef qDebug
309    printf("PHY %d maker $%X model %d revision %d\n",ep->phyAddr,ep->phyOUI,ep->phyModel,ep->phyRev);
310  #endif
311 
312  /* Test for PHYs that we understand; insert new PHY types initialisation here */
313  if (ep->phyOUI == kMarvellOUI || ep->phyModel == k88E1111Part) {
314    /* 88E111-specific: Enable RxTx timing control, enable transmitter */
315    n = ReadPHY(ep, k8ExtCtlReg);
316    n |= k8RcvTimingDelay + k8XmtTimingDelay + k8XmtEnable;   
317    WritePHY(ep, k8ExtCtlReg, n);
318   
319    /* Set LED mode; Haleakala has LINK10 and TX LEDs only. Set up to do 100/1000 and link up/active*/
320    WritePHY(ep, k8LEDCtlReg, 0x4109);
321   
322    /* Need to do a reset after fiddling with registers*/
323    ResetPHY(ep);
324  } else
325    rtems_panic("Unknown PHY type");
326}
327
328
329/*--------------------- Interrupt handlers for the MAL ----------------------------- */
330
331static void
332MALTXDone_handler(rtems_irq_hdl_param param)
333{
334  int n;
335 
336  n = PPC_DEVICE_CONTROL_REGISTER(MAL0_TXEOBISR);
337  if (n & kMALChannel0) {
338    gEmacs[0].txInterrupts++;
339    rtems_event_send (gEmacs[0].txDaemonTid, INTERRUPT_EVENT);
340  }
341  if (n & kMALChannel1) {
342    gEmacs[1].txInterrupts++;
343    rtems_event_send (gEmacs[1].txDaemonTid, INTERRUPT_EVENT);
344  }
345  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXEOBISR,n);
346}
347
348static void
349MALRXDone_handler (rtems_irq_hdl_param param)
350{
351  int n;
352 
353  n = PPC_DEVICE_CONTROL_REGISTER(MAL0_RXEOBISR);
354  if (n & kMALChannel0) {
355    gEmacs[0].rxInterrupts++;
356    rtems_event_send (gEmacs[0].rxDaemonTid, INTERRUPT_EVENT);
357  }
358  if (n & kMALChannel1) {
359    gEmacs[1].rxInterrupts++;
360    rtems_event_send (gEmacs[1].rxDaemonTid, INTERRUPT_EVENT);
361  }
362  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXEOBISR,n);  /* Write back to clear interrupt */
363}
364
365/* These handlers are useful for debugging, but we don't actually need to process these interrupts */
366
367static void
368MALErr_handler (rtems_irq_hdl_param param)
369{
370  uint32_t errCause;
371 
372  errCause = PPC_DEVICE_CONTROL_REGISTER(MAL0_ESR);
373  /* Clear the error */
374  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_ESR,errCause);
375}
376 
377static void
378EMAC0Err_handler (rtems_irq_hdl_param param)
379{
380  uint32_t errCause;
381 
382  errCause = gEmacs[0].EMAC->intStatus;
383  /* Clear error by writing back */
384  gEmacs[0].EMAC->intStatus = errCause;
385}
386
387static void
388EMAC1Err_handler (rtems_irq_hdl_param param)
389{
390  uint32_t errCause;
391 
392  errCause = gEmacs[1].EMAC->intStatus;
393  /* Clear error by writing back */
394  gEmacs[1].EMAC->intStatus = errCause;
395}
396
397
398/*--------------------- Low-level hardware initialisation ----------------------------- */
399
400
401
402static void
403mal_initialise(void)
404
405  uint32_t bdescbase;
406  int nBytes, ntables;
407 
408  /*------------------- Initialise the MAL for both channels ---------------------- */
409     
410  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_CFG,kMALReset);
411  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCARR, kMALChannel0 | kMALChannel1);
412  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCARR, kMALChannel0 | kMALChannel1);
413
414  /* Acquire MAL interrupts */
415  InstallIRQHandler(BSP_UIC_MALTXEOB, MALTXDone_handler, NoAction, NoAction);
416  InstallIRQHandler(BSP_UIC_MALRXEOB, MALRXDone_handler, NoAction, NoAction);
417  InstallIRQHandler(BSP_UIC_MALSERR, MALErr_handler, NoAction, NoAction);
418   
419  /* Set up the buffer descriptor tables */
420  bdescbase = (uint32_t)(_enet_bdesc_start);
421  nBytes = sizeof(MALDescriptor) * 256;
422  ntables = 4;
423  if (get_ppc_cpu_type() != PPC_405EX) {
424    /* The 405GP/GPr requires table bases to be 4K-aligned and can use two tx channels on one EMAC */
425    nBytes = (nBytes + 0x0FFF) & ~0x0FFF;
426    bdescbase = (bdescbase + 0x0FFF) & ~0x0FFF;
427    ntables = 3;
428  }
429 
430  /* printf("Buffer descriptors at $%X..$%X, code from $%X\n",bdescbase, bdescbase + nBytes*ntables - 1,(uint32_t)&_text_start); */
431 
432  /* Check that we have been given enough space and the buffers don't run past the enet_bdesc_end address */
433  if (bdescbase + nBytes*ntables > (uint32_t)_enet_bdesc_end)
434    rtems_panic("Ethernet descriptor space insufficient!");
435   
436  gTx0Descs = (MALDescriptor*)bdescbase;
437  gTx1Descs = (MALDescriptor*)(bdescbase + nBytes);
438  gRx0Descs = (MALDescriptor*)(bdescbase + nBytes*2);
439  /* Clear the buffer descriptor tables */
440  memset(gTx0Descs, 0, sizeof(MALDescriptor)*256);
441  memset(gTx1Descs, 0, sizeof(MALDescriptor)*256);
442  memset(gRx0Descs, 0, sizeof(MALDescriptor)*256);
443  if (get_ppc_cpu_type() == PPC_405EX) {
444    gRx1Descs = (MALDescriptor*)(bdescbase + nBytes*3);
445    memset(gRx1Descs, 0, sizeof(MALDescriptor)*256);
446  }
447 
448  /* Set up the MAL registers */
449  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCTP0R,gTx0Descs);
450  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCTP1R,gTx1Descs);
451  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCTP0R,gRx0Descs);
452  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RCBS0, (MCLBYTES-16)>>4);    /* The hardware writes directly to the mbuf clusters, so it can write MCLBYTES */
453  if (get_ppc_cpu_type() == PPC_405EX) {
454    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_CFG,kMALMedHiPriority + keMALRdMaxBurst32 + keMALWrMedHiPriority + keMALWrMaxBurst32 +
455                       kMALLocksOPB + kMALLocksErrs + kMALCanBurst);
456    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCTP1R,gRx1Descs);
457    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RCBS1, (MCLBYTES-16)>>4);
458    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_IER,0xF7);    /* Enable all MAL interrupts */
459  } else {
460    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_CFG,kMALMedHiPriority + kMALLocksOPB + kMALLocksErrs + kMALCanBurst + kMALLatency8);
461    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_IER,0x1F);    /* Enable all MAL interrupts */
462  }
463}
464
465
466
467#ifdef qDebug
468static void printaddr(uint8_t* enetaddr)
469{
470  printf("%02X.%02X.%02X.%02X.%02X.%02X",enetaddr[0],enetaddr[1],enetaddr[2],enetaddr[3],enetaddr[4],enetaddr[5]);
471}
472#endif
473
474static bool gMALInited = FALSE;
475 
476static void
477ppc405_emac_initialize_hardware(EMACLocals* ep)
478{
479
480  int  n,mfr;
481  int  unitnum = ep->arpcom.ac_if.if_unit;
482 
483  if (get_ppc_cpu_type() == PPC_405EX) {
484    /* PPC405EX: configure the RGMII bridge and clocks */
485    RGMIIRegisters* rgmp = (RGMIIRegisters*)RGMIIAddress;
486    rgmp->FER = 0x00080055;  /* Both EMACs RGMII */
487    rgmp->SSR = 0x00000044;  /* Both EMACs 1000Mbps */
488    /* Configure the TX clock to be external */
489    mfsdr(SDR0_MFR,mfr);
490    mfr &= ~0x0C000000;    /* Switches both PHYs */
491    mtsdr(SDR0_MFR,mfr);
492  }
493 
494  /* Reset the EMAC */
495  n = 0;
496  ep->EMAC->mode0 = kEMACSoftRst;             
497  while ((ep->EMAC->mode0 & kEMACSoftRst) != 0)
498    n++;    /* Wait for it to complete */
499 
500  /* Set up so we can talk to the PHY */
501  ep->EMAC->mode1 = keEMACIPHYAddr4 |  keEMACOPB100MHz;
502 
503  /* Initialise the PHY  */
504  InitPHY(ep);
505 
506  /* Initialise the MAL (once only) */
507  if ( ! gMALInited) {
508    mal_initialise();
509    gMALInited = TRUE;
510  }
511
512  /* Set up IRQ handlers and enable the MAL channels for this port */
513  if (unitnum==0) {
514    ep->xmtDescTable = gTx0Descs;
515    ep->rcvDescTable = gRx0Descs;
516    InstallIRQHandler(BSP_UIC_EMAC0, EMAC0Err_handler, NoAction, NoAction);
517    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCASR,kMALChannel0);
518    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCASR,kMALChannel0);
519  } else {
520    ep->xmtDescTable = gTx1Descs;
521    ep->rcvDescTable = gRx1Descs;
522    InstallIRQHandler(BSP_UIC_EMAC1, EMAC1Err_handler, NoAction, NoAction);
523    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCASR,kMALChannel1);
524    PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCASR,kMALChannel1);
525  }
526 
527  /* The rest of the EMAC initialisation is done in emac_phy_adapt
528     when we know what the characteristics of the link are */
529}
530
531
532/* EMAC second stage initialisation; talks to the PHY to find out how to do it.
533   Resets the EMAC if the PHY parameters need to be changed */
534 
535int ppc405_emac_phy_adapt(EMACLocals* ep)
536{
537  int linkState = GetPHYLinkState(ep);
538  int spd;
539 
540  if ((linkState & kELinkUp) && (linkState != ep->phyState)) {
541    /* Reset the EMAC and set registers according to PHY state */
542    int i,n = 0;
543    uint32_t mode, rmode;
544   
545    ep->EMAC->mode0 = kEMACSoftRst;             
546    while ((ep->EMAC->mode0 & kEMACSoftRst) != 0)
547      n++;    /* Wait for it to complete */
548    spd = linkState & kELinkSpeedMask;
549    mode = (spd<<22) | kgEMACTx0Multi;
550    if (get_ppc_cpu_type() == PPC_405EX)
551      mode |= (keEMAC16KRxFIFO | keEMAC16KTxFIFO | keEMACIPHYAddr4 | keEMACOPB100MHz );
552    else
553      mode |= (kgEMAC4KRxFIFO | kgEMAC2KTxFIFO);
554    if (linkState & kELinkFullDuplex)
555      mode |= kEMACFullDuplex + kEMACDoFlowControl;
556    if ( (linkState & kELinkFullDuplex) || (spd > kELinkSpeed10) )
557      mode |= kEMACIgnoreSQE;
558 
559   
560    if (spd==kELinkSpeed1000) {
561      /* Gigabit, so we support jumbo frames. Take appropriate measures: adjust the if_mtu */
562      /* Note that we do this here because changing it later doesn't work very well : see
563         the SIOCSIFMTU discussion below */
564      struct ifnet* ifp = &ep->arpcom.ac_if;
565      ifp->if_mtu = ETHERMTU_JUMBO;
566      mode |= keEMACJumbo;
567    }
568   
569   
570    ep->phyState = linkState;
571    ep->EMAC->mode1 = mode;
572   
573    /* Install 48-bit hardware address that we have been given */
574    ep->EMAC->addrHi = (ep->arpcom.ac_enaddr[0]<<8) + ep->arpcom.ac_enaddr[1];
575    ep->EMAC->addrLo = (ep->arpcom.ac_enaddr[2]<<24) + (ep->arpcom.ac_enaddr[3]<<16)
576            + (ep->arpcom.ac_enaddr[4]<<8) + (ep->arpcom.ac_enaddr[5] );
577   
578    /* Set receive mode appropriately */
579    rmode = kEMACStripPadding + kEMACStripFCS + kEMACBrcastRcv;
580   
581    if (ep->arpcom.ac_if.if_flags & IFF_PROMISC) rmode |= kEMACPromiscRcv;
582                        else rmode |= kEMACIndivRcv;
583    if (get_ppc_cpu_type() == PPC_405EX)
584      rmode |= keEMACRxFIFOAFMax; 
585    if ((ep->arpcom.ac_if.if_flags & IFF_ALLMULTI) != 0)
586      rmode |= kEMACPromMultRcv;
587    else if ((ep->arpcom.ac_if.if_flags & IFF_MULTICAST) != 0)
588      rmode |= kEMACMultcastRcv;
589   
590    ep->EMAC->rcvMode = rmode;
591
592    if (get_ppc_cpu_type() == PPC_405EX)
593      for (i=0; i<8; i++)
594        ep->EMAC->e_groupHash[i] = 0;
595    else
596      for (i=0; i<4; i++)
597        ep->EMAC->g_groupHash[i] = 0;
598
599    if (get_ppc_cpu_type() == PPC_405EX) {
600      /* Rcv low watermark, must be < mode1 Rcv FIFO size and > MAL burst length (default 64x4 bytes), 16-byte units
601         High watermark must be > low and < RcvFIFO size */
602      ep->EMAC->rcvWatermarks = (16<<22) + (768<<6);
603      /* Xmt low request must be >= 17 FIFO entries, Xmt urgent must be > low */
604      ep->EMAC->xmtMode1 = (17<<27) + (68<<14);      /* TLR = 17, TUR = 68 */
605      /* Xmt partial packet request threshold */
606      ep->EMAC->xmtReqThreshold = ((1000>>2)-1) << 24;  /* TRTR[TRT] = 1000 FIFO entries */
607    } else {
608      ep->EMAC->rcvWatermarks = (15<<24) + (32<<8);
609      ep->EMAC->xmtReqThreshold = ((1448>>6)-1) << 26;  /* TRT = 1024b */
610      ep->EMAC->xmtMode1 = 0x40200000;          /* TLR = 8w=32b, TUR=32w=128b */
611    }
612     
613    ep->EMAC->IPGap = 8;
614   
615    /* Want EMAC interrupts for error logging & statistics */
616    ep->EMAC->intEnable = kEMACIOverrun + kEMACIPause + kEMACIBadPkt + kEMACIRuntPkt + kEMACIShortEvt
617              + kEMACIAlignErr + kEMACIBadFCS + kEMACIOverSize + kEMACILLCRange + kEMACISQEErr
618              + kEMACITxErr;
619           
620    /* Start it running */
621    ep->EMAC->mode0 = kEMACRxEnable + kEMACTxEnable;   
622    return 0;
623  } else
624    return -1;
625}
626
627
628static void
629ppc405_emac_disable(EMACLocals* ep)
630/* Disable the EMAC channels so we stop running and processing interrupts */
631{
632  ep->EMAC->mode0 = 0;
633}
634
635static void
636ppc405_emac_startxmt(EMACLocals* ep)
637/* Start the transmitter: set TMR0[GNP] */
638{
639  ep->EMAC->xmtMode0 = kEMACNewPacket0 + 7;    /* *** TFAE value for EX */
640}
641
642static void ppc405_emac_watchdog(struct ifnet* ifp)
643/* Called if a transmit stalls or when the interface is down. Check the PHY
644   until we get a valid link */
645{
646  EMACLocals* ep = ifp->if_softc;
647 
648  if (ppc405_emac_phy_adapt(ep)==0) {
649    ep->arpcom.ac_if.if_flags |= IFF_RUNNING;
650    ifp->if_timer = 0;    /* No longer needed */
651  } else
652    ifp->if_timer = 1;    /* reschedule, once a second */
653}
654
655
656
657/*----------------------- The transmit daemon/task -------------------------- */
658
659
660static void
661FreeTxDescriptors(EMACLocals* ep)
662/* Make descriptors and mbufs at xmtBusyIndex available for re-use if the packet that they */
663/* point at has all gone */
664{
665  uint16_t scan, status;
666 
667  if (ep->xmtBusyIndex != kNoXmtBusy) {
668    scan = ep->xmtBusyIndex;
669    while (TRUE) {
670      /* Scan forward through the descriptors */
671      status = ep->xmtDescTable[scan].ctrlBits;
672      if (++scan >= kNXmtDescriptors)
673        scan = 0;
674      /* If we find a ready (i.e not-yet-sent) descriptor, stop */
675      if ((status & kMALTxReady) != 0)
676        break;
677      /* If we find a last descriptor, we can free all the buffers up to and including it */
678      if ((status & kMALLast) != 0) {
679        /* End of packet and it has been sent or abandoned; advance xmtBusyIndex to  */
680        /* the next buffer and free buffers. */
681        if ((status & kEMACErrMask) != 0) {
682          /* Transmit error of some kind */
683         
684          if ((status & kEMACDeferred) != 0)
685            ep->txDeferred++;
686          if ((status & kEMACLostCarrier) != 0)
687            ep->txLostCarrier++;  /* *** Perhaps more serious reaction needed... */
688         
689          if ((status & kEMACLateColl) != 0)
690            ep->txLateCollision++;
691          if ((status & kEMACOneColl) != 0)
692            ep->txOneCollision++;
693          if ((status & kEMACMultColl) != 0)
694            ep->txMultiCollision++;
695          if ((status & kEMACCollFail) != 0)
696            ep->txTooManyCollision++;
697         
698          if ((status & kEMACSQEFail) != 0)
699            ep->txPoorSignal++;
700          if ((status & kEMACUnderrun) != 0)
701            ep->txUnderrun++;
702        }
703        while (ep->xmtBusyIndex != scan) {
704          m_free(ep->txMBufs[ep->xmtBusyIndex]);
705          if (++ep->xmtBusyIndex >= kNXmtDescriptors) ep->xmtBusyIndex = 0;
706        }
707        if (ep->xmtBusyIndex == ep->xmtFreeIndex) {
708          /* Nothing is busy */
709          ep->xmtBusyIndex = kNoXmtBusy;
710          break;
711        }
712      }
713    }
714  }
715}
716
717
718static void
719SendPacket (EMACLocals* ep, struct ifnet *ifp, struct mbuf *m)
720/* Given a chain of mbufs, set up a transmit description and fire it off */
721{
722  int nAdded, index, lastidx = -1, totalbytes;
723  uint16_t status;
724  struct mbuf* lastAdded;
725 
726  nAdded = 0;
727  totalbytes = 0;
728  lastAdded = NULL;
729  index = ep->xmtFreeIndex;
730 
731  /* Go through the chain of mbufs setting up descriptors for each */
732  while (m != NULL) {
733         
734    if (m->m_len == 0) {
735      /* Can be empty: dispose and unlink from chain */
736      m = m_free(m);
737      if (lastAdded!=NULL) lastAdded->m_next = m;
738    } else {
739      /* Make sure the mbuf has been written to memory */
740      rtems_cache_flush_multiple_data_lines(mtod (m, void *), m->m_len);
741      /* If there are no descriptors available wait until there are */
742      while (index == ep->xmtBusyIndex) {
743        rtems_event_set events;
744        ifp->if_timer = 2;
745        /* Then check for free descriptors, followed by: */
746        rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events);
747        FreeTxDescriptors(ep);
748      }
749       
750      /* Fill in a descriptor for this mbuf and record it */
751      ep->txMBufs[index] = m;
752      ep->xmtDescTable[index].ptr = mtod (m, void *);
753      ep->xmtDescTable[index].adrDataSize = m->m_len;
754      /* Fill in ctrlBits as we go but don't mark the first one as ready yet */
755      status = kEMACGenFCS + kEMACGenPad + kEMACRepSrcAddr;
756      if (nAdded > 0)
757        status |= kMALTxReady;
758      if (index==kNXmtDescriptors-1)
759        status |= kMALWrap;
760      ep->xmtDescTable[index].ctrlBits = status;
761      lastidx = index;
762         
763      totalbytes += m->m_len;
764      lastAdded = m;
765      m = m->m_next;
766      nAdded++;
767     
768      index += 1;
769      if (index==kNXmtDescriptors)
770        index = 0;
771     
772      if (nAdded==kNXmtDescriptors)
773        rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);    /* This is impossible, of course... */
774    }
775  }
776
777  _Assert( lastidx != -1 );
778
779  if (nAdded > 0) {
780    /* Done and we added some buffers */
781    /* Label the last buffer and ask for an interrupt */
782    ep->xmtDescTable[lastidx].ctrlBits |= kMALLast + kMALInterrupt;
783    /* Finally set the ready bit on the first buffer */
784    ep->xmtDescTable[ep->xmtFreeIndex].ctrlBits |= kMALTxReady;
785    /* Make sure this has been written */
786    _sync;
787    if (ep->xmtBusyIndex == kNoXmtBusy)
788      ep->xmtBusyIndex = ep->xmtFreeIndex;
789    ep->xmtFreeIndex = index;
790    /* Poke the EMAC to get it started (which may not be needed if its already running */
791    ppc405_emac_startxmt(ep);
792    ifp->if_timer = 2;
793  }
794}
795
796static void
797ppc405_emac_txDaemon (void* param)
798{
799  EMACLocals* ep = param;
800  struct ifnet *ifp = &ep->arpcom.ac_if;
801  struct mbuf *m;
802  rtems_event_set events;
803
804  ep->xmtFreeIndex = 0;
805  ep->xmtBusyIndex = kNoXmtBusy;
806  while (TRUE) {
807    /* Wait for someone wanting to transmit */
808    rtems_bsdnet_event_receive (START_TRANSMIT_EVENT | INTERRUPT_EVENT,
809                  RTEMS_EVENT_ANY | RTEMS_WAIT,
810                  RTEMS_NO_TIMEOUT,
811                  &events);
812    if (events & INTERRUPT_EVENT)
813      ifp->if_timer = 0;
814    /* Grab packets and send until empty */
815    /* Note that this doesn't (at the time of writing, RTEMS 4.9.1), ever get asked to send more than
816       one header mbuf and one data mbuf cluster, regardless of the MTU. This is because sosend() in the FreeBSD
817       stack only passes one mbuf at a time across to tcp_send, which immediately sends it */
818    while (TRUE) {
819      FreeTxDescriptors(ep);
820      IF_DEQUEUE(&ifp->if_snd, m);
821      if (m == NULL)
822        break;
823      SendPacket (ep, ifp, m);
824    }
825    ifp->if_flags &= ~IFF_OACTIVE;
826  }
827}
828
829/*----------------------- The receive daemon/task -------------------------- */
830
831static void
832MakeRxBuffer(EMACLocals* ep, int index)
833{
834  struct mbuf*   m;
835 
836  /* Allocate an mbuf, wait if necessary, label as dynamic data, start of record */
837  MGETHDR (m, M_WAIT, MT_DATA);
838  /* Allocate a cluster buffer to this mbuf, waiting if necessary */
839  MCLGET (m, M_WAIT);
840  /* Set up reference to the interface the packet will be received on */
841  m->m_pkthdr.rcvif = &ep->arpcom.ac_if;
842  ep->rxMBufs[index] = m;
843  ep->rcvDescTable[index].ptr = mtod (m, uint8_t*);
844  ep->rcvDescTable[index].adrDataSize = 0x0EEE;    /* Precaution */
845  if (index==ep->nRxBuffers-1)
846    ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt + kMALWrap;
847  else
848    ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt;
849}
850
851
852
853static void
854ppc405_emac_rxDaemon (void* param)
855{
856  EMACLocals* ep = param;
857  int     index,n,mdex;
858  struct mbuf*   m;
859  struct mbuf*    mstart = NULL;
860  struct mbuf*    mlast = NULL;
861  struct ifnet*  ifp;
862  struct ether_header* eh = NULL;
863  rtems_event_set events;
864 
865  /* Startup : allocate a bunch of receive buffers and point the descriptor table entries at them */
866  ifp = &ep->arpcom.ac_if;
867  index = 0;
868  while (index < ep->nRxBuffers) {
869    MakeRxBuffer(ep,index);
870    index += 1;
871  }
872  index = 0;
873  mdex = 0;
874 
875  /* Loop waiting for frames to arrive */
876  while (TRUE) {
877    rtems_bsdnet_event_receive (INTERRUPT_EVENT,
878                      RTEMS_WAIT | RTEMS_EVENT_ANY,
879                      RTEMS_NO_TIMEOUT,
880                      &events);
881    while ((ep->rcvDescTable[index].ctrlBits & kMALRxEmpty) == 0) {
882      /* Got a frame */
883      uint16_t flags = ep->rcvDescTable[index].ctrlBits;
884      if ((flags & kEMACErrMask) != 0) {
885        /* It has errors. Update statistics */
886        if ((flags & kEMACOverrun) != 0)
887          ep->rxOverrun++;
888        if ((flags & kEMACRuntPkt) != 0)
889          ep->rxRunt++;
890        if ((flags & kEMACBadFCS) != 0)
891          ep->rxBadCRC++;
892        if ((flags & kEMACAlignErr) != 0)
893          ep->rxNonOctet++;
894        if ((flags & kEMACPktLong) != 0)
895          ep->rxGiant++;
896        /* and reset descriptor to empty */
897       
898        /* No need to get new mbufs, just reset */
899        ep->rcvDescTable[index].adrDataSize = 0x0EEE;
900        if (index==ep->nRxBuffers-1)
901          ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt + kMALWrap;
902        else
903          ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt;
904       
905      } else {
906        /* Seems to be OK. Invalidate cache over the size we received */
907        n = ep->rcvDescTable[index].adrDataSize & 0x0FFF;
908        m = ep->rxMBufs[index];
909        rtems_cache_invalidate_multiple_data_lines(m->m_data, (n + kCacheLineMask) & ~kCacheLineMask);
910       
911        /* Consider copying small packets out of the cluster into m_pktdat to save clusters? */
912        m->m_len = n;
913         
914        /* Jumbo packets will span multiple mbufs; chain them together and submit when we get the last one */
915        if (flags & kMALRxFirst) {
916          /* First mbuf in the packet */
917          if (mstart!=NULL)
918            rtems_panic("first, no last");
919         
920          /* Adjust the mbuf pointers to skip the header and set eh to point to it */
921          m->m_len -= sizeof(struct ether_header);
922          m->m_pkthdr.len = m->m_len;
923          eh = mtod (m, struct ether_header *);
924          m->m_data += sizeof(struct ether_header);
925          mstart = m;
926          mlast = m;
927          mdex = index;
928        } else {
929          /* Chain onto mstart: add length to pkthdr.len */
930          if (mstart == NULL)
931            rtems_panic("last, no first");
932         
933          mstart->m_pkthdr.len += n;
934          m->m_flags &= ~M_PKTHDR;
935          mlast->m_next = m;
936          mlast = m;
937        }
938       
939        if (flags & kMALLast) {
940          /* Last mbuf in the packet: pass base of the chain to a higher level */
941          ether_input (ifp, eh, mstart);
942         
943          /* ether_input took the chain, set up new mbufs in the slots we used */
944          mdex -= 1;
945          do {
946            if (++mdex==ep->nRxBuffers) mdex = 0;
947            MakeRxBuffer(ep,mdex);
948          } while (mdex != index);
949          mstart = NULL;
950          mlast = NULL;
951          eh = NULL;
952        }
953      }
954      index += 1;
955      if (index == ep->nRxBuffers) index = 0;
956    }
957  }
958}
959
960/*----------- Vectored routines called through the driver struct ------------------ */
961
962static void ppc405_emac_init (void* p)
963/* Initialise the hardware, create and start the transmit and receive tasks */
964{
965  char txName[] = "ETx0";
966  char rxName[] = "ERx0";
967 
968  EMACLocals* ep = (EMACLocals*)p;
969  if (ep->txDaemonTid == 0) {
970    ppc405_emac_initialize_hardware(ep);
971    rxName[3] += ep->phyAddr;
972    ep->rxDaemonTid = rtems_bsdnet_newproc (rxName, 4096, ppc405_emac_rxDaemon, ep);
973    txName[3] += ep->phyAddr;
974    ep->txDaemonTid = rtems_bsdnet_newproc (txName, 4096, ppc405_emac_txDaemon, ep);
975  }
976  /* Only set IFF_RUNNING if the PHY is ready. If not set the watchdog timer running so we check it */
977  if ( GetPHYLinkState(ep) & kELinkUp )
978    ep->arpcom.ac_if.if_flags |= IFF_RUNNING;
979  else
980    ep->arpcom.ac_if.if_timer = 1;
981}
982
983static void ppc405_emac_start(struct ifnet *ifp)
984/* Send a packet: send an event to the transmit task, waking it up */
985{
986  EMACLocals* ep = ifp->if_softc;
987  rtems_event_send (ep->txDaemonTid, START_TRANSMIT_EVENT);
988  ifp->if_flags |= IFF_OACTIVE;
989}
990
991static void ppc405_emac_stop (EMACLocals* ep)
992{
993  uint32_t mask;
994 
995  mask = 0x80000000 >> ep->arpcom.ac_if.if_unit;
996  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCARR,mask);
997  PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCARR,mask);
998  ppc405_emac_disable(ep);
999  /* *** delete daemons, or do they exit themselves? */
1000  ep->arpcom.ac_if.if_flags &= ~IFF_RUNNING;
1001}
1002
1003#ifdef qDebug
1004static void ppc405_emac_stats (EMACLocals* ep)
1005{
1006
1007  printf ("  Rx Interrupts:%-8lu", ep->rxInterrupts);
1008  printf ("          Giant:%-8lu", ep->rxGiant);
1009  printf ("           Runt:%-8lu\n", ep->rxRunt);
1010  printf ("      Non-octet:%-8lu", ep->rxNonOctet);
1011  printf ("        Bad CRC:%-8lu", ep->rxBadCRC);
1012  printf ("        Overrun:%-8lu\n", ep->rxOverrun);
1013
1014  printf ("    Tx Interrupts:%-8lu", ep->txInterrupts);
1015  printf ("    Long deferral:%-8lu", ep->txDeferred);
1016  printf ("       No Carrier:%-8lu\n", ep->txLostCarrier);
1017  printf ("   Late collision:%-8lu", ep->txLateCollision);
1018  printf ("    One collision:%-8lu", ep->txOneCollision);
1019  printf ("  Many collisions:%-8lu\n", ep->txMultiCollision);
1020  printf ("Excess collisions:%-8lu", ep->txTooManyCollision);
1021  printf ("         Underrun:%-8lu", ep->txUnderrun);
1022  printf ("      Poor signal:%-8lu\n", ep->txPoorSignal);
1023}
1024#endif
1025
1026static int UpdateMulticast(EMACLocals* ep)
1027{
1028  /* Traverse list of multicast addresses and update hardware hash filter. This is just a work-reduction */
1029  /* step; the filter uses a hash of the hardware address and therefore doesn't catch all unwanted packets */
1030  /* We have to do other checks in software. */
1031  /* 405GP/GPr has 4x16-bit hash registers, 405EX/EXr has 8x32-bit */
1032 
1033  struct ether_multi* enm;
1034  struct ether_multistep step;
1035  uint32_t hash;
1036 
1037  #ifdef qMultiDebug
1038    printf("\nMulticast etheraddrs:\n");
1039  #endif
1040 
1041  ETHER_FIRST_MULTI(step, &ep->arpcom, enm);
1042  while (enm != NULL) {
1043   
1044    /* *** Doesn't implement ranges */
1045       
1046    hash = ether_crc32_be( (uint8_t*)&enm->enm_addrlo, sizeof(enm->enm_addrlo) );
1047    if (get_ppc_cpu_type() == PPC_405EX) {
1048      hash >>= 24;  /* Upper 8 bits, split 3/5 */
1049      /* This has been experimentally verified against the hardware */
1050      ep->EMAC->e_groupHash[7-(hash>>5)] |= (1 << (hash & 0x1F));
1051    } else {
1052      hash >>= 26;  /* Upper 6 bits, split 2/4 */
1053      /* This has not been checked */
1054      ep->EMAC->g_groupHash[3-(hash>>6)] |= (1 << (hash & 0xF));
1055    }
1056   
1057    #ifdef qMultiDebug
1058      printf("  ");
1059      printaddr(enm->enm_addrlo);
1060      printf(" = bit %d",hash);
1061      if (memcmp(&enm->enm_addrlo, &enm->enm_addrhi, 6) != 0) {
1062        printf(" - ");
1063        printaddr(enm->enm_addrhi);
1064        printf(" [not supported]");
1065      }
1066      printf("\n");
1067    #endif
1068   
1069    ETHER_NEXT_MULTI(step, enm);
1070  }
1071  #ifdef qMultiDebug
1072  {
1073    int i;
1074    printf(" Grouphash is ");
1075    for (i=0; i<8; i++)
1076      printf("%08X:",(int)ep->EMAC->e_groupHash[i]);
1077    printf("\n");
1078  }
1079  #endif
1080  return 0;
1081}
1082
1083
1084static int ppc405_emac_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1085{
1086  int error = 0;
1087  EMACLocals* ep = ifp->if_softc;
1088  struct ifreq* reqP = (struct ifreq *) data;
1089   
1090  switch (command) {
1091 
1092    case SIOCSIFFLAGS:
1093      switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
1094        case IFF_RUNNING:
1095          ppc405_emac_stop(ep);
1096          break;
1097   
1098        case IFF_UP:
1099          ppc405_emac_init(ep);
1100          break;
1101   
1102        case IFF_UP | IFF_RUNNING:
1103          ppc405_emac_stop(ep);
1104          ppc405_emac_init(ep);
1105          break;
1106   
1107        default:
1108          break;
1109      }
1110      break;
1111 
1112    case SIOCADDMULTI: {
1113        error = ether_addmulti( reqP, &ep->arpcom);
1114        if (error==ENETRESET)
1115          error = UpdateMulticast(ep);
1116      } break;
1117     
1118    case SIOCDELMULTI:
1119      error = ether_delmulti( (struct ifreq *) data, &ep->arpcom);
1120      if (error==ENETRESET)
1121        error = UpdateMulticast(ep);
1122      break;
1123     
1124    case SIOCSIFMTU: {
1125        /* Note that this may not do what you want; setting the interface MTU doesn't touch the route MTUs,
1126           and new routes are sometimes made by cloning old ones. So this won't change the MTU to known hosts
1127           and may not change the MTU to new ones either... */
1128        int max;
1129        if ( get_ppc_cpu_type() == PPC_405EX && (ep->EMAC->mode1 & keEMACJumbo) != 0 )
1130          max = ETHER_MAX_LEN_JUMBO;
1131        else
1132          max = ETHER_MAX_LEN;
1133        if (reqP->ifr_mtu > max - ETHER_HDR_LEN - ETHER_CRC_LEN)
1134          error = EINVAL;
1135        else
1136          ifp->if_mtu = reqP->ifr_mtu;
1137      } break;
1138     
1139    case SIO_RTEMS_SHOW_STATS:
1140      #ifdef qDebug
1141        ppc405_emac_stats(ep);
1142      #endif
1143      break;
1144     
1145    default:
1146      /* Not handled here, pass to generic */
1147      error = ether_ioctl(ifp,command,data);
1148      break;
1149  }
1150 
1151  #ifdef qDebug
1152  if (error != 0)
1153    printf("--- Ethernet ioctl %d failed %d\n",(int)command,error);
1154  #endif
1155 
1156  return error;
1157}
1158
1159 
1160/*----------------------- External attach function --------------------------
1161 * 
1162 * This is the one function we are required to define in here: declared in bsp.h
1163 * as RTEMS_BSP_NETWORK_DRIVER_ATTACH and called from rtems_bsdnet_attach
1164 *
1165*/
1166
1167int
1168rtems_emac_driver_attach(struct rtems_bsdnet_ifconfig* config, int attaching)
1169{
1170  int   unitNumber, nUnits;
1171  char*  unitName;
1172  struct  ifnet* ifp;
1173  EMACLocals* ep;
1174 
1175  if (attaching==0) {
1176    printk ("EMAC: driver cannot be detached.\n");
1177    return 0;
1178  }
1179 
1180  nUnits = 1;
1181  if (get_ppc_cpu_type()==PPC_405EX && get_ppc_cpu_revision() > 0x1474)
1182    nUnits = 2;  /* PPC405EX has two interfaces, EXr has one */
1183 
1184  unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName);
1185    if (unitNumber < 0 || unitNumber > nUnits-1) {
1186    printk ("EMAC: bad unit number %d.\n",unitNumber);
1187    return 0;
1188  }
1189 
1190  ep = &gEmacs[unitNumber];
1191 
1192  if (get_ppc_cpu_type()==PPC_405EX) {
1193    if (unitNumber==0) ep->EMAC = (EthernetRegisters_EX*)EMAC0EXAddress;
1194            else ep->EMAC = (EthernetRegisters_GP*)EMAC1EXAddress;
1195  } else
1196    ep->EMAC = (EthernetRegisters_GP*)EMAC0GPAddress;
1197   
1198  ifp = &ep->arpcom.ac_if;
1199  if (ifp->if_softc != NULL) {
1200    printk ("EMAC: driver already in use.\n");
1201    return 0;
1202  }
1203  ifp->if_softc = ep;
1204 
1205  if (config->hardware_address == 0)
1206    rtems_panic("No Ethernet MAC address specified!");
1207  memcpy (ep->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1208 
1209  ifp->if_name = unitName;
1210  ifp->if_unit = unitNumber;
1211 
1212  if (config->mtu != 0)
1213    ifp->if_mtu = config->mtu;
1214  else
1215    ifp->if_mtu = ETHERMTU;    /* May be adjusted later by ppc405_emac_phy_adapt() */
1216   
1217  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1218  if (ifp->if_snd.ifq_maxlen == 0)
1219    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1220  ifp->if_init = &ppc405_emac_init;
1221  ifp->if_ioctl = ppc405_emac_ioctl;
1222  ifp->if_start = ppc405_emac_start;
1223  ifp->if_output = ether_output;
1224  ifp->if_watchdog = ppc405_emac_watchdog;
1225  ifp->if_timer   = 0;
1226 
1227  if (config->rbuf_count != 0) {
1228    if (config->rbuf_count > 256) ep->nRxBuffers = 256;
1229                 else ep->nRxBuffers = config->rbuf_count;
1230  } else
1231    ep->nRxBuffers = nmbclusters/2;
1232   
1233  ep->phyAddr = unitNumber+1;
1234  ep->phyState = 0;
1235 
1236  #ifdef qDebug
1237    printf("\n  Setting up EMAC %d of %d\n",unitNumber+1,nUnits);
1238    printf("  MAC address is ");
1239    printaddr(ep->arpcom.ac_enaddr);
1240    printf("  MHLEN = %d, MINCLSIZE = %d MCLBYTES = %d\n",MHLEN,MINCLSIZE,MCLBYTES);
1241    printf("  ticks/sec = %d, usec/tick = %d\n", rtems_bsdnet_ticks_per_second, rtems_bsdnet_microseconds_per_tick);
1242   #endif
1243 
1244   if_attach (ifp);
1245  ether_ifattach (ifp);
1246
1247  return 1;
1248}
1249
Note: See TracBrowser for help on using the repository browser.