source: rtems/bsps/powerpc/virtex/net/xiltemac.c @ 65f868c

5
Last change on this file since 65f868c was 031df391, checked in by Sebastian Huber <sebastian.huber@…>, on 04/23/18 at 07:53:31

bsps: Move legacy network drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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