diff options
Diffstat (limited to 'bsps/powerpc/virtex')
-rw-r--r-- | bsps/powerpc/virtex/net/xiltemac.c | 961 |
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; -} - |