summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/virtex/network
diff options
context:
space:
mode:
authorThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2007-07-04 12:37:36 +0000
committerThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2007-07-04 12:37:36 +0000
commit862c231785024acbd6c830fb30e0a6a64e6c3318 (patch)
treefc09530e45e5436192c6286e70b912fbff8bcf16 /c/src/lib/libbsp/powerpc/virtex/network
parentmerged individual exception handler code to a common one. (diff)
downloadrtems-862c231785024acbd6c830fb30e0a6a64e6c3318.tar.bz2
added virtex BSP support and some missing files for common PPC
exception handling
Diffstat (limited to '')
-rw-r--r--c/src/lib/libbsp/powerpc/virtex/network/xiltemac.c966
-rw-r--r--c/src/lib/libbsp/powerpc/virtex/network/xiltemac.h375
2 files changed, 1341 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/virtex/network/xiltemac.c b/c/src/lib/libbsp/powerpc/virtex/network/xiltemac.c
new file mode 100644
index 0000000000..a4316148c2
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/virtex/network/xiltemac.c
@@ -0,0 +1,966 @@
+/*
+ * 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.com/license/LICENSE.
+ *
+ */
+#define PPC_HAS_CLASSIC_EXCEPTIONS FALSE
+
+#ifndef __INSIDE_RTEMS_BSD_TCPIP_STACK__
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+#endif
+
+#ifndef __BSD_VISIBLE
+#define __BSD_VISIBLE
+#endif
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.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
+
+extern void printk(char*, ...);
+
+/* Why isn't this defined in stdio.h like it's supposed to be? */
+extern int snprintf(char*, size_t, const char*, ...);
+
+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 };
+
+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;
+}
+
+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];
+ }
+ }
+}
+
+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: %08x\n", emcfg);
+ emcfg |= 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
+ {
+ 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 *);
+ 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: %08x\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");
+}
+
+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: %08x\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: %08x\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_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_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
+
+
+int32_t xilTemacSetMulticastFilter(struct ifnet *ifp)
+{
+ return 0;
+}
+
+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_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)));
+
+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
+}
+
+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);
+ }
+ }
+ }
+ }
+}
+
+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);
+ }
+ }
+ }
+ }
+}
+
+int32_t 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%d", 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;
+}
+
diff --git a/c/src/lib/libbsp/powerpc/virtex/network/xiltemac.h b/c/src/lib/libbsp/powerpc/virtex/network/xiltemac.h
new file mode 100644
index 0000000000..6a0c821b01
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/virtex/network/xiltemac.h
@@ -0,0 +1,375 @@
+/*
+ * Driver for plb inteface of the xilinx temac 3.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.com/license/LICENSE.
+ *
+ */
+
+#ifndef _XILINX_TEMAC_
+#define _XILINX_TEMAC_
+#include <rtems/irq.h>
+
+
+#define XILTEMAC_DRIVER_PREFIX "xiltemac"
+
+#define DRIVER_PREFIX XILTEMAC_DRIVER_PREFIX
+
+
+/** IPIF interrupt and reset registers
+ */
+#define XTE_DISR_OFFSET 0x00000000 /**< Device interrupt status */
+#define XTE_DIPR_OFFSET 0x00000004 /**< Device interrupt pending */
+#define XTE_DIER_OFFSET 0x00000008 /**< Device interrupt enable */
+#define XTE_DIIR_OFFSET 0x00000018 /**< Device interrupt ID */
+#define XTE_DGIE_OFFSET 0x0000001C /**< Device global interrupt enable */
+#define XTE_IPISR_OFFSET 0x00000020 /**< IP interrupt status */
+#define XTE_IPIER_OFFSET 0x00000028 /**< IP interrupt enable */
+#define XTE_DSR_OFFSET 0x00000040 /**< Device software reset (write) */
+
+/** IPIF transmit fifo
+ */
+#define XTE_PFIFO_TX_BASE_OFFSET 0x00002000 /**< Packet FIFO Tx channel */
+#define XTE_PFIFO_TX_VACANCY_OFFSET 0x00002004 /**< Packet Fifo Tx Vacancy */
+#define XTE_PFIFO_TX_DATA_OFFSET 0x00002100 /**< IPIF Tx packet fifo port */
+
+/** IPIF receive fifo
+ */
+#define XTE_PFIFO_RX_BASE_OFFSET 0x00002010 /**< Packet FIFO Rx channel */
+#define XTE_PFIFO_RX_VACANCY_OFFSET 0x00002014 /**< Packet Fifo Rx Vacancy */
+#define XTE_PFIFO_RX_DATA_OFFSET 0x00002200 /**< IPIF Rx packet fifo port */
+
+/** IPIF fifo masks
+ */
+#define XTE_PFIFO_COUNT_MASK 0x00FFFFFF
+
+/** IPIF transmit and recieve DMA offsets
+ */
+#define XTE_DMA_SEND_OFFSET 0x00002300 /**< DMA Tx channel */
+#define XTE_DMA_RECV_OFFSET 0x00002340 /**< DMA Rx channel */
+
+/** IPIF IPIC_TO_TEMAC Core Registers
+ */
+#define XTE_CR_OFFSET 0x00001000 /**< Control */
+#define XTE_TPLR_OFFSET 0x00001004 /**< Tx packet length (FIFO) */
+#define XTE_TSR_OFFSET 0x00001008 /**< Tx status (FIFO) */
+#define XTE_RPLR_OFFSET 0x0000100C /**< Rx packet length (FIFO) */
+#define XTE_RSR_OFFSET 0x00001010 /**< Receive status */
+#define XTE_IFGP_OFFSET 0x00001014 /**< Interframe gap */
+#define XTE_TPPR_OFFSET 0x00001018 /**< Tx pause packet */
+
+/** TEMAC Core Registers
+ * These are registers defined within the device's hard core located in the
+ * processor block. They are accessed with the host interface. These registers
+ * are addressed offset by XTE_HOST_IPIF_OFFSET or by the DCR base address
+ * if so configured.
+ */
+#define XTE_HOST_IPIF_OFFSET 0x00003000 /**< Offset of host registers when
+ memory mapped into IPIF */
+#define XTE_ERXC0_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000200) /**< Rx configuration word 0 */
+#define XTE_ERXC1_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000240) /**< Rx configuration word 1 */
+#define XTE_ETXC_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000280) /**< Tx configuration */
+#define XTE_EFCC_OFFSET (XTE_HOST_IPIF_OFFSET + 0x000002C0) /**< Flow control configuration */
+#define XTE_ECFG_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000300) /**< EMAC configuration */
+#define XTE_EGMIC_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000320) /**< RGMII/SGMII configuration */
+#define XTE_EMC_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000340) /**< Management configuration */
+#define XTE_EUAW0_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000380) /**< Unicast address word 0 */
+#define XTE_EUAW1_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000384) /**< Unicast address word 1 */
+#define XTE_EMAW0_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000388) /**< Multicast address word 0 */
+#define XTE_EMAW1_OFFSET (XTE_HOST_IPIF_OFFSET + 0x0000038C) /**< Multicast address word 1 */
+#define XTE_EAFM_OFFSET (XTE_HOST_IPIF_OFFSET + 0x00000390) /**< Promisciuous mode */
+#define XTE_EIRS_OFFSET (XTE_HOST_IPIF_OFFSET + 0x000003A0) /**< IRstatus */
+#define XTE_EIREN_OFFSET (XTE_HOST_IPIF_OFFSET + 0x000003A4) /**< IRenable */
+#define XTE_EMIID_OFFSET (XTE_HOST_IPIF_OFFSET + 0x000003B0) /**< MIIMwrData */
+#define XTE_EMIIC_OFFSET (XTE_HOST_IPIF_OFFSET + 0x000003B4) /**< MiiMcnt */
+
+/* Register masks. The following constants define bit locations of various
+ * control bits in the registers. Constants are not defined for those registers
+ * that have a single bit field representing all 32 bits. For further
+ * information on the meaning of the various bit masks, refer to the HW spec.
+ */
+
+/** Interrupt status bits for top level interrupts
+ * These bits are associated with the XTE_DISR_OFFSET, XTE_DIPR_OFFSET,
+ * and XTE_DIER_OFFSET registers.
+ */
+#define XTE_DXR_SEND_FIFO_MASK 0x00000040 /**< Send FIFO channel */
+#define XTE_DXR_RECV_FIFO_MASK 0x00000020 /**< Receive FIFO channel */
+#define XTE_DXR_RECV_DMA_MASK 0x00000010 /**< Receive DMA channel */
+#define XTE_DXR_SEND_DMA_MASK 0x00000008 /**< Send DMA channel */
+#define XTE_DXR_CORE_MASK 0x00000004 /**< Core */
+#define XTE_DXR_DPTO_MASK 0x00000002 /**< Data phase timeout */
+#define XTE_DXR_TERR_MASK 0x00000001 /**< Transaction error */
+
+/** Interrupt status bits for MAC interrupts
+ * These bits are associated with XTE_IPISR_OFFSET and XTE_IPIER_OFFSET
+ * registers.
+ */
+#define XTE_IPXR_XMIT_DONE_MASK 0x00000001 /**< Tx complete */
+#define XTE_IPXR_RECV_DONE_MASK 0x00000002 /**< Rx complete */
+#define XTE_IPXR_AUTO_NEG_MASK 0x00000004 /**< Auto negotiation complete */
+#define XTE_IPXR_RECV_REJECT_MASK 0x00000008 /**< Rx packet rejected */
+#define XTE_IPXR_XMIT_SFIFO_EMPTY_MASK 0x00000010 /**< Tx status fifo empty */
+#define XTE_IPXR_RECV_LFIFO_EMPTY_MASK 0x00000020 /**< Rx length fifo empty */
+#define XTE_IPXR_XMIT_LFIFO_FULL_MASK 0x00000040 /**< Tx length fifo full */
+#define XTE_IPXR_RECV_LFIFO_OVER_MASK 0x00000080 /**< Rx length fifo overrun
+ Note that this signal is
+ no longer asserted by HW
+ */
+#define XTE_IPXR_RECV_LFIFO_UNDER_MASK 0x00000100 /**< Rx length fifo underrun */
+#define XTE_IPXR_XMIT_SFIFO_OVER_MASK 0x00000200 /**< Tx status fifo overrun */
+#define XTE_IPXR_XMIT_SFIFO_UNDER_MASK 0x00000400 /**< Tx status fifo underrun */
+#define XTE_IPXR_XMIT_LFIFO_OVER_MASK 0x00000800 /**< Tx length fifo overrun */
+#define XTE_IPXR_XMIT_LFIFO_UNDER_MASK 0x00001000 /**< Tx length fifo underrun */
+#define XTE_IPXR_RECV_PFIFO_ABORT_MASK 0x00002000 /**< Rx packet rejected due to
+ full packet FIFO */
+#define XTE_IPXR_RECV_LFIFO_ABORT_MASK 0x00004000 /**< Rx packet rejected due to
+ full length FIFO */
+
+#define XTE_IPXR_RECV_DROPPED_MASK \
+ (XTE_IPXR_RECV_REJECT_MASK | \
+ XTE_IPXR_RECV_PFIFO_ABORT_MASK | \
+ XTE_IPXR_RECV_LFIFO_ABORT_MASK) /**< IPXR bits that indicate a dropped
+ receive frame */
+#define XTE_IPXR_XMIT_ERROR_MASK \
+ (XTE_IPXR_XMIT_SFIFO_OVER_MASK | \
+ XTE_IPXR_XMIT_SFIFO_UNDER_MASK | \
+ XTE_IPXR_XMIT_LFIFO_OVER_MASK | \
+ XTE_IPXR_XMIT_LFIFO_UNDER_MASK) /**< IPXR bits that indicate transmit
+ errors */
+
+#define XTE_IPXR_RECV_ERROR_MASK \
+ (XTE_IPXR_RECV_DROPPED_MASK | \
+ XTE_IPXR_RECV_LFIFO_UNDER_MASK) /**< IPXR bits that indicate receive
+ errors */
+
+#define XTE_IPXR_FIFO_FATAL_ERROR_MASK \
+ (XTE_IPXR_XMIT_SFIFO_OVER_MASK | \
+ XTE_IPXR_XMIT_SFIFO_UNDER_MASK | \
+ XTE_IPXR_XMIT_LFIFO_OVER_MASK | \
+ XTE_IPXR_XMIT_LFIFO_UNDER_MASK | \
+ XTE_IPXR_RECV_LFIFO_UNDER_MASK) /**< IPXR bits that indicate errors with
+ one of the length or status FIFOs
+ that is fatal in nature. These bits
+ can only be cleared by a device
+ reset */
+
+/** Software reset register (DSR)
+ */
+#define XTE_DSR_RESET_MASK 0x0000000A /**< Write this value to DSR to
+ reset entire core */
+
+
+/** Global interrupt enable register (DGIE)
+ */
+#define XTE_DGIE_ENABLE_MASK 0x80000000 /**< Write this value to DGIE to
+ enable interrupts from this
+ device */
+
+/** Control Register (CR)
+ */
+#define XTE_CR_HTRST_MASK 0x00000008 /**< Reset hard temac */
+#define XTE_CR_BCREJ_MASK 0x00000004 /**< Disable broadcast address
+ filtering */
+#define XTE_CR_MCREJ_MASK 0x00000002 /**< Disable multicast address
+ filtering */
+#define XTE_CR_HDUPLEX_MASK 0x00000001 /**< Enable half duplex operation */
+
+
+/** Transmit Packet Length Register (TPLR)
+ */
+#define XTE_TPLR_TXPL_MASK 0x00003FFF /**< Tx packet length in bytes */
+
+
+/** Transmit Status Register (TSR)
+ */
+#define XTE_TSR_TXED_MASK 0x80000000 /**< Excess deferral error */
+#define XTE_TSR_PFIFOU_MASK 0x40000000 /**< Packet FIFO underrun */
+#define XTE_TSR_TXA_MASK 0x3E000000 /**< Transmission attempts */
+#define XTE_TSR_TXLC_MASK 0x01000000 /**< Late collision error */
+#define XTE_TSR_TPCF_MASK 0x00000001 /**< Transmit packet complete
+ flag */
+
+#define XTE_TSR_ERROR_MASK \
+ (XTE_TSR_TXED_MASK | \
+ XTE_TSR_PFIFOU_MASK | \
+ XTE_TSR_TXLC_MASK) /**< TSR bits that indicate an
+ error */
+
+
+/** Receive Packet Length Register (RPLR)
+ */
+#define XTE_RPLR_RXPL_MASK 0x00003FFF /**< Rx packet length in bytes */
+
+
+/** Receive Status Register (RSR)
+ */
+#define XTE_RSR_RPCF_MASK 0x00000001 /**< Receive packet complete
+ flag */
+
+/** Interframe Gap Register (IFG)
+ */
+#define XTE_IFG_IFGD_MASK 0x000000FF /**< IFG delay */
+
+
+/** Transmit Pause Packet Register (TPPR)
+ */
+#define XTE_TPPR_TPPD_MASK 0x0000FFFF /**< Tx pause packet data */
+
+
+/** Receiver Configuration Word 1 (ERXC1)
+ */
+#define XTE_ERXC1_RXRST_MASK 0x80000000 /**< Receiver reset */
+#define XTE_ERXC1_RXJMBO_MASK 0x40000000 /**< Jumbo frame enable */
+#define XTE_ERXC1_RXFCS_MASK 0x20000000 /**< FCS not stripped */
+#define XTE_ERXC1_RXEN_MASK 0x10000000 /**< Receiver enable */
+#define XTE_ERXC1_RXVLAN_MASK 0x08000000 /**< VLAN enable */
+#define XTE_ERXC1_RXHD_MASK 0x04000000 /**< Half duplex */
+#define XTE_ERXC1_RXLT_MASK 0x02000000 /**< Length/type check disable */
+#define XTE_ERXC1_ERXC1_MASK 0x0000FFFF /**< Pause frame source address
+ bits [47:32]. Bits [31:0]
+ are stored in register
+ ERXC0 */
+
+
+/** Transmitter Configuration (ETXC)
+ */
+#define XTE_ETXC_TXRST_MASK 0x80000000 /**< Transmitter reset */
+#define XTE_ETXC_TXJMBO_MASK 0x40000000 /**< Jumbo frame enable */
+#define XTE_ETXC_TXFCS_MASK 0x20000000 /**< Generate FCS */
+#define XTE_ETXC_TXEN_MASK 0x10000000 /**< Transmitter enable */
+#define XTE_ETXC_TXVLAN_MASK 0x08000000 /**< VLAN enable */
+#define XTE_ETXC_TXHD_MASK 0x04000000 /**< Half duplex */
+#define XTE_ETXC_TXIFG_MASK 0x02000000 /**< IFG adjust enable */
+
+
+/** Flow Control Configuration (EFCC)
+ */
+#define XTE_EFCC_TXFLO_MASK 0x40000000 /**< Tx flow control enable */
+#define XTE_EFCC_RXFLO_MASK 0x20000000 /**< Rx flow control enable */
+
+
+/** EMAC Configuration (ECFG)
+ */
+#define XTE_ECFG_LINKSPD_MASK 0xC0000000 /**< Link speed */
+#define XTE_ECFG_RGMII_MASK 0x20000000 /**< RGMII mode enable */
+#define XTE_ECFG_SGMII_MASK 0x10000000 /**< SGMII mode enable */
+#define XTE_ECFG_1000BASEX_MASK 0x08000000 /**< 1000BaseX mode enable */
+#define XTE_ECFG_HOSTEN_MASK 0x04000000 /**< Host interface enable */
+#define XTE_ECFG_TX16BIT 0x02000000 /**< 16 bit Tx client enable */
+#define XTE_ECFG_RX16BIT 0x01000000 /**< 16 bit Rx client enable */
+
+#define XTE_ECFG_LINKSPD_10 0x00000000 /**< XTE_ECFG_LINKSPD_MASK for
+ 10 Mbit */
+#define XTE_ECFG_LINKSPD_100 0x40000000 /**< XTE_ECFG_LINKSPD_MASK for
+ 100 Mbit */
+#define XTE_ECFG_LINKSPD_1000 0x80000000 /**< XTE_ECFG_LINKSPD_MASK for
+ 1000 Mbit */
+
+/** EMAC RGMII/SGMII Configuration (EGMIC)
+ */
+#define XTE_EGMIC_RGLINKSPD_MASK 0xC0000000 /**< RGMII link speed */
+#define XTE_EGMIC_SGLINKSPD_MASK 0x0000000C /**< SGMII link speed */
+#define XTE_EGMIC_RGSTATUS_MASK 0x00000002 /**< RGMII link status */
+#define XTE_EGMIC_RGHALFDUPLEX_MASK 0x00000001 /**< RGMII half duplex */
+
+#define XTE_EGMIC_RGLINKSPD_10 0x00000000 /**< XTE_EGMIC_RGLINKSPD_MASK
+ for 10 Mbit */
+#define XTE_EGMIC_RGLINKSPD_100 0x40000000 /**< XTE_EGMIC_RGLINKSPD_MASK
+ for 100 Mbit */
+#define XTE_EGMIC_RGLINKSPD_1000 0x80000000 /**< XTE_EGMIC_RGLINKSPD_MASK
+ for 1000 Mbit */
+#define XTE_EGMIC_SGLINKSPD_10 0x00000000 /**< XTE_SGMIC_RGLINKSPD_MASK
+ for 10 Mbit */
+#define XTE_EGMIC_SGLINKSPD_100 0x00000004 /**< XTE_SGMIC_RGLINKSPD_MASK
+ for 100 Mbit */
+#define XTE_EGMIC_SGLINKSPD_1000 0x00000008 /**< XTE_SGMIC_RGLINKSPD_MASK
+ for 1000 Mbit */
+
+/** EMAC Management Configuration (EMC)
+ */
+#define XTE_EMC_MDIO_MASK 0x00000040 /**< MII management enable */
+#define XTE_EMC_CLK_DVD_MAX 0x3F /**< Maximum MDIO divisor */
+
+
+/** EMAC Unicast Address Register Word 1 (EUAW1)
+ */
+#define XTE_EUAW1_MASK 0x0000FFFF /**< Station address bits [47:32]
+ Station address bits [31:0]
+ are stored in register
+ EUAW0 */
+
+
+/** EMAC Multicast Address Register Word 1 (EMAW1)
+ */
+#define XTE_EMAW1_CAMRNW_MASK 0x00800000 /**< CAM read/write control */
+#define XTE_EMAW1_CAMADDR_MASK 0x00030000 /**< CAM address mask */
+#define XTE_EUAW1_MASK 0x0000FFFF /**< Multicast address bits [47:32]
+ Multicast address bits [31:0]
+ are stored in register
+ EMAW0 */
+#define XTE_EMAW1_CAMMADDR_SHIFT_MASK 16 /**< Number of bits to shift right
+ to align with
+ XTE_EMAW1_CAMADDR_MASK */
+
+
+/** EMAC Address Filter Mode (EAFM)
+ */
+#define XTE_EAFM_EPPRM_MASK 0x80000000 /**< Promiscuous mode enable */
+
+
+/** EMAC MII Management Write Data (EMIID)
+ */
+#define XTE_EMIID_MIIMWRDATA_MASK 0x0000FFFF /**< Data port */
+
+
+/** EMAC MII Management Control (EMIIC)
+ */
+#define XTE_EMIID_MIIMDECADDR_MASK 0x0000FFFF /**< Address port */
+
+
+struct XilTemacStats
+{
+ volatile uint32_t iInterrupts;
+
+ volatile uint32_t iRxInterrupts;
+ volatile uint32_t iRxRejectedInterrupts;
+ volatile uint32_t iRxRejectedInvalidFrame;
+ volatile uint32_t iRxRejectedDataFifoFull;
+ volatile uint32_t iRxRejectedLengthFifoFull;
+ volatile uint32_t iRxMaxDrained;
+ volatile uint32_t iRxStrayEvents;
+
+ volatile uint32_t iTxInterrupts;
+ volatile uint32_t iTxMaxDrained;
+};
+
+#define MAX_UNIT_BYTES 50
+
+struct XilTemac
+{
+ struct arpcom iArpcom;
+ struct XilTemacStats iStats;
+ struct ifnet* iIfp;
+
+ char iUnitName[MAX_UNIT_BYTES];
+
+ uint32_t iAddr;
+ rtems_event_set iIoEvent;
+
+ int iIsrVector;
+
+#if PPC_HAS_CLASSIC_EXCEPTIONS
+ rtems_isr_entry iOldHandler;
+#else
+ rtems_irq_connect_data iOldHandler;
+#endif
+ int iIsPresent;
+};
+
+
+#endif /* _XILINX_EMAC_*/