source: rtems/c/src/lib/libbsp/powerpc/virtex/network/xiltemac.c @ f16a1458

4.104.115
Last change on this file since f16a1458 was f16a1458, checked in by Ralf Corsepius <ralf.corsepius@…>, on 05/23/10 at 05:42:35

2010-05-23 Ralf Corsépius <ralf.corsepius@…>

  • console/consolelite.c, network/xiltemac.c: Reflect prototypes having changed (Warning removal).
  • Property mode set to 100644
File size: 28.3 KB
Line 
1/*
2 * Driver for Xilinx plb temac v3.00a
3 *
4 * Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca>
5 * Copyright (c) 2007 Linn Products Ltd, Scotland.
6 *
7 * The license and distribution terms for this file may be
8 * found in the file LICENSE in this distribution or at
9 * http://www.rtems.com/license/LICENSE.
10 *
11 */
12#define PPC_HAS_CLASSIC_EXCEPTIONS FALSE
13
14#ifndef __INSIDE_RTEMS_BSD_TCPIP_STACK__
15#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
16#endif
17
18#ifndef __BSD_VISIBLE
19#define __BSD_VISIBLE
20#endif
21
22#include <rtems.h>
23#include <rtems/bspIo.h>
24#include <rtems/rtems_bsdnet.h>
25
26#include <sys/param.h>
27#include <sys/mbuf.h>
28
29#include <sys/socket.h>
30#include <sys/sockio.h>
31#include <net/if.h>
32#include <netinet/in.h>
33#include <netinet/if_ether.h>
34
35#include <stdio.h>
36#include <stdarg.h>
37#include <errno.h>
38#include <string.h>
39#include <assert.h>
40
41#include <xiltemac.h>
42#include <rtems/irq.h>
43
44/* Reading/Writing memory mapped i/o */
45#define IN32(aPtr)                ((uint32_t)( *((volatile uint32_t *)(aPtr))) )
46#define OUT32(aPtr, aValue)     (*((volatile uint32_t *)(aPtr)) = (uint32_t)aValue)
47#define NUM_XILTEMAC_UNITS 2
48
49/* Why isn't this defined in stdio.h like it's supposed to be? */
50extern int snprintf(char*, size_t, const char*, ...);
51
52extern rtems_isr xilTemacIsr( void *handle );
53extern void xilTemacIsrOn(const rtems_irq_connect_data *);
54extern void xilTemacIsrOff(const rtems_irq_connect_data *);
55extern int xilTemacIsrIsOn(const rtems_irq_connect_data *);
56
57void xilTemacInit( void *voidptr );
58void xilTemacReset(struct ifnet *ifp);
59void xilTemacStop(struct ifnet *ifp);
60void xilTemacSend(struct ifnet *ifp);
61void xilTemacStart(struct ifnet *ifp);
62void xilTemacSetMacAddress(struct ifnet *ifp, unsigned char* aAddr);
63void xilTemacPrintStats(struct ifnet *ifp);
64
65void xilTemacRxThread( void *ignore );
66void xilTemacTxThread( void *ignore );
67
68static struct XilTemac gXilTemac[ NUM_XILTEMAC_UNITS ];
69
70static rtems_id       gXilRxThread = 0;
71static rtems_id       gXilTxThread = 0;
72
73/*
74** Events, one per unit.  The event is sent to the rx task from the isr
75** or from the stack to the tx task whenever a unit needs service.  The
76** rx/tx tasks identify the requesting unit(s) by their particular
77** events so only requesting units are serviced.
78*/
79
80static rtems_event_set gUnitSignals[ NUM_XILTEMAC_UNITS ]= { RTEMS_EVENT_1,
81                                                            RTEMS_EVENT_2 };
82
83uint32_t xilTemacTxFifoVacancyBytes(uint32_t aBaseAddr)
84{
85  uint32_t ipisr = IN32(aBaseAddr + XTE_IPISR_OFFSET);
86  uint32_t bytes = 0;
87  if(ipisr & XTE_IPXR_XMIT_LFIFO_FULL_MASK) {
88    /* If there's no room in the transmit length fifo, then any room in the
89     * data fifo is irrelevant, return 0 */
90  } else {
91    bytes = IN32(aBaseAddr + XTE_PFIFO_TX_VACANCY_OFFSET);
92    bytes &= XTE_PFIFO_COUNT_MASK;
93    bytes *= 8;
94  }
95  return bytes;
96}
97
98void xilTemacFifoRead64(uint32_t aBaseAddr, uint32_t* aBuf, uint32_t aBytes)
99{
100  uint32_t numqwords = aBytes / 8;
101  uint32_t xtrabytes = aBytes % 8;
102  uint32_t i;
103
104  for(i = 0; i < numqwords; i++)
105  {
106    aBuf[ (i*2)   ] = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET);
107    aBuf[ (i*2)+1 ] = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET + 4);
108  }
109
110  /* If there was a non qword sized read */
111  if( xtrabytes != 0 )
112  {
113    uint32_t lastdwordMS = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET);
114    uint32_t lastdwordLS = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET + 4);
115    uint8_t* finalbytes = (uint8_t *)&aBuf[ (numqwords*2) ];
116    uint8_t* ptr8;
117    int32_t  offset = 0;
118
119    ptr8 = (uint8_t *)&lastdwordMS;
120    if( xtrabytes >= 4 )
121    {
122      finalbytes[ offset++ ] = ptr8[0];
123      finalbytes[ offset++ ] = ptr8[1];
124      finalbytes[ offset++ ] = ptr8[2];
125      finalbytes[ offset++ ] = ptr8[3];
126
127      xtrabytes -= 4;
128      ptr8 = (uint8_t *)&lastdwordLS;
129    }
130
131    if( xtrabytes == 1 )
132    {
133      finalbytes[ offset++ ] = ptr8[0];
134    }
135    else if ( xtrabytes == 2 )
136    {
137      finalbytes[ offset++ ] = ptr8[0];
138      finalbytes[ offset++ ] = ptr8[1];
139    }
140    else if ( xtrabytes == 3 )
141    {
142      finalbytes[ offset++ ] = ptr8[0];
143      finalbytes[ offset++ ] = ptr8[1];
144      finalbytes[ offset++ ] = ptr8[2];
145    }
146  }
147}
148
149void xilTemacFifoWrite64(uint32_t aBaseAddr, uint32_t* aBuf, uint32_t aBytes)
150{
151  uint32_t numqwords = aBytes / 8;
152  uint32_t xtrabytes = aBytes % 8;
153  uint32_t i;
154
155  for(i = 0; i < numqwords; i++ ) {
156    OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET    , aBuf[ (i*2)   ]);
157    OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET + 4, aBuf[ (i*2)+1 ]);
158  }
159
160  /* If there was a non word sized write */
161  if( xtrabytes != 0 ) {
162    uint32_t lastdwordMS = 0;
163    uint32_t lastdwordLS = 0;
164    uint8_t* finalbytes = (uint8_t *)&aBuf[ (numqwords*2) ];
165    uint8_t* ptr8;
166    int32_t  offset = 0;
167
168    ptr8 = (uint8_t *)&lastdwordMS;
169
170    if( xtrabytes >= 4 ) {
171      ptr8[0] = finalbytes[ offset++ ];
172      ptr8[1] = finalbytes[ offset++ ];
173      ptr8[2] = finalbytes[ offset++ ];
174      ptr8[3] = finalbytes[ offset++ ];
175
176      xtrabytes -= 4;
177
178      ptr8 = (uint8_t *)&lastdwordLS;
179    }
180
181    if( xtrabytes == 1 ) {
182      ptr8[0] = finalbytes[ offset++ ];
183    }
184    else if ( xtrabytes == 2 ) {
185      ptr8[0] = finalbytes[ offset++ ];
186      ptr8[1] = finalbytes[ offset++ ];
187    }
188    else if ( xtrabytes == 3 ) {
189      ptr8[0] = finalbytes[ offset++ ];
190      ptr8[1] = finalbytes[ offset++ ];
191      ptr8[2] = finalbytes[ offset++ ];
192    }
193
194    OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET,     lastdwordMS);
195    OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET + 4, lastdwordLS);
196  }
197}
198
199void xilTemacStop(struct ifnet *ifp)
200{
201  struct XilTemac* xilTemac = ifp->if_softc;
202  uint32_t base = xilTemac->iAddr;
203
204  /* Disable ipif interrupts */
205  OUT32(base + XTE_DGIE_OFFSET, 0);
206
207  /* Disable the receiver */
208  uint32_t rxc1 = IN32(base + XTE_ERXC1_OFFSET);
209  rxc1 &= ~XTE_ERXC1_RXEN_MASK;
210  OUT32(base + XTE_ERXC1_OFFSET, rxc1);
211
212  /* If receiver was receiving a packet when we disabled it, it will be
213   * rejected, clear appropriate status bit */
214  uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET);
215  if( ipisr & XTE_IPXR_RECV_REJECT_MASK ) {
216    OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_REJECT_MASK);
217  }
218
219#if PPC_HAS_CLASSIC_EXCEPTIONS
220  if( xilTemac->iOldHandler )
221  {
222    opb_intc_set_vector( xilTemac->iOldHandler, xilTemac->iIsrVector, NULL );
223    xilTemac->iOldHandler = 0;
224  }
225#else
226  if( xilTemac->iOldHandler.name != 0)
227  {
228    BSP_install_rtems_irq_handler (&xilTemac->iOldHandler);
229  }
230#endif
231
232  ifp->if_flags &= ~IFF_RUNNING;
233}
234
235void xilTemacStart(struct ifnet *ifp)
236{
237  if( (ifp->if_flags & IFF_RUNNING) == 0 )
238  {
239    struct XilTemac* xilTemac = ifp->if_softc;
240    uint32_t base = xilTemac->iAddr;
241
242    /* Reset plb temac */
243    OUT32(base + XTE_DSR_OFFSET, XTE_DSR_RESET_MASK);
244    /* Don't have usleep on rtems 4.6
245    usleep(1);
246    */
247    /* @ fastest ppc clock of 500 MHz = 2ns clk */
248    uint32_t i = 0;
249    for( i = 0; i < 1 * 500; i++) {
250    }
251
252    /* Reset hard temac */
253    OUT32(base + XTE_CR_OFFSET, XTE_CR_HTRST_MASK);
254    /* Don't have usleep on rtems 4.6
255    usleep(4);
256    */
257    for( i = 0; i < 4 * 500; i++) {
258    }
259
260    /* Disable the receiver -- no need to disable xmit as we control that ;) */
261    uint32_t rxc1 = IN32(base + XTE_ERXC1_OFFSET);
262    rxc1 &= ~XTE_ERXC1_RXEN_MASK;
263    OUT32(base + XTE_ERXC1_OFFSET, rxc1);
264
265    /* If receiver was receiving a packet when we disabled it, it will be
266     * rejected, clear appropriate status bit */
267    uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET);
268    if( ipisr & XTE_IPXR_RECV_REJECT_MASK ) {
269      OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_REJECT_MASK);
270    }
271
272    /* Setup IPIF interrupt enables */
273    uint32_t dier = XTE_DXR_CORE_MASK | XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK;
274    dier |= XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK;
275    OUT32(base + XTE_DIER_OFFSET, dier);
276
277    /* Set the mac address */
278    xilTemacSetMacAddress( ifp, xilTemac->iArpcom.ac_enaddr);
279
280    /* Set the link speed */
281    uint32_t emcfg = IN32(base + XTE_ECFG_OFFSET);
282    printk("xiltemacStart, default linkspeed: %08x\n", emcfg);
283    emcfg = (emcfg & ~XTE_ECFG_LINKSPD_MASK) | XTE_ECFG_LINKSPD_100;
284    OUT32(base + XTE_ECFG_OFFSET, emcfg);
285
286    /* Set phy divisor and enable mdio.  For a plb bus freq of 150MHz (the
287       maximum as of Virtex4 Fx), a divisor of 29 gives a mdio clk freq of
288       2.5MHz (see Xilinx docs for equation), the maximum in the phy standard.
289       For slower plb frequencies, slower mkdio clks will result.  They may not
290       be optimal, but they should work.  */
291    uint32_t divisor = 29;
292    OUT32(base + XTE_EMC_OFFSET, divisor | XTE_EMC_MDIO_MASK);
293
294#if PPC_HAS_CLASSIC_EXCEPTIONS /* old connect code */
295    /* Connect isr vector */
296    rtems_status_code   sc;
297    extern rtems_isr xilTemacIsr( rtems_vector_number aVector );
298    sc = opb_intc_set_vector( xilTemacIsr, xilTemac->iIsrVector, &xilTemac->iOldHandler );
299    if( sc != RTEMS_SUCCESSFUL )
300    {
301      xilTemac->iOldHandler = 0;
302      printk("%s: Could not set interrupt vector for interface '%s' opb_intc_set_vector ret: %d\n", DRIVER_PREFIX, xilTemac->iUnitName, sc );
303      assert(0);
304    }
305#else
306    {
307      rtems_irq_connect_data IrqConnData;
308
309      /*
310       *get old irq handler
311       */
312      xilTemac->iOldHandler.name = xilTemac->iIsrVector;
313      if (!BSP_get_current_rtems_irq_handler (&xilTemac->iOldHandler)) {
314        xilTemac->iOldHandler.name = 0;
315        printk("%s: Unable to detect previous Irq handler\n",DRIVER_PREFIX);
316        rtems_fatal_error_occurred(1);
317      }
318
319      IrqConnData.on     = xilTemacIsrOn;
320      IrqConnData.off    = xilTemacIsrOff;
321      IrqConnData.isOn   = xilTemacIsrIsOn;
322      IrqConnData.name   = xilTemac->iIsrVector;
323      IrqConnData.hdl    = xilTemacIsr;
324      IrqConnData.handle = xilTemac;
325
326      if (!BSP_install_rtems_irq_handler (&IrqConnData)) {
327        printk("%s: Unable to connect Irq handler\n",DRIVER_PREFIX);
328        rtems_fatal_error_occurred(1);
329      }
330    }
331#endif
332    /* Enable promiscuous mode -- The temac only supports full duplex, which
333       means we're plugged into a switch.  Thus promiscuous mode simply means
334       we get all multicast addresses*/
335    OUT32(base + XTE_EAFM_OFFSET, XTE_EAFM_EPPRM_MASK);
336
337    /* Setup and enable receiver */
338    rxc1 = XTE_ERXC1_RXFCS_MASK | XTE_ERXC1_RXEN_MASK | XTE_ERXC1_RXVLAN_MASK;
339    OUT32(base + XTE_ERXC1_OFFSET, rxc1);
340
341    /* Setup and enable transmitter */
342    uint32_t txc = XTE_ETXC_TXEN_MASK | XTE_ETXC_TXVLAN_MASK;
343    OUT32(base + XTE_ETXC_OFFSET, txc);
344
345    /* Enable interrupts for temac */
346    uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
347    ipier |= (XTE_IPXR_XMIT_ERROR_MASK);
348    ipier |= (XTE_IPXR_RECV_ERROR_MASK | XTE_IPXR_RECV_DONE_MASK);
349    ipier |= (XTE_IPXR_AUTO_NEG_MASK);
350    OUT32(base + XTE_IPIER_OFFSET, ipier);
351
352    printk("%s: xiltemacStart, ipier: %08x\n",DRIVER_PREFIX, ipier);
353
354    /* Enable device global interrutps */
355    OUT32(base + XTE_DGIE_OFFSET, XTE_DGIE_ENABLE_MASK);
356    ifp->if_flags |= IFF_RUNNING;
357  }
358}
359
360void xilTemacInit( void *voidptr )
361{
362}
363
364void xilTemacReset(struct ifnet *ifp)
365{
366   xilTemacStop( ifp );
367   xilTemacStart( ifp );
368}
369
370void xilTemacSetMacAddress(struct ifnet *ifp, unsigned char* aAddr)
371{
372  struct XilTemac* xilTemac = ifp->if_softc;
373  uint32_t base = xilTemac->iAddr;
374
375  /* You can't change the mac address while the card is in operation */
376  if( (ifp->if_flags & IFF_RUNNING) != 0 ) {
377    printk("%s: attempted to change MAC while up, interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
378    assert(0);
379  }
380  uint32_t mac;
381  mac  = aAddr[0] & 0x000000FF;
382  mac |= aAddr[1] << 8;
383  mac |= aAddr[2] << 16;
384  mac |= aAddr[3] << 24;
385  OUT32(base + XTE_EUAW0_OFFSET, mac);
386
387  mac = IN32(base + XTE_EUAW1_OFFSET);
388  mac &= ~XTE_EUAW1_MASK;
389  mac |= aAddr[4] & 0x000000FF;
390  mac |= aAddr[5] << 8;
391  OUT32(base + XTE_EUAW1_OFFSET, mac);
392}
393
394void xilTemacPrintStats( struct ifnet *ifp )
395{
396   struct XilTemac* xilTemac = ifp->if_softc;
397
398   printf("\n");
399   printf("%s: Statistics for interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
400
401   printf("%s:        Ipif Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iInterrupts);
402   printf("%s:          Rx Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxInterrupts);
403   printf("%s: Rx Rejected Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedInterrupts);
404   printf("%s:   Rx Rej Invalid Frame: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedInvalidFrame);
405   printf("%s:  Rx Rej Data Fifo Full: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedDataFifoFull);
406   printf("%s:Rx Rej Length Fifo Full: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedLengthFifoFull);
407   printf("%s:        Rx Stray Events: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxStrayEvents);
408   printf("%s:         Rx Max Drained: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxMaxDrained);
409   printf("%s:          Tx Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iTxInterrupts);
410   printf("%s:         Tx Max Drained: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iTxMaxDrained);
411
412   printf("\n");
413}
414
415void xilTemacIsrSingle(struct XilTemac* xilTemac)
416{
417  uint32_t base = xilTemac->iAddr;
418  uint32_t disr = IN32( base + XTE_DISR_OFFSET );
419  struct ifnet* ifp = xilTemac->iIfp;
420
421  if( disr && (ifp->if_flags & IFF_RUNNING) == 0 ) {
422    /* some interrupt status bits are asserted but card is down */
423    printk("%s: Fatal error, disr 0 or this emac not running\n", DRIVER_PREFIX);
424    /*assert(0);*/
425  } else {
426    /* Handle all error conditions first */
427    if( disr & (XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK |
428                XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK) ) {
429      printk("%s: Fatal Bus error, disr: %08x\n", DRIVER_PREFIX, disr);
430      /*assert(0);*/
431    }
432    if( disr & XTE_DXR_CORE_MASK ) {
433      /* Normal case, temac interrupt */
434      uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET);
435      uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
436      uint32_t newipier = ipier;
437      uint32_t pending = ipisr & ipier;
438      xilTemac->iStats.iInterrupts++;
439
440      /* Check for all fatal errors, even if that error is not enabled in ipier */
441      if(ipisr & XTE_IPXR_FIFO_FATAL_ERROR_MASK) {
442        printk("%s: Fatal Fifo Error ipisr: %08x\n", DRIVER_PREFIX, ipisr);
443        /*assert(0);*/
444      }
445
446      if(pending & XTE_IPXR_RECV_DONE_MASK) {
447        /* We've received a packet
448           - inc stats
449           - disable rx interrupt
450           - signal rx thread to empty out fifo
451             (rx thread must renable interrupt)
452        */
453        xilTemac->iStats.iRxInterrupts++;
454
455        newipier &= ~XTE_IPXR_RECV_DONE_MASK;
456
457        rtems_event_send(gXilRxThread, xilTemac->iIoEvent);
458      }
459      if(pending & XTE_IPXR_XMIT_DONE_MASK) {
460        /* We've transmitted a packet.  This interrupt is only ever enabled in
461           the ipier if the tx thread didn't have enough space in the data fifo
462           or the tplr fifo.  If that's the case, we:
463           - inc stats
464           - disable tx interrupt
465           - signal tx thread that a transmit has completed and thus there is now
466             room to send again.
467        */
468        xilTemac->iStats.iTxInterrupts++;
469
470        newipier &= ~XTE_IPXR_XMIT_DONE_MASK;
471
472        rtems_event_send(gXilTxThread, xilTemac->iIoEvent);
473      }
474      if(pending & XTE_IPXR_RECV_DROPPED_MASK) {
475        /* A packet was dropped (because it was invalid, or receiving it
476           have overflowed one of the rx fifo's).
477           - Increment stats.
478           - Clear interrupt condition.
479        */
480        uint32_t toggle = 0;
481        if(pending & XTE_IPXR_RECV_REJECT_MASK) {
482          xilTemac->iStats.iRxRejectedInvalidFrame++;
483          toggle |= XTE_IPXR_RECV_REJECT_MASK;
484        }
485        if(pending & XTE_IPXR_RECV_PFIFO_ABORT_MASK) {
486          xilTemac->iStats.iRxRejectedDataFifoFull++;
487          toggle |= XTE_IPXR_RECV_PFIFO_ABORT_MASK;
488        }
489        if(pending & XTE_IPXR_RECV_LFIFO_ABORT_MASK) {
490          xilTemac->iStats.iRxRejectedLengthFifoFull++;
491          toggle |= XTE_IPXR_RECV_LFIFO_ABORT_MASK;
492        }
493        xilTemac->iStats.iRxRejectedInterrupts++;
494        OUT32(base + XTE_IPISR_OFFSET, toggle);
495      }
496      if(pending & XTE_IPXR_AUTO_NEG_MASK) {
497        printk("%s: Autonegotiation finished\n", DRIVER_PREFIX);
498        OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_AUTO_NEG_MASK);
499      }
500      if(newipier != ipier) {
501        OUT32(base + XTE_IPIER_OFFSET, newipier);
502      }
503    }
504  }
505}
506
507#if PPC_HAS_CLASSIC_EXCEPTIONS
508rtems_isr xilTemacIsr( rtems_vector_number aVector )
509{
510  struct XilTemac* xilTemac;
511  int              i;
512
513  for( i=0; i< NUM_XILTEMAC_UNITS; i++ ) {
514    xilTemac = &gXilTemac[i];
515
516    if( xilTemac->iIsPresent ) {
517      xilTemacIsrSingle(xilTemac);
518    }
519  }
520}
521#else
522rtems_isr xilTemacIsr(void *handle )
523{
524  struct XilTemac* xilTemac = (struct XilTemac*)handle;
525
526  xilTemacIsrSingle(xilTemac);
527}
528
529void xilTemacIsrOn(const rtems_irq_connect_data *unused)
530{
531}
532
533void xilTemacIsrOff(const rtems_irq_connect_data *unused)
534{
535}
536
537int xilTemacIsrIsOn(const rtems_irq_connect_data *unused)
538{
539  return 1;
540}
541#endif
542
543
544int32_t xilTemacSetMulticastFilter(struct ifnet *ifp)
545{
546  return 0;
547}
548
549int xilTemacIoctl(struct ifnet* ifp, ioctl_command_t   aCommand, caddr_t aData)
550{
551  struct XilTemac* xilTemac = ifp->if_softc;
552  int32_t error = 0;
553
554  switch(aCommand) {
555    case SIOCGIFADDR:
556    case SIOCSIFADDR:
557      ether_ioctl(ifp, aCommand, aData);
558      break;
559
560    case SIOCSIFFLAGS:
561      switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
562      {
563        case IFF_RUNNING:
564          xilTemacStop(ifp);
565          break;
566
567        case IFF_UP:
568          xilTemacStart(ifp);
569          break;
570
571        case IFF_UP | IFF_RUNNING:
572          xilTemacReset(ifp);
573          break;
574
575        default:
576          break;
577      }
578      break;
579
580    case SIOCADDMULTI:
581    case SIOCDELMULTI: {
582        struct ifreq* ifr = (struct ifreq*) aData;
583        error = ((aCommand == SIOCADDMULTI) ?
584                 ( ether_addmulti(ifr, &(xilTemac->iArpcom)) ) :
585                 ( ether_delmulti(ifr, &(xilTemac->iArpcom)))
586           );
587        /* ENETRESET indicates that driver should update its multicast filters */
588        if(error == ENETRESET)
589        {
590            error = xilTemacSetMulticastFilter( ifp );
591        }
592        break;
593    }
594
595    case SIO_RTEMS_SHOW_STATS:
596      xilTemacPrintStats( ifp );
597      break;
598
599    default:
600      error = EINVAL;
601      break;
602  }
603  return error;
604}
605
606void xilTemacSend(struct ifnet* ifp)
607{
608  struct XilTemac* xilTemac = ifp->if_softc;
609
610  /* wake up tx thread w/ outbound interface's signal */
611  rtems_event_send( gXilTxThread, xilTemac->iIoEvent );
612
613  ifp->if_flags |= IFF_OACTIVE;
614}
615
616/* align the tx buffer to 32 bytes just for kicks, should make it more
617 * cache friendly */
618static unsigned char gTxBuf[2048] __attribute__ ((aligned (32)));
619
620void xilTemacSendPacket(struct ifnet *ifp, struct mbuf* aMbuf)
621{
622  struct XilTemac  *xilTemac = ifp->if_softc;
623  struct mbuf     *n = aMbuf;
624  uint32_t        len = 0;
625
626#ifdef DEBUG
627  printk("SendPacket\n");
628  printk("TXD: 0x%08x\n", (int32_t) n->m_data);
629#endif
630
631  /* assemble the packet into the tx buffer */
632  for(;;) {
633#ifdef DEBUG
634    uint32_t i = 0;
635    printk("MBUF: 0x%08x : ", (int32_t) n->m_data);
636    for (i=0;i<n->m_len;i+=2) {
637      printk("%02x%02x ", mtod(n, unsigned char*)[i], mtod(n, unsigned char*)[i+1]);
638    }
639    printk("\n");
640#endif
641
642    if( n->m_len > 0 ) {
643      memcpy( &gTxBuf[ len ], (char *)n->m_data, n->m_len);
644      len += n->m_len;
645    }
646    if( (n = n->m_next) == 0) {
647      break;
648    }
649  }
650
651  xilTemacFifoWrite64( xilTemac->iAddr, (uint32_t*)gTxBuf, len );
652  /* Set the Transmit Packet Length Register which registers the packet
653  * length, enqueues the packet and signals the xmit unit to start
654  * sending. */
655  OUT32(xilTemac->iAddr + XTE_TPLR_OFFSET, len);
656
657#ifdef DEBUG
658  printk("%s: txpkt, len %d\n", DRIVER_PREFIX, len );
659  memset(gTxBuf, 0, len);
660#endif
661}
662
663void xilTemacTxThreadSingle(struct ifnet* ifp)
664{
665  struct XilTemac* xilTemac = ifp->if_softc;
666  struct mbuf*     m;
667  uint32_t base = xilTemac->iAddr;
668
669#ifdef DEBUG
670  printk("%s: tx send packet, interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
671#endif
672
673  /* Send packets till mbuf queue empty or tx fifo full */
674  for(;;) {
675    uint32_t i = 0;
676
677    /* 1) clear out any statuses from previously sent tx frames */
678    while( IN32(base + XTE_IPISR_OFFSET) & XTE_IPXR_XMIT_DONE_MASK ) {
679      IN32(base + XTE_TSR_OFFSET);
680      OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_XMIT_DONE_MASK);
681      i++;
682    }
683    if( i > xilTemac->iStats.iTxMaxDrained ) {
684      xilTemac->iStats.iTxMaxDrained = i;
685    }
686
687    /* 2) Check if enough space in tx data fifo _and_ tx tplr for an entire
688       ethernet frame */
689    if( xilTemacTxFifoVacancyBytes( xilTemac->iAddr ) <= ifp->if_mtu ) {
690      /* 2a) If not, enable transmit done interrupt and break out of loop to
691         wait for space */
692      uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
693      ipier |= (XTE_IPXR_XMIT_DONE_MASK);
694      OUT32(base + XTE_IPIER_OFFSET, ipier);
695      break;
696    }
697
698    /* 3) Contuine to dequeue mbuf chains till none left */
699    IF_DEQUEUE( &(ifp->if_snd), m);
700    if( !m ) {
701      break;
702    }
703
704    /* 4) Send dequeued mbuf chain */
705    xilTemacSendPacket( ifp, m );
706
707    /* 5) Free mbuf chain */
708    m_freem( m );
709  }
710  ifp->if_flags &= ~IFF_OACTIVE;
711}
712
713void xilTemacTxThread( void *ignore )
714{
715  struct XilTemac  *xilTemac;
716  struct ifnet     *ifp;
717
718  rtems_event_set  events;
719  int              i;
720
721  for(;;) {
722    /* Wait for:
723       - notification from stack of packet to send OR
724       - notification from interrupt handler that there is space available to
725         send already queued packets
726    */
727    rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
728                                RTEMS_EVENT_ANY | RTEMS_WAIT,
729                                RTEMS_NO_TIMEOUT,
730                                &events );
731
732    for(i=0; i< NUM_XILTEMAC_UNITS; i++) {
733      xilTemac = &gXilTemac[i];
734
735      if( xilTemac->iIsPresent ) {
736        ifp = xilTemac->iIfp;
737
738        if( (ifp->if_flags & IFF_RUNNING) ) {
739
740          if( events & xilTemac->iIoEvent ) {
741            xilTemacTxThreadSingle(ifp);
742          }
743
744        } else {
745          printk("%s: xilTemacTxThread: event received for device: %s, but device not active\n",
746            DRIVER_PREFIX, xilTemac->iUnitName);
747          assert(0);
748        }
749      }
750    }
751  }
752}
753
754void xilTemacRxThreadSingle(struct ifnet* ifp)
755{
756  struct XilTemac* xilTemac = ifp->if_softc;
757
758  uint32_t npkts = 0;
759#ifdef DEBUG
760  printk("%s: rxthread, packet rx on interface %s\n", DRIVER_PREFIX, xilTemac->iUnitName );
761#endif
762
763  uint32_t base = xilTemac->iAddr;
764
765  /* While RECV_DONE_MASK in ipisr stays set */
766  while( IN32(base + XTE_IPISR_OFFSET) & XTE_IPXR_RECV_DONE_MASK ) {
767
768    /* 1) Read the length of the packet */
769    uint32_t bytes = IN32(base + XTE_RPLR_OFFSET);
770
771    /* 2) Read the Read Status Register (which contains no information).  When
772     * all of these in the fifo have been read, then XTE_IPXR_RECV_DONE_MASK
773     * will stay turned off, after it's written to */
774    IN32(base + XTE_RSR_OFFSET);
775    npkts++;
776
777    struct mbuf* m;
778    struct ether_header* eh;
779
780    /* 3) Get some memory from the ip stack to store the packet in */
781    MGETHDR(m, M_WAIT, MT_DATA);
782    MCLGET(m, M_WAIT);
783
784    m->m_pkthdr.rcvif = ifp;
785
786    /* 4) Copy the packet into the ip stack's memory */
787    xilTemacFifoRead64( base, mtod(m, uint32_t*), bytes);
788
789    m->m_len = bytes - sizeof(struct ether_header);
790    m->m_pkthdr.len = bytes - sizeof(struct ether_header);
791
792    eh = mtod(m, struct ether_header*);
793
794    m->m_data += sizeof(struct ether_header);
795
796    /* 5) Tell the ip stack about the received packet */
797    ether_input(ifp, eh, m);
798
799    /* 6) Try and turn off XTE_IPXR_RECV_DONE bit in the ipisr.  If there's
800     * still more packets (ie RSR ! empty), then it will stay asserted.  If
801     * there's no more packets, this will turn it off.
802     */
803    OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_DONE_MASK);
804  }
805
806  /* End) All Rx packets serviced, renable rx interrupt */
807  uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
808  ipier |= XTE_IPXR_RECV_DONE_MASK;
809  OUT32(base + XTE_IPIER_OFFSET, ipier);
810
811#ifdef DEBUG
812  printk("%s: rxthread, retrieved %d packets\n", DRIVER_PREFIX, npkts );
813#endif
814  if(npkts > xilTemac->iStats.iRxMaxDrained) {
815    xilTemac->iStats.iRxMaxDrained = npkts;
816  }
817  /* ??) Very very occasionally, under extremely high stress, I get a situation
818   * where we process no packets.  That is, the rx thread was evented, but
819   * there was no packet available.  I'm not sure how this happens.  Ideally,
820   * it shouldn't ocurr, and I suspect a minor bug in the driver.  However, for
821   * me it's happenning 3 times in several hunderd million interrupts.  Nothing
822   * bad happens, as long as we don't read from the rx fifo's if nothing is
823   * there.  It is just not as efficient as possible (rx thread being evented
824   * pointlessly) and a bit disconcerting about how it's ocurring.
825   * The best way to reproduce this is to have two clients run:
826   * $ ping <host> -f -s 65507
827   * This flood pings the device from two clients with the maximum size ping
828   * packet.  It absolutely hammers the device under test.  Eventually, (if
829   * you leave it running overnight for instance), you'll get a couple of these
830   * stray rx events. */
831  if(npkts == 0) {
832    /*printk("%s: RxThreadSingle: fatal error: event received, but no packets available\n", DRIVER_PREFIX);
833    assert(0); */
834    xilTemac->iStats.iRxStrayEvents++;
835  }
836}
837
838void xilTemacRxThread( void *ignore )
839{
840  struct XilTemac* xilTemac;
841  struct ifnet*   ifp;
842  int             i;
843  rtems_event_set events;
844
845#ifdef DEBUG
846  printk("%s: xilTemacRxThread running\n", DRIVER_PREFIX );
847#endif
848
849  for(;;) {
850    rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
851                                RTEMS_WAIT | RTEMS_EVENT_ANY,
852                                RTEMS_NO_TIMEOUT,
853                                &events);
854
855#ifdef DEBUG
856    printk("%s: rxthread, wakeup\n", DRIVER_PREFIX );
857#endif
858
859    for(i=0; i< NUM_XILTEMAC_UNITS; i++) {
860      xilTemac = &gXilTemac[i];
861
862      if( xilTemac->iIsPresent ) {
863        ifp = xilTemac->iIfp;
864
865        if( (ifp->if_flags & IFF_RUNNING) != 0 ) {
866          if( events & xilTemac->iIoEvent ) {
867            xilTemacRxThreadSingle(ifp);
868          }
869        }
870        else {
871          printk("%s: rxthread, interface %s present but not running\n", DRIVER_PREFIX, xilTemac->iUnitName );
872          assert(0);
873        }
874      }
875    }
876  }
877}
878
879int32_t xilTemac_driver_attach(struct rtems_bsdnet_ifconfig* aBsdConfig, int aDummy)
880{
881   struct ifnet*    ifp;
882   int32_t          mtu;
883   int32_t          unit;
884   char*            unitName;
885   struct XilTemac* xilTemac;
886
887   unit = rtems_bsdnet_parse_driver_name(aBsdConfig, &unitName);
888   if(unit < 0 )
889   {
890      printk("%s: Interface Unit number < 0\n", DRIVER_PREFIX );
891      return 0;
892   }
893
894   if( aBsdConfig->bpar == 0 )
895   {
896      printk("%s: Did not specify base address for device '%s'", DRIVER_PREFIX, unitName );
897      return 0;
898   }
899
900   if( aBsdConfig->hardware_address == NULL )
901   {
902      printk("%s: No MAC address given for interface '%s'\n", DRIVER_PREFIX, unitName );
903      return 0;
904   }
905
906   xilTemac = &gXilTemac[ unit ];
907   memset(xilTemac, 0, sizeof(struct XilTemac));
908
909   xilTemac->iIsPresent = 1;
910
911   snprintf( xilTemac->iUnitName, MAX_UNIT_BYTES, "%s%" PRId32, unitName, unit );
912
913   xilTemac->iIfp        = &(xilTemac->iArpcom.ac_if);
914   ifp                  = &(xilTemac->iArpcom.ac_if);
915   xilTemac->iAddr      = aBsdConfig->bpar;
916   xilTemac->iIoEvent   = gUnitSignals[ unit ];
917   xilTemac->iIsrVector = aBsdConfig->irno;
918
919   memcpy( xilTemac->iArpcom.ac_enaddr, aBsdConfig->hardware_address, ETHER_ADDR_LEN);
920
921   if( aBsdConfig->mtu )
922   {
923      mtu = aBsdConfig->mtu;
924   }
925   else
926   {
927      mtu = ETHERMTU;
928   }
929
930   ifp->if_softc  = xilTemac;
931   ifp->if_unit   = unit;
932   ifp->if_name   = unitName;
933   ifp->if_mtu    = mtu;
934   ifp->if_init   = xilTemacInit;
935   ifp->if_ioctl  = xilTemacIoctl;
936   ifp->if_start  = xilTemacSend;
937   ifp->if_output = ether_output;
938
939   ifp->if_flags  =  IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
940
941   if(ifp->if_snd.ifq_maxlen == 0)
942   {
943      ifp->if_snd.ifq_maxlen = ifqmaxlen;
944   }
945
946   if_attach(ifp);
947   ether_ifattach(ifp);
948
949   /* create shared rx & tx threads */
950   if( (gXilRxThread == 0) && (gXilTxThread == 0) )
951   {
952      printk("%s: Creating shared RX/TX threads\n", DRIVER_PREFIX );
953      gXilRxThread = rtems_bsdnet_newproc("xerx", 4096, xilTemacRxThread, NULL );
954      gXilTxThread = rtems_bsdnet_newproc("xetx", 4096, xilTemacTxThread, NULL );
955   }
956
957   printk("%s: Initializing driver for '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
958
959   printk("%s: base address 0x%08X, intnum 0x%02X, \n",
960          DRIVER_PREFIX,
961          aBsdConfig->bpar,
962          aBsdConfig->irno );
963
964   return 1;
965}
966
Note: See TracBrowser for help on using the repository browser.