summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/virtex/net/xiltemac.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/virtex/net/xiltemac.c')
-rw-r--r--bsps/powerpc/virtex/net/xiltemac.c961
1 files changed, 0 insertions, 961 deletions
diff --git a/bsps/powerpc/virtex/net/xiltemac.c b/bsps/powerpc/virtex/net/xiltemac.c
deleted file mode 100644
index 2e8b31b5f2..0000000000
--- a/bsps/powerpc/virtex/net/xiltemac.c
+++ /dev/null
@@ -1,961 +0,0 @@
-/*
- * Driver for Xilinx plb temac v3.00a
- *
- * Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca>
- * Copyright (c) 2007 Linn Products Ltd, Scotland.
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- *
- */
-
-#include <machine/rtems-bsd-kernel-space.h>
-#define PPC_HAS_CLASSIC_EXCEPTIONS FALSE
-
-#include <bsp.h>
-#include <rtems/bspIo.h>
-#include <rtems/rtems_bsdnet.h>
-#include <inttypes.h>
-
-#include <sys/param.h>
-#include <sys/mbuf.h>
-
-#include <sys/socket.h>
-#include <sys/sockio.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-
-#include <xiltemac.h>
-#include <rtems/irq.h>
-
-/* Reading/Writing memory mapped i/o */
-#define IN32(aPtr) ((uint32_t)( *((volatile uint32_t *)(aPtr))) )
-#define OUT32(aPtr, aValue) (*((volatile uint32_t *)(aPtr)) = (uint32_t)aValue)
-#define NUM_XILTEMAC_UNITS 2
-
-/* Why isn't this defined in stdio.h like it's supposed to be? */
-extern int snprintf(char*, size_t, const char*, ...);
-
-extern rtems_isr xilTemacIsr( void *handle );
-extern void xilTemacIsrOn(const rtems_irq_connect_data *);
-extern void xilTemacIsrOff(const rtems_irq_connect_data *);
-extern int xilTemacIsrIsOn(const rtems_irq_connect_data *);
-
-void xilTemacInit( void *voidptr );
-void xilTemacReset(struct ifnet *ifp);
-void xilTemacStop(struct ifnet *ifp);
-void xilTemacSend(struct ifnet *ifp);
-void xilTemacStart(struct ifnet *ifp);
-void xilTemacSetMacAddress(struct ifnet *ifp, unsigned char* aAddr);
-void xilTemacPrintStats(struct ifnet *ifp);
-
-void xilTemacRxThread( void *ignore );
-void xilTemacTxThread( void *ignore );
-
-static struct XilTemac gXilTemac[ NUM_XILTEMAC_UNITS ];
-
-static rtems_id gXilRxThread = 0;
-static rtems_id gXilTxThread = 0;
-
-/*
-** Events, one per unit. The event is sent to the rx task from the isr
-** or from the stack to the tx task whenever a unit needs service. The
-** rx/tx tasks identify the requesting unit(s) by their particular
-** events so only requesting units are serviced.
-*/
-
-static rtems_event_set gUnitSignals[ NUM_XILTEMAC_UNITS ]= { RTEMS_EVENT_1,
- RTEMS_EVENT_2 };
-
-static uint32_t xilTemacTxFifoVacancyBytes(uint32_t aBaseAddr)
-{
- uint32_t ipisr = IN32(aBaseAddr + XTE_IPISR_OFFSET);
- uint32_t bytes = 0;
- if(ipisr & XTE_IPXR_XMIT_LFIFO_FULL_MASK) {
- /* If there's no room in the transmit length fifo, then any room in the
- * data fifo is irrelevant, return 0 */
- } else {
- bytes = IN32(aBaseAddr + XTE_PFIFO_TX_VACANCY_OFFSET);
- bytes &= XTE_PFIFO_COUNT_MASK;
- bytes *= 8;
- }
- return bytes;
-}
-
-static void xilTemacFifoRead64(uint32_t aBaseAddr, uint32_t* aBuf, uint32_t aBytes)
-{
- uint32_t numqwords = aBytes / 8;
- uint32_t xtrabytes = aBytes % 8;
- uint32_t i;
-
- for(i = 0; i < numqwords; i++)
- {
- aBuf[ (i*2) ] = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET);
- aBuf[ (i*2)+1 ] = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET + 4);
- }
-
- /* If there was a non qword sized read */
- if( xtrabytes != 0 )
- {
- uint32_t lastdwordMS = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET);
- uint32_t lastdwordLS = IN32(aBaseAddr + XTE_PFIFO_RX_DATA_OFFSET + 4);
- uint8_t* finalbytes = (uint8_t *)&aBuf[ (numqwords*2) ];
- uint8_t* ptr8;
- int32_t offset = 0;
-
- ptr8 = (uint8_t *)&lastdwordMS;
- if( xtrabytes >= 4 )
- {
- finalbytes[ offset++ ] = ptr8[0];
- finalbytes[ offset++ ] = ptr8[1];
- finalbytes[ offset++ ] = ptr8[2];
- finalbytes[ offset++ ] = ptr8[3];
-
- xtrabytes -= 4;
- ptr8 = (uint8_t *)&lastdwordLS;
- }
-
- if( xtrabytes == 1 )
- {
- finalbytes[ offset++ ] = ptr8[0];
- }
- else if ( xtrabytes == 2 )
- {
- finalbytes[ offset++ ] = ptr8[0];
- finalbytes[ offset++ ] = ptr8[1];
- }
- else if ( xtrabytes == 3 )
- {
- finalbytes[ offset++ ] = ptr8[0];
- finalbytes[ offset++ ] = ptr8[1];
- finalbytes[ offset++ ] = ptr8[2];
- }
- }
-}
-
-static void xilTemacFifoWrite64(uint32_t aBaseAddr, uint32_t* aBuf, uint32_t aBytes)
-{
- uint32_t numqwords = aBytes / 8;
- uint32_t xtrabytes = aBytes % 8;
- uint32_t i;
-
- for(i = 0; i < numqwords; i++ ) {
- OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET , aBuf[ (i*2) ]);
- OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET + 4, aBuf[ (i*2)+1 ]);
- }
-
- /* If there was a non word sized write */
- if( xtrabytes != 0 ) {
- uint32_t lastdwordMS = 0;
- uint32_t lastdwordLS = 0;
- uint8_t* finalbytes = (uint8_t *)&aBuf[ (numqwords*2) ];
- uint8_t* ptr8;
- int32_t offset = 0;
-
- ptr8 = (uint8_t *)&lastdwordMS;
-
- if( xtrabytes >= 4 ) {
- ptr8[0] = finalbytes[ offset++ ];
- ptr8[1] = finalbytes[ offset++ ];
- ptr8[2] = finalbytes[ offset++ ];
- ptr8[3] = finalbytes[ offset++ ];
-
- xtrabytes -= 4;
-
- ptr8 = (uint8_t *)&lastdwordLS;
- }
-
- if( xtrabytes == 1 ) {
- ptr8[0] = finalbytes[ offset++ ];
- }
- else if ( xtrabytes == 2 ) {
- ptr8[0] = finalbytes[ offset++ ];
- ptr8[1] = finalbytes[ offset++ ];
- }
- else if ( xtrabytes == 3 ) {
- ptr8[0] = finalbytes[ offset++ ];
- ptr8[1] = finalbytes[ offset++ ];
- ptr8[2] = finalbytes[ offset++ ];
- }
-
- OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET, lastdwordMS);
- OUT32(aBaseAddr + XTE_PFIFO_TX_DATA_OFFSET + 4, lastdwordLS);
- }
-}
-
-void xilTemacStop(struct ifnet *ifp)
-{
- struct XilTemac* xilTemac = ifp->if_softc;
- uint32_t base = xilTemac->iAddr;
-
- /* Disable ipif interrupts */
- OUT32(base + XTE_DGIE_OFFSET, 0);
-
- /* Disable the receiver */
- uint32_t rxc1 = IN32(base + XTE_ERXC1_OFFSET);
- rxc1 &= ~XTE_ERXC1_RXEN_MASK;
- OUT32(base + XTE_ERXC1_OFFSET, rxc1);
-
- /* If receiver was receiving a packet when we disabled it, it will be
- * rejected, clear appropriate status bit */
- uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET);
- if( ipisr & XTE_IPXR_RECV_REJECT_MASK ) {
- OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_REJECT_MASK);
- }
-
-#if PPC_HAS_CLASSIC_EXCEPTIONS
- if( xilTemac->iOldHandler )
- {
- opb_intc_set_vector( xilTemac->iOldHandler, xilTemac->iIsrVector, NULL );
- xilTemac->iOldHandler = 0;
- }
-#else
- if( xilTemac->iOldHandler.name != 0)
- {
- BSP_install_rtems_irq_handler (&xilTemac->iOldHandler);
- }
-#endif
-
- ifp->if_flags &= ~IFF_RUNNING;
-}
-
-void xilTemacStart(struct ifnet *ifp)
-{
- if( (ifp->if_flags & IFF_RUNNING) == 0 )
- {
- struct XilTemac* xilTemac = ifp->if_softc;
- uint32_t base = xilTemac->iAddr;
-
- /* Reset plb temac */
- OUT32(base + XTE_DSR_OFFSET, XTE_DSR_RESET_MASK);
- /* Don't have usleep on rtems 4.6
- usleep(1);
- */
- /* @ fastest ppc clock of 500 MHz = 2ns clk */
- uint32_t i = 0;
- for( i = 0; i < 1 * 500; i++) {
- }
-
- /* Reset hard temac */
- OUT32(base + XTE_CR_OFFSET, XTE_CR_HTRST_MASK);
- /* Don't have usleep on rtems 4.6
- usleep(4);
- */
- for( i = 0; i < 4 * 500; i++) {
- }
-
- /* Disable the receiver -- no need to disable xmit as we control that ;) */
- uint32_t rxc1 = IN32(base + XTE_ERXC1_OFFSET);
- rxc1 &= ~XTE_ERXC1_RXEN_MASK;
- OUT32(base + XTE_ERXC1_OFFSET, rxc1);
-
- /* If receiver was receiving a packet when we disabled it, it will be
- * rejected, clear appropriate status bit */
- uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET);
- if( ipisr & XTE_IPXR_RECV_REJECT_MASK ) {
- OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_REJECT_MASK);
- }
-
- /* Setup IPIF interrupt enables */
- uint32_t dier = XTE_DXR_CORE_MASK | XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK;
- dier |= XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK;
- OUT32(base + XTE_DIER_OFFSET, dier);
-
- /* Set the mac address */
- xilTemacSetMacAddress( ifp, xilTemac->iArpcom.ac_enaddr);
-
- /* Set the link speed */
- uint32_t emcfg = IN32(base + XTE_ECFG_OFFSET);
- printk("xiltemacStart, default linkspeed: %08" PRIx32 "\n", emcfg);
- emcfg = (emcfg & ~XTE_ECFG_LINKSPD_MASK) | XTE_ECFG_LINKSPD_100;
- OUT32(base + XTE_ECFG_OFFSET, emcfg);
-
- /* Set phy divisor and enable mdio. For a plb bus freq of 150MHz (the
- maximum as of Virtex4 Fx), a divisor of 29 gives a mdio clk freq of
- 2.5MHz (see Xilinx docs for equation), the maximum in the phy standard.
- For slower plb frequencies, slower mkdio clks will result. They may not
- be optimal, but they should work. */
- uint32_t divisor = 29;
- OUT32(base + XTE_EMC_OFFSET, divisor | XTE_EMC_MDIO_MASK);
-
-#if PPC_HAS_CLASSIC_EXCEPTIONS /* old connect code */
- /* Connect isr vector */
- rtems_status_code sc;
- extern rtems_isr xilTemacIsr( rtems_vector_number aVector );
- sc = opb_intc_set_vector( xilTemacIsr, xilTemac->iIsrVector, &xilTemac->iOldHandler );
- if( sc != RTEMS_SUCCESSFUL )
- {
- xilTemac->iOldHandler = 0;
- printk("%s: Could not set interrupt vector for interface '%s' opb_intc_set_vector ret: %d\n", DRIVER_PREFIX, xilTemac->iUnitName, sc );
- assert(0);
- }
-#else
- {
- rtems_irq_connect_data IrqConnData;
-
- /*
- *get old irq handler
- */
- xilTemac->iOldHandler.name = xilTemac->iIsrVector;
- if (!BSP_get_current_rtems_irq_handler (&xilTemac->iOldHandler)) {
- xilTemac->iOldHandler.name = 0;
- printk("%s: Unable to detect previous Irq handler\n",DRIVER_PREFIX);
- rtems_fatal_error_occurred(1);
- }
-
- IrqConnData.on = xilTemacIsrOn;
- IrqConnData.off = xilTemacIsrOff;
- IrqConnData.isOn = xilTemacIsrIsOn;
- IrqConnData.name = xilTemac->iIsrVector;
- IrqConnData.hdl = xilTemacIsr;
- IrqConnData.handle = xilTemac;
-
- if (!BSP_install_rtems_irq_handler (&IrqConnData)) {
- printk("%s: Unable to connect Irq handler\n",DRIVER_PREFIX);
- rtems_fatal_error_occurred(1);
- }
- }
-#endif
- /* Enable promiscuous mode -- The temac only supports full duplex, which
- means we're plugged into a switch. Thus promiscuous mode simply means
- we get all multicast addresses*/
- OUT32(base + XTE_EAFM_OFFSET, XTE_EAFM_EPPRM_MASK);
-
- /* Setup and enable receiver */
- rxc1 = XTE_ERXC1_RXFCS_MASK | XTE_ERXC1_RXEN_MASK | XTE_ERXC1_RXVLAN_MASK;
- OUT32(base + XTE_ERXC1_OFFSET, rxc1);
-
- /* Setup and enable transmitter */
- uint32_t txc = XTE_ETXC_TXEN_MASK | XTE_ETXC_TXVLAN_MASK;
- OUT32(base + XTE_ETXC_OFFSET, txc);
-
- /* Enable interrupts for temac */
- uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
- ipier |= (XTE_IPXR_XMIT_ERROR_MASK);
- ipier |= (XTE_IPXR_RECV_ERROR_MASK | XTE_IPXR_RECV_DONE_MASK);
- ipier |= (XTE_IPXR_AUTO_NEG_MASK);
- OUT32(base + XTE_IPIER_OFFSET, ipier);
-
- printk("%s: xiltemacStart, ipier: %08" PRIx32 "\n",DRIVER_PREFIX, ipier);
-
- /* Enable device global interrutps */
- OUT32(base + XTE_DGIE_OFFSET, XTE_DGIE_ENABLE_MASK);
- ifp->if_flags |= IFF_RUNNING;
- }
-}
-
-void xilTemacInit( void *voidptr )
-{
-}
-
-void xilTemacReset(struct ifnet *ifp)
-{
- xilTemacStop( ifp );
- xilTemacStart( ifp );
-}
-
-void xilTemacSetMacAddress(struct ifnet *ifp, unsigned char* aAddr)
-{
- struct XilTemac* xilTemac = ifp->if_softc;
- uint32_t base = xilTemac->iAddr;
-
- /* You can't change the mac address while the card is in operation */
- if( (ifp->if_flags & IFF_RUNNING) != 0 ) {
- printk("%s: attempted to change MAC while up, interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
- assert(0);
- }
- uint32_t mac;
- mac = aAddr[0] & 0x000000FF;
- mac |= aAddr[1] << 8;
- mac |= aAddr[2] << 16;
- mac |= aAddr[3] << 24;
- OUT32(base + XTE_EUAW0_OFFSET, mac);
-
- mac = IN32(base + XTE_EUAW1_OFFSET);
- mac &= ~XTE_EUAW1_MASK;
- mac |= aAddr[4] & 0x000000FF;
- mac |= aAddr[5] << 8;
- OUT32(base + XTE_EUAW1_OFFSET, mac);
-}
-
-void xilTemacPrintStats( struct ifnet *ifp )
-{
- struct XilTemac* xilTemac = ifp->if_softc;
-
- printf("\n");
- printf("%s: Statistics for interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
-
- printf("%s: Ipif Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iInterrupts);
- printf("%s: Rx Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxInterrupts);
- printf("%s: Rx Rejected Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedInterrupts);
- printf("%s: Rx Rej Invalid Frame: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedInvalidFrame);
- printf("%s: Rx Rej Data Fifo Full: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedDataFifoFull);
- printf("%s:Rx Rej Length Fifo Full: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxRejectedLengthFifoFull);
- printf("%s: Rx Stray Events: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxStrayEvents);
- printf("%s: Rx Max Drained: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iRxMaxDrained);
- printf("%s: Tx Interrupts: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iTxInterrupts);
- printf("%s: Tx Max Drained: %lu\n", DRIVER_PREFIX, xilTemac->iStats.iTxMaxDrained);
-
- printf("\n");
-}
-
-static void xilTemacIsrSingle(struct XilTemac* xilTemac)
-{
- uint32_t base = xilTemac->iAddr;
- uint32_t disr = IN32( base + XTE_DISR_OFFSET );
- struct ifnet* ifp = xilTemac->iIfp;
-
- if( disr && (ifp->if_flags & IFF_RUNNING) == 0 ) {
- /* some interrupt status bits are asserted but card is down */
- printk("%s: Fatal error, disr 0 or this emac not running\n", DRIVER_PREFIX);
- /*assert(0);*/
- } else {
- /* Handle all error conditions first */
- if( disr & (XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK |
- XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK) ) {
- printk("%s: Fatal Bus error, disr: %08" PRIx32 "\n", DRIVER_PREFIX, disr);
- /*assert(0);*/
- }
- if( disr & XTE_DXR_CORE_MASK ) {
- /* Normal case, temac interrupt */
- uint32_t ipisr = IN32(base + XTE_IPISR_OFFSET);
- uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
- uint32_t newipier = ipier;
- uint32_t pending = ipisr & ipier;
- xilTemac->iStats.iInterrupts++;
-
- /* Check for all fatal errors, even if that error is not enabled in ipier */
- if(ipisr & XTE_IPXR_FIFO_FATAL_ERROR_MASK) {
- printk("%s: Fatal Fifo Error ipisr: %08" PRIx32 "\n", DRIVER_PREFIX, ipisr);
- /*assert(0);*/
- }
-
- if(pending & XTE_IPXR_RECV_DONE_MASK) {
- /* We've received a packet
- - inc stats
- - disable rx interrupt
- - signal rx thread to empty out fifo
- (rx thread must renable interrupt)
- */
- xilTemac->iStats.iRxInterrupts++;
-
- newipier &= ~XTE_IPXR_RECV_DONE_MASK;
-
- rtems_bsdnet_event_send(gXilRxThread, xilTemac->iIoEvent);
- }
- if(pending & XTE_IPXR_XMIT_DONE_MASK) {
- /* We've transmitted a packet. This interrupt is only ever enabled in
- the ipier if the tx thread didn't have enough space in the data fifo
- or the tplr fifo. If that's the case, we:
- - inc stats
- - disable tx interrupt
- - signal tx thread that a transmit has completed and thus there is now
- room to send again.
- */
- xilTemac->iStats.iTxInterrupts++;
-
- newipier &= ~XTE_IPXR_XMIT_DONE_MASK;
-
- rtems_bsdnet_event_send(gXilTxThread, xilTemac->iIoEvent);
- }
- if(pending & XTE_IPXR_RECV_DROPPED_MASK) {
- /* A packet was dropped (because it was invalid, or receiving it
- have overflowed one of the rx fifo's).
- - Increment stats.
- - Clear interrupt condition.
- */
- uint32_t toggle = 0;
- if(pending & XTE_IPXR_RECV_REJECT_MASK) {
- xilTemac->iStats.iRxRejectedInvalidFrame++;
- toggle |= XTE_IPXR_RECV_REJECT_MASK;
- }
- if(pending & XTE_IPXR_RECV_PFIFO_ABORT_MASK) {
- xilTemac->iStats.iRxRejectedDataFifoFull++;
- toggle |= XTE_IPXR_RECV_PFIFO_ABORT_MASK;
- }
- if(pending & XTE_IPXR_RECV_LFIFO_ABORT_MASK) {
- xilTemac->iStats.iRxRejectedLengthFifoFull++;
- toggle |= XTE_IPXR_RECV_LFIFO_ABORT_MASK;
- }
- xilTemac->iStats.iRxRejectedInterrupts++;
- OUT32(base + XTE_IPISR_OFFSET, toggle);
- }
- if(pending & XTE_IPXR_AUTO_NEG_MASK) {
- printk("%s: Autonegotiation finished\n", DRIVER_PREFIX);
- OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_AUTO_NEG_MASK);
- }
- if(newipier != ipier) {
- OUT32(base + XTE_IPIER_OFFSET, newipier);
- }
- }
- }
-}
-
-#if PPC_HAS_CLASSIC_EXCEPTIONS
-rtems_isr xilTemacIsr( rtems_vector_number aVector )
-{
- struct XilTemac* xilTemac;
- int i;
-
- for( i=0; i< NUM_XILTEMAC_UNITS; i++ ) {
- xilTemac = &gXilTemac[i];
-
- if( xilTemac->iIsPresent ) {
- xilTemacIsrSingle(xilTemac);
- }
- }
-}
-#else
-rtems_isr xilTemacIsr(void *handle )
-{
- struct XilTemac* xilTemac = (struct XilTemac*)handle;
-
- xilTemacIsrSingle(xilTemac);
-}
-
-void xilTemacIsrOn(const rtems_irq_connect_data *unused)
-{
-}
-
-void xilTemacIsrOff(const rtems_irq_connect_data *unused)
-{
-}
-
-int xilTemacIsrIsOn(const rtems_irq_connect_data *unused)
-{
- return 1;
-}
-#endif
-
-
-static int32_t xilTemacSetMulticastFilter(struct ifnet *ifp)
-{
- return 0;
-}
-
-static int xilTemacIoctl(struct ifnet* ifp, ioctl_command_t aCommand, caddr_t aData)
-{
- struct XilTemac* xilTemac = ifp->if_softc;
- int32_t error = 0;
-
- switch(aCommand) {
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- ether_ioctl(ifp, aCommand, aData);
- break;
-
- case SIOCSIFFLAGS:
- switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
- {
- case IFF_RUNNING:
- xilTemacStop(ifp);
- break;
-
- case IFF_UP:
- xilTemacStart(ifp);
- break;
-
- case IFF_UP | IFF_RUNNING:
- xilTemacReset(ifp);
- break;
-
- default:
- break;
- }
- break;
-
- case SIOCADDMULTI:
- case SIOCDELMULTI: {
- struct ifreq* ifr = (struct ifreq*) aData;
- error = ((aCommand == SIOCADDMULTI) ?
- ( ether_addmulti(ifr, &(xilTemac->iArpcom)) ) :
- ( ether_delmulti(ifr, &(xilTemac->iArpcom)))
- );
- /* ENETRESET indicates that driver should update its multicast filters */
- if(error == ENETRESET)
- {
- error = xilTemacSetMulticastFilter( ifp );
- }
- break;
- }
-
- case SIO_RTEMS_SHOW_STATS:
- xilTemacPrintStats( ifp );
- break;
-
- default:
- error = EINVAL;
- break;
- }
- return error;
-}
-
-void xilTemacSend(struct ifnet* ifp)
-{
- struct XilTemac* xilTemac = ifp->if_softc;
-
- /* wake up tx thread w/ outbound interface's signal */
- rtems_bsdnet_event_send( gXilTxThread, xilTemac->iIoEvent );
-
- ifp->if_flags |= IFF_OACTIVE;
-}
-
-/* align the tx buffer to 32 bytes just for kicks, should make it more
- * cache friendly */
-static unsigned char gTxBuf[2048] __attribute__ ((aligned (32)));
-
-static void xilTemacSendPacket(struct ifnet *ifp, struct mbuf* aMbuf)
-{
- struct XilTemac *xilTemac = ifp->if_softc;
- struct mbuf *n = aMbuf;
- uint32_t len = 0;
-
-#ifdef DEBUG
- printk("SendPacket\n");
- printk("TXD: 0x%08x\n", (int32_t) n->m_data);
-#endif
-
- /* assemble the packet into the tx buffer */
- for(;;) {
-#ifdef DEBUG
- uint32_t i = 0;
- printk("MBUF: 0x%08x : ", (int32_t) n->m_data);
- for (i=0;i<n->m_len;i+=2) {
- printk("%02x%02x ", mtod(n, unsigned char*)[i], mtod(n, unsigned char*)[i+1]);
- }
- printk("\n");
-#endif
-
- if( n->m_len > 0 ) {
- memcpy( &gTxBuf[ len ], (char *)n->m_data, n->m_len);
- len += n->m_len;
- }
- if( (n = n->m_next) == 0) {
- break;
- }
- }
-
- xilTemacFifoWrite64( xilTemac->iAddr, (uint32_t*)gTxBuf, len );
- /* Set the Transmit Packet Length Register which registers the packet
- * length, enqueues the packet and signals the xmit unit to start
- * sending. */
- OUT32(xilTemac->iAddr + XTE_TPLR_OFFSET, len);
-
-#ifdef DEBUG
- printk("%s: txpkt, len %d\n", DRIVER_PREFIX, len );
- memset(gTxBuf, 0, len);
-#endif
-}
-
-static void xilTemacTxThreadSingle(struct ifnet* ifp)
-{
- struct XilTemac* xilTemac = ifp->if_softc;
- struct mbuf* m;
- uint32_t base = xilTemac->iAddr;
-
-#ifdef DEBUG
- printk("%s: tx send packet, interface '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
-#endif
-
- /* Send packets till mbuf queue empty or tx fifo full */
- for(;;) {
- uint32_t i = 0;
-
- /* 1) clear out any statuses from previously sent tx frames */
- while( IN32(base + XTE_IPISR_OFFSET) & XTE_IPXR_XMIT_DONE_MASK ) {
- IN32(base + XTE_TSR_OFFSET);
- OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_XMIT_DONE_MASK);
- i++;
- }
- if( i > xilTemac->iStats.iTxMaxDrained ) {
- xilTemac->iStats.iTxMaxDrained = i;
- }
-
- /* 2) Check if enough space in tx data fifo _and_ tx tplr for an entire
- ethernet frame */
- if( xilTemacTxFifoVacancyBytes( xilTemac->iAddr ) <= ifp->if_mtu ) {
- /* 2a) If not, enable transmit done interrupt and break out of loop to
- wait for space */
- uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
- ipier |= (XTE_IPXR_XMIT_DONE_MASK);
- OUT32(base + XTE_IPIER_OFFSET, ipier);
- break;
- }
-
- /* 3) Contuine to dequeue mbuf chains till none left */
- IF_DEQUEUE( &(ifp->if_snd), m);
- if( !m ) {
- break;
- }
-
- /* 4) Send dequeued mbuf chain */
- xilTemacSendPacket( ifp, m );
-
- /* 5) Free mbuf chain */
- m_freem( m );
- }
- ifp->if_flags &= ~IFF_OACTIVE;
-}
-
-void xilTemacTxThread( void *ignore )
-{
- struct XilTemac *xilTemac;
- struct ifnet *ifp;
-
- rtems_event_set events;
- int i;
-
- for(;;) {
- /* Wait for:
- - notification from stack of packet to send OR
- - notification from interrupt handler that there is space available to
- send already queued packets
- */
- rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
- RTEMS_EVENT_ANY | RTEMS_WAIT,
- RTEMS_NO_TIMEOUT,
- &events );
-
- for(i=0; i< NUM_XILTEMAC_UNITS; i++) {
- xilTemac = &gXilTemac[i];
-
- if( xilTemac->iIsPresent ) {
- ifp = xilTemac->iIfp;
-
- if( (ifp->if_flags & IFF_RUNNING) ) {
-
- if( events & xilTemac->iIoEvent ) {
- xilTemacTxThreadSingle(ifp);
- }
-
- } else {
- printk("%s: xilTemacTxThread: event received for device: %s, but device not active\n",
- DRIVER_PREFIX, xilTemac->iUnitName);
- assert(0);
- }
- }
- }
- }
-}
-
-static void xilTemacRxThreadSingle(struct ifnet* ifp)
-{
- struct XilTemac* xilTemac = ifp->if_softc;
-
- uint32_t npkts = 0;
-#ifdef DEBUG
- printk("%s: rxthread, packet rx on interface %s\n", DRIVER_PREFIX, xilTemac->iUnitName );
-#endif
-
- uint32_t base = xilTemac->iAddr;
-
- /* While RECV_DONE_MASK in ipisr stays set */
- while( IN32(base + XTE_IPISR_OFFSET) & XTE_IPXR_RECV_DONE_MASK ) {
-
- /* 1) Read the length of the packet */
- uint32_t bytes = IN32(base + XTE_RPLR_OFFSET);
-
- /* 2) Read the Read Status Register (which contains no information). When
- * all of these in the fifo have been read, then XTE_IPXR_RECV_DONE_MASK
- * will stay turned off, after it's written to */
- IN32(base + XTE_RSR_OFFSET);
- npkts++;
-
- struct mbuf* m;
- struct ether_header* eh;
-
- /* 3) Get some memory from the ip stack to store the packet in */
- MGETHDR(m, M_WAIT, MT_DATA);
- MCLGET(m, M_WAIT);
-
- m->m_pkthdr.rcvif = ifp;
-
- /* 4) Copy the packet into the ip stack's memory */
- xilTemacFifoRead64( base, mtod(m, uint32_t*), bytes);
-
- m->m_len = bytes - sizeof(struct ether_header);
- m->m_pkthdr.len = bytes - sizeof(struct ether_header);
-
- eh = mtod(m, struct ether_header*);
-
- m->m_data += sizeof(struct ether_header);
-
- /* 5) Tell the ip stack about the received packet */
- ether_input(ifp, eh, m);
-
- /* 6) Try and turn off XTE_IPXR_RECV_DONE bit in the ipisr. If there's
- * still more packets (ie RSR ! empty), then it will stay asserted. If
- * there's no more packets, this will turn it off.
- */
- OUT32(base + XTE_IPISR_OFFSET, XTE_IPXR_RECV_DONE_MASK);
- }
-
- /* End) All Rx packets serviced, renable rx interrupt */
- uint32_t ipier = IN32(base + XTE_IPIER_OFFSET);
- ipier |= XTE_IPXR_RECV_DONE_MASK;
- OUT32(base + XTE_IPIER_OFFSET, ipier);
-
-#ifdef DEBUG
- printk("%s: rxthread, retrieved %d packets\n", DRIVER_PREFIX, npkts );
-#endif
- if(npkts > xilTemac->iStats.iRxMaxDrained) {
- xilTemac->iStats.iRxMaxDrained = npkts;
- }
- /* ??) Very very occasionally, under extremely high stress, I get a situation
- * where we process no packets. That is, the rx thread was evented, but
- * there was no packet available. I'm not sure how this happens. Ideally,
- * it shouldn't ocurr, and I suspect a minor bug in the driver. However, for
- * me it's happenning 3 times in several hunderd million interrupts. Nothing
- * bad happens, as long as we don't read from the rx fifo's if nothing is
- * there. It is just not as efficient as possible (rx thread being evented
- * pointlessly) and a bit disconcerting about how it's ocurring.
- * The best way to reproduce this is to have two clients run:
- * $ ping <host> -f -s 65507
- * This flood pings the device from two clients with the maximum size ping
- * packet. It absolutely hammers the device under test. Eventually, (if
- * you leave it running overnight for instance), you'll get a couple of these
- * stray rx events. */
- if(npkts == 0) {
- /*printk("%s: RxThreadSingle: fatal error: event received, but no packets available\n", DRIVER_PREFIX);
- assert(0); */
- xilTemac->iStats.iRxStrayEvents++;
- }
-}
-
-void xilTemacRxThread( void *ignore )
-{
- struct XilTemac* xilTemac;
- struct ifnet* ifp;
- int i;
- rtems_event_set events;
-
-#ifdef DEBUG
- printk("%s: xilTemacRxThread running\n", DRIVER_PREFIX );
-#endif
-
- for(;;) {
- rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- RTEMS_NO_TIMEOUT,
- &events);
-
-#ifdef DEBUG
- printk("%s: rxthread, wakeup\n", DRIVER_PREFIX );
-#endif
-
- for(i=0; i< NUM_XILTEMAC_UNITS; i++) {
- xilTemac = &gXilTemac[i];
-
- if( xilTemac->iIsPresent ) {
- ifp = xilTemac->iIfp;
-
- if( (ifp->if_flags & IFF_RUNNING) != 0 ) {
- if( events & xilTemac->iIoEvent ) {
- xilTemacRxThreadSingle(ifp);
- }
- }
- else {
- printk("%s: rxthread, interface %s present but not running\n", DRIVER_PREFIX, xilTemac->iUnitName );
- assert(0);
- }
- }
- }
- }
-}
-
-int xilTemac_driver_attach(struct rtems_bsdnet_ifconfig* aBsdConfig, int aDummy)
-{
- struct ifnet* ifp;
- int32_t mtu;
- int32_t unit;
- char* unitName;
- struct XilTemac* xilTemac;
-
- unit = rtems_bsdnet_parse_driver_name(aBsdConfig, &unitName);
- if(unit < 0 )
- {
- printk("%s: Interface Unit number < 0\n", DRIVER_PREFIX );
- return 0;
- }
-
- if( aBsdConfig->bpar == 0 )
- {
- printk("%s: Did not specify base address for device '%s'", DRIVER_PREFIX, unitName );
- return 0;
- }
-
- if( aBsdConfig->hardware_address == NULL )
- {
- printk("%s: No MAC address given for interface '%s'\n", DRIVER_PREFIX, unitName );
- return 0;
- }
-
- xilTemac = &gXilTemac[ unit ];
- memset(xilTemac, 0, sizeof(struct XilTemac));
-
- xilTemac->iIsPresent = 1;
-
- snprintf( xilTemac->iUnitName, MAX_UNIT_BYTES, "%s%" PRId32, unitName, unit );
-
- xilTemac->iIfp = &(xilTemac->iArpcom.ac_if);
- ifp = &(xilTemac->iArpcom.ac_if);
- xilTemac->iAddr = aBsdConfig->bpar;
- xilTemac->iIoEvent = gUnitSignals[ unit ];
- xilTemac->iIsrVector = aBsdConfig->irno;
-
- memcpy( xilTemac->iArpcom.ac_enaddr, aBsdConfig->hardware_address, ETHER_ADDR_LEN);
-
- if( aBsdConfig->mtu )
- {
- mtu = aBsdConfig->mtu;
- }
- else
- {
- mtu = ETHERMTU;
- }
-
- ifp->if_softc = xilTemac;
- ifp->if_unit = unit;
- ifp->if_name = unitName;
- ifp->if_mtu = mtu;
- ifp->if_init = xilTemacInit;
- ifp->if_ioctl = xilTemacIoctl;
- ifp->if_start = xilTemacSend;
- ifp->if_output = ether_output;
-
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-
- if(ifp->if_snd.ifq_maxlen == 0)
- {
- ifp->if_snd.ifq_maxlen = ifqmaxlen;
- }
-
- if_attach(ifp);
- ether_ifattach(ifp);
-
- /* create shared rx & tx threads */
- if( (gXilRxThread == 0) && (gXilTxThread == 0) )
- {
- printk("%s: Creating shared RX/TX threads\n", DRIVER_PREFIX );
- gXilRxThread = rtems_bsdnet_newproc("xerx", 4096, xilTemacRxThread, NULL );
- gXilTxThread = rtems_bsdnet_newproc("xetx", 4096, xilTemacTxThread, NULL );
- }
-
- printk("%s: Initializing driver for '%s'\n", DRIVER_PREFIX, xilTemac->iUnitName );
-
- printk("%s: base address 0x%08X, intnum 0x%02X, \n",
- DRIVER_PREFIX,
- aBsdConfig->bpar,
- aBsdConfig->irno );
-
- return 1;
-}
-